python中getattr/setattr/hasattr/delattr函数都是干什么的?

目录

1、getattr:动态获取属性 🔍

1.1 动态获取属性

1.2 默认值处理技巧

1.3 实战案例:配置文件动态加载

2、setattr:动态设置属性 🛠

2.1 修改对象属性

2.2 新增属性场景

2.3 应用场景:类的动态配置更新

3、hasattr:检查属性存在与否 🔎

3.1 安全性检查

3.2 条件逻辑简化

4、delattr:删除对象属性 🗑

4.1 属性清理实例

4.2 特殊应用场景:资源清理与状态重置

4.3 警惕:删除属性的副作用

5、综合案例:构建动态属性处理器 🌀

5.1 设计思路解析

功能目标:

设计步骤:

5.2 代码实现与优化

6、深入Python数据模型 📖

6.1 揭秘__getattribute__

6.2 自定义属性访问控制

7、性能考量与最佳实践 ⏱️

7.1 动态属性操作的性能影响

7.2 优化策略:减少动态属性依赖

7.3 实战建议:平衡灵活性与效率

8、总结与展望 🚀



1、getattr:动态获取属性 🔍

1.1 动态获取属性

在Python中,getattr函数是探索和操作对象属性的强大工具。当需要从一个对象中获取属性时,通常我们会直接使用点操作符(.)。然而,在不知道属性名或者属性名由动态变量决定的情况下,getattr就显得尤为实用了。

示例代码:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('张三', 30)
attr_name = 'name'

print(getattr(p, attr_name))

输出:

张三

在这个例子中,我们创建了一个Person类并实例化了一个Person对象p。通过使用getattr,我们可以根据字符串'name'动态地获取p对象的name属性。

1.2 默认值处理技巧

getattr函数还允许我们指定一个默认值 ,当尝试获取的属性不存在时,这个默认值将被返回。这可以防止程序因为属性不存在而抛出异常,使得代码更加健壮和灵活。

示例代码:

print(getattr(p, 'gender', '未指定'))

输出:

未指定

这里 ,p对象并没有gender属性 ,但是由于我们在getattr调用中指定了默认值'未指定' ,所以程序不会中断,而是返回了这个默认值。

通过getattr函数,开发者能够在不知道具体属性名的情况下灵活地操作对象,同时还能通过设置默认值来增强代码的健壮性。这是Python动态性的一个重要体现,也是面向对象编程中非常实用的功能。

1.3 实战案例:配置文件动态加载

在现实项目中 ,动态加载配置文件中的属性是一种常见的需求。我们可以利用 getattr 来实现这一功能。

假设我们有一个配置类 Config ,其中包含各种配置项,如数据库连接字符串等。下面是如何使用 getattr 来读取这些配置项的示例:

示例代码:

class Config:
    DATABASE_URL = 'postgresql://user:password@localhost:5432/mydatabase'
    API_KEY = 'secret_key_here'

def get_config_value(key, default=None):
    return getattr(Config, key, default)

db_url = get_config_value('DATABASE_URL')
api_key = get_config_value('API_KEY')
secret_token = get_config_value('SECRET_TOKEN', 'default_secret')

print(db_url)
print(api_key)
print(secret_token)

输出:

postgresql://user:password@localhost:5432/mydatabase
secret_key_here
default_secret

这个例子展示了如何使用 getattr 来从 Config 类中动态地获取配置项 ,同时提供了一个默认值以应对配置项可能未定义的情况。这种方法使得我们的代码更加灵活,能够轻松适应不同环境下的配置差异。

2、setattr:动态设置属性 🛠

2.1 修改对象属性

setattr是Python中的一个内置函数,它允许你动态地修改或设置对象的属性值。这在需要根据运行时条件改变对象状态的场景下非常有用。

示例代码:

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year

my_car = Car('Toyota', 'Corolla', 2015)

# 修改对象属性
setattr(my_car, 'year', 2020)

print(my_car.year)

输出:

2020

在这个例子中,我们首先定义了一个Car类 ,并创建了一个Car对象my_car。然后,使用setattr函数将my_caryear属性从2015年修改到了2020年 ,展示了动态修改对象属性的能力。

2.2 新增属性场景

除了修改已存在的属性,setattr还可以用来为对象添加全新的属性,这对于设计灵活的数据结构或动态扩展对象功能特别有帮助。

示例代码:

# 继续使用之前的my_car对象
setattr(my_car, 'color', 'Blue')

print(my_car.color)

输出:

Blue

这里 ,我们为my_car对象新增了一个名为color的属性,并赋值为Blue。尽管Car类的初始化中并未包含color属性 ,但通过setattr,我们仍然能够成功地为其添加这一属性。

2.3 应用场景:类的动态配置更新

在复杂的系统中,类的配置可能需要根据外部条件变化而动态调整。setattr 在此类场景下显得尤为有用。比如,在一个应用程序初始化时,可根据配置文件更新类的属性:

示例代码:

class AppConfig:
    debug_mode = False

def update_config_from_file(filename):
    with open(filename, 'r') as file:
        for line in file:
            key, value = line.strip().split('=')
            if hasattr(AppConfig, key):
                setattr(AppConfig, key, eval(value))

update_config_from_file('config.txt')
print(AppConfig.debug_mode)

假设 config.txt 包含 debug_mode=True,此例展示了如何读取配置文件并使用 setattr 更新 AppConfig 的属性值。请注意 ,在实际应用中直接使用 eval 函数可能存在安全风险,应谨慎使用或替换为更安全的解析方式。

3、hasattr:检查属性存在与否 🔎

3.1 安全性检查

hasattr函数在Python中扮演着安全卫士的角色,它用于检查一个对象是否具有特定的属性。这对于编写健壮且可靠的代码至关重要,尤其是在处理可能由外部输入动态变化的对象时。

示例代码:

class Vehicle:
    def __init__(self, name, wheels=None):
        self.name = name
        self.wheels = wheels

car = Vehicle('Toyota Corolla', 4)
plane = Vehicle('Boeing 747')

# 使用hasattr检查属性是否存在
if hasattr(car, 'wheels'):
    print(f"{car.name} has {car.wheels} wheels.")
else:
    print(f"{car.name} does not have wheels.")

if hasattr(plane, 'wheels'):
    print(f"{plane.name} has wheels.")
else:
    print(f"{plane.name} does not have wheels.")

输出:

Toyota Corolla has 4 wheels.
Boeing 747 does not have wheels.

在这个例子中 ,我们定义了一个Vehicle类 ,其中car对象有wheels属性 ,而plane对象没有。通过hasattr函数,我们能够安全地检查和处理这两个对象的不同属性 ,从而避免了潜在的AttributeError

3.2 条件逻辑简化

hasattr不仅提高了代码的安全性 ,还能简化条件逻辑,使得代码更加清晰和易于维护。当需要根据对象是否具有某属性执行不同的逻辑分支时 ,hasattr是一个理想的选择。

示例代码:

def display_vehicle_info(vehicle):
    if hasattr(vehicle, 'wheels'):
        print(f"The vehicle has {vehicle.wheels} wheels.")
    else:
        print("The vehicle does not have wheels information.")

display_vehicle_info(car)
display_vehicle_info(plane)

输出:

The vehicle has 4 wheels.
The vehicle does not have wheels information.

这段代码定义了一个display_vehicle_info函数,它接受一个Vehicle类型的对象作为参数。通过使用hasattr ,函数能够根据不同车辆类型的存在或缺失wheels属性,输出恰当的信息。这样,即使面对不同类型或配置的车辆 ,该函数也能灵活适应,提供正确的输出。

hasattr函数的运用不仅加强了代码的安全防护,还简化了条件判断逻辑,提升了代码的可读性和维护性。掌握这一函数,对于构建高效、健壮的Python应用程序来说,无疑是锦上添花。

4、delattr:删除对象属性 🗑

4.1 属性清理实例

在Python中,delattr函数提供了删除对象属性的能力,这对于资源管理和内存优化尤其关键。当不再需要某个属性时 ,适时清理可以避免不必要的内存占用。

示例代码:

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

user = User('Alice', 'SecurePwd123')

# 显示对象初始属性
print(user.__dict__)

# 删除敏感属性
delattr(user, 'password')

# 再次显示对象属性,验证password已被删除
print(user.__dict__)

输出:

{'username': 'Alice', 'password': 'SecurePwd123'}
{'username': 'Alice'}

此例中,我们定义了一个User类 ,实例化后利用delattr函数移除了敏感的password属性 ,确保了数据的安全性,并释放了相关内存空间。

4.2 特殊应用场景:资源清理与状态重置

在一些特殊的应用场景下,delattr 可以用来实现资源的清理工作或对象状态的完全重置。例如,在设计一个管理数据库连接的对象时,可以利用 delattr 来断开连接,以确保资源的及时释放。

示例代码:

class DatabaseConnection:
    def __init__(self, connection_string):
        self.connection = connect_to_database(connection_string)

    def disconnect(self):
        if hasattr(self, 'connection'):
            delattr(self, 'connection')
            print("Database connection closed.")

conn = DatabaseConnection("my_db_connection_string")
conn.disconnect()

这里 ,disconnect 方法使用 hasattr 检查 connection 属性是否存在,存在则使用 delattr 删除之,模拟了数据库连接的关闭过程。

4.3 警惕:删除属性的副作用

虽然 delattr 提供了强大的动态属性管理能力,但使用时也需格外小心。删除一个对象的关键属性可能会导致对象处于不一致状态 ,影响后续的正常操作。特别是对于那些依赖于特定属性存在的方法,删除这些属性可能会引发意外的错误。

另外,尝试删除一个不可删除的属性(如某些内置类型或第三方库中的属性)会导致 AttributeError。此外,对于静态属性(类变量)的删除,应当使用 del 关键字直接在类定义外部操作,而不是 delattr

总之,在使用 delattr 时 ,务必清楚其潜在的副作用,并确保有充分的理由去执行属性删除操作,以免引入难以预料的错误到你的代码中。

5、综合案例:构建动态属性处理器 🌀

5.1 设计思路解析

在面向对象编程中,动态属性处理器是一种能够根据运行时数据动态创建、修改、检查或删除对象属性的机制。这种能力在处理高度可定制或不确定的业务逻辑时尤为关键 ,比如配置管理、元编程等场景。我们将利用getattrsetattrhasattrdelattr构建一个简单的动态属性处理器 ,以展示其在实际应用中的灵活性和效率。

功能目标:
  1. 根据传入的键值对动态创建对象属性。

  2. 提供方法检查对象是否具有特定属性。

  3. 允许安全地修改对象属性。

  4. 支持按需删除对象属性。

设计步骤:
  1. 初始化对象:创建一个基础类,用于存储和管理动态属性。

  2. 动态属性创建:实现方法接收键值对列表 ,使用setattr为对象动态添加属性。

  3. 属性检查:设计函数,利用hasattr检查对象是否具有给定的属性名。

  4. 属性修改:提供接口,通过setattr安全地修改现有属性值。

  5. 属性删除:实现功能 ,使用delattr按需移除属性。

5.2 代码实现与优化

接下来,我们将按照上述设计思路,逐步实现一个动态属性处理器的代码框架。

示例代码:

class DynamicAttrHandler:
    def __init__(self):
        # 初始化,对象默认无任何动态属性
        pass

    def add_attributes(self, attributes):
        """
        根据传入的键值对列表 ,动态创建对象属性。
        :param attributes: 键值对列表 ,如 [('name', 'Alice'), ('age', 30)]
        """
        for key, value in attributes:
            setattr(self, key, value)

    def has_attribute(self, attribute_name):
        """
        检查对象是否具有特定属性。
        :param attribute_name: 待检查的属性名
        :return: True/False
        """
        return hasattr(self, attribute_name)

    def set_attribute(self, attribute_name, value):
        """
        安全地修改现有属性值。
        :param attribute_name: 属性名
        :param value: 新的属性值
        """
        setattr(self, attribute_name, value)

    def delete_attribute(self, attribute_name):
        """
        移除对象的指定属性。
        :param attribute_name: 要删除的属性名
        """
        if self.has_attribute(attribute_name):
            delattr(self, attribute_name)

# 实例化动态属性处理器
handler = DynamicAttrHandler()

# 动态添加属性
handler.add_attributes([('name', 'Alice'), ('age', 30)])

# 检查属性是否存在
print(handler.has_attribute('name'))  # 应输出True
print(handler.has_attribute('gender'))  # 应输出False

# 修改属性值
handler.set_attribute('age', 31)

# 删除属性
handler.delete_attribute('age')

# 最终状态验证
print(handler.__dict__)

输出:

True
False
{'name': 'Alice'}

在上述代码中 ,我们定义了一个DynamicAttrHandler类 ,它封装了动态属性的创建、检查、修改和删除功能。通过一系列方法的组合使用 ,我们构建了一个能够灵活响应运行时数据变化的动态属性处理器,这在实际项目中具有广泛的应用前景,尤其是在需要高度定制化或动态配置的系统中。

6、深入Python数据模型 📖

6.1 揭秘__getattribute__

在Python中,__getattribute__是一个特殊方法 ,它定义了对象属性的获取方式。当尝试访问对象的属性时,Python解释器会调用这个方法,而不是直接访问属性。这为自定义属性的获取流程提供了极大的灵活性,使得开发者可以添加额外的逻辑 ,如属性的验证、转换或动态生成等。

示例代码:

class CustomObject:
    def __init__(self, value):
        self._value = value

    def __getattribute__(self, item):
        if item == '_value':
            return 'Access to _value is restricted!'
        else:
            return super().__getattribute__(item)

obj = CustomObject(42)

print(obj._value)  # 将调用__getattribute__
print(obj.__dict__)  # 直接访问对象字典,绕过__getattribute__

输出:

Access to _value is restricted!
{'_value': 42}

在这个例子中,CustomObject类重写了__getattribute__方法,限制了对_value属性的直接访问,而允许通过对象字典__dict__间接访问。这展示了如何利用__getattribute__来控制属性的访问逻辑。

6.2 自定义属性访问控制

除了__getattribute__,Python还提供了__getattr____setattr__等特殊方法,分别用于处理未定义属性的访问和属性的设置。这些方法的结合使用,可以实现更复杂的属性访问控制机制。

示例代码:

class DynamicProperty:
    def __init__(self):
        self._properties = {}

    def __getattr__(self, item):
        if item in self._properties:
            return self._properties[item]
        else:
            raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{item}'")

    def __setattr__(self, key, value):
        if key.startswith('_'):
            super().__setattr__(key, value)
        else:
            self._properties[key] = value

dp = DynamicProperty()
dp.name = 'Alice'
dp.age = 30

print(dp.name)
print(dp.age)

try:
    print(dp.gender)
except AttributeError as e:
    print(e)

输出:

Alice
30
'DynamicProperty' object has no attribute 'gender'

这段代码定义了一个DynamicProperty类,它使用__getattr____setattr__实现了动态属性的存储和访问。当尝试设置或获取属性时,这些方法会被调用 ,从而实现了对属性的动态管理。如果尝试访问一个未定义的属性,__getattr__会抛出AttributeError,确保了属性访问的健壮性。

7、性能考量与最佳实践 ⏱️

7.1 动态属性操作的性能影响

在Python中频繁使用 getattrsetattrhasattrdelattr 这类动态属性访问函数可能会对性能产生一定影响。每次调用这些函数时,Python解释器都需要进行额外的查找和安全性检查,相比于直接访问属性(即通过.属性名方式) ,这会带来微小的性能开销。在大规模循环或高频率调用的场景下,这种开销可能会累积 ,进而影响整体性能。

7.2 优化策略:减少动态属性依赖

为了提高效率,可以采取以下策略减少对动态属性操作的依赖:

  1. 属性缓存:如果属性访问模式相对固定 ,可以考虑首次访问时缓存属性引用 ,后续直接使用缓存的引用访问属性,避免重复的查找过程。

示例代码:

class CachedAccess:
    def __init__(self):
        self._cached_attr = None

    def cached_get(self, obj, attr_name):
        if self._cached_attr is None:
            self._cached_attr = getattr(obj, attr_name)
        return self._cached_attr
  1. 直接访问:在可能的情况下,优先使用直接属性访问,特别是在循环和关键路径代码中。对于那些确定性的属性,直接使用点操作符(.)访问会更高效。

  2. 设计模式优化:采用如“策略模式”、“装饰器模式”等设计模式重构代码,减少对动态属性操作的直接依赖,转而通过更高效的设计模式来组织和管理属性。

7.3 实战建议:平衡灵活性与效率

在实际应用中 ,平衡动态属性带来的灵活性与潜在的性能损失至关重要。以下是一些建议:

  • 评估使用场景:仔细分析应用的具体需求,识别哪些部分对性能敏感 ,哪些部分需要高度灵活性。对性能敏感的部分尽量减少动态属性的使用。

  • 分层设计:在架构设计上,可以将需要高度动态性的部分与性能敏感部分分开 ,使动态属性操作的影响局部化。

  • 适时使用反射:在需要高度灵活性或动态性配置的场景(如插件系统、动态配置加载)中,适时利用反射机制是合理的,但应确保对性能影响的监控和优化。

  • 性能测试:在引入动态属性操作后,通过性能测试工具(如Python的timeit模块或第三方库如pytest-benchmark)定期评估关键路径的性能,确保优化措施的有效性。

通过上述策略和建议 ,开发者可以在享受动态属性带来的便利的同时,有效控制和优化性能,达到灵活性与效率的和谐共存。

8、总结与展望 🚀

探索Python中getattrsetattrhasattr, 和 delattr的使用之旅,揭示了动态属性操作的精髓。从基础应用到高级技巧,这些函数不仅助力于对象属性的灵活获取与修改 ,还确保了安全性与内存管理的高效性。通过实战演练,如构建动态属性处理器,深入理解其在设计模式及实际项目中的强大功能。对比Java反射机制与JavaScript的相似功能,凸显了Python在动态语言特性上的独特优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783405.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 命令历史、补全和正则表达式

1.命令历史就和windows的ctrlz一个概念,就是返回上一次的命令。 按下小键盘上下切换 ctrlc可以终止本次输入,进行下一次输入。 2.tab键可以自动补全(有点鸡肋) 3.正则表达式 类似于word的快速搜索,Linux也是用*和…

浅析C++引用

浅析C引用"&" ​ C中引入了一个新的语言特性——引用(&),它表示某一对象的别名,对象与该对象的引用都是指向统一地址。那么我们就来看看关于引用的一些知识点吧🧐 特性 引用在定义时必须初始化一个变量可以有多个引用引…

zdppy_api+vue3+antd前后端分离开发,使用描述列表组件渲染用户详情信息

后端代码 import api import upload import time import amcomment import env import mcrud import amuserdetailsave_dir "uploads" env.load(".env") db mcrud.new_env()app api.Api(routes[*amcomment.get_routes(db),*amuserdetail.get_routes(db…

记一次微信小程序逆向

扫码领取网安教程 遇到瓶颈了,不知道该干什么,突然想到学校的小程序 闲来无事就看一看 抓包下来的数据是这样的,嗯,下机(hhh 一、反编译程序 加密嘛,之前抓了看到是加密就放弃了,现在重新弄一…

轻松转换!两款AI工具让word秒变ppt!

想把Word文档一键生成PPT,过去有一个很常见的做法:先在Word文档中设置标题样式,通过标题样式来分隔每一部分,之后导出为PPT,就能得到一份PPT的雏形,但这种方法无法对PPT自动进行美化,即得到的只…

js替换对象内部的对象名称或属性名称-(第二篇)递归

1.代码示例: function replaceKey(obj, oldKey, newKey) {// 如果不是对象或者oldKey不存在,直接返回原对象if (typeof obj ! object || !obj || !(oldKey in obj)) return obj;// 如果是数组,遍历数组每个元素if (Array.isArray(obj)) {obj…

【Python】一文向您详细介绍 np.inner()

【Python】一文向您详细介绍 np.inner() 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本硕,曾…

君方智能设计平台-对象持久化技术方案

1.背景介绍 1.1序列化功能 序列化是将复杂的图形对象、数据结构或对象转换成一种可被存储、传输或分享的格式的过程。这个格式通常是二进制或文本形式,能够轻松地保存在文件中或通过网络发送到其他应用程序。序列化的目的是将数据持久化,使其在不同时间…

【学术会议征稿】2024年第四届工商管理与数据科学学术会议(BADS 2024)

2024年第四届工商管理与数据科学学术会议(BADS 2024) 2024 4th International Conference on Business Administration and Data Science 2024年第四届工商管理与数据科学学术会议(BADS 2024)将于2024年10月25-27日在新疆喀什召开,由喀什大学支持本次会议。会议旨…

Mapboxgl 根据 AWS 地形的高程值制作等高线

更多精彩内容尽在dt.sim3d.cn&#xff0c;关注公众号【sky的数孪技术】&#xff0c;技术交流、源码下载请添加VX&#xff1a;digital_twin123 使用mapboxgl 3.0版本&#xff0c;根据 AWS 地形图块的高程值制作等高线&#xff0c;源码如下&#xff1a; <!DOCTYPE html> &…

OV证书签发一般要多久?

OV证书&#xff0c;即组织验证型SSL证书&#xff0c;的签发流程涉及多个阶段&#xff0c;其具体时间取决于多种因素。OV证书的签发一般需要1-3个工作日&#xff0c;这个过程可以分为以下几个阶段&#xff1a; 1、选择和购买证书&#xff1a; 用户需要在SSL证书服务商处选择合适…

AnaPico为众多工厂产线老化测试提供高效经济的微波解决方案

在电子设备的生产中&#xff0c;老化测试在整个使用寿命期间的可靠性和对声明参数的保证起着重要作用&#xff0c;尤其是在特殊应用&#xff08;国防和航天工业、电信、医药等&#xff09;方面。即使经过成功的参数和功能测试&#xff0c;在实际操作条件下使用时也有可能出现设…

【JSP+Servlet+Maven】——优质外卖订餐系统之概论部分

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

【Linux】进程的概念 + 查看进程

前言&#xff1a; 在前面我们学习了Liunx的基本指令和权限相关知识&#xff0c;还有基本工具的使用&#xff0c;有了以上的基础知识我们本章将正式接触Linux操作系统。 目录 1.冯诺依曼体系结构1.1 内存存在的意义1.2 程序加载到内存的含义1.3 程序的预加载&#xff1a; 2 .认识…

python读取指定文件夹下的图片(glob获取)

python读取指定文件夹下的图片&#xff08;glob获取&#xff09; 定义traverse_images函数&#xff0c;仅需要改变下根路径即可 glob是python中用来查找符合特定规则的文件路径名的函数 import os from glob import globdef traverse_images (folder_path):image_formats …

Google账号输入用户名和密码后提醒要到手机通知点是,还要点击数字,但是我手机收不到

有一些朋友换了一个新的电脑后手机登录谷歌账号时&#xff0c;用户名和密码都正确输入以后&#xff0c;第三步弹出一个提示&#xff0c;要在手机上的通知栏点击是&#xff0c;并且点击手机上相应的数字才能继续登录。 但是自己的手机上下拉通知栏却没有来自谷歌的通知&#xf…

mkv怎么改成mp4格式?把mkv改成MP4的几种方法介绍

mkv怎么改成mp4格式&#xff1f;将mkv格式的视频文件转换为MP4格式是许多用户常常需要解决的问题&#xff0c;尤其是在不同设备之间传输和播放视频时。mkv是一种灵活且功能强大的多媒体容器格式&#xff0c;能够包含多种视频、音频和字幕轨道。然而&#xff0c;尽管其优势显著&…

前端web在线PPT编辑器-PPTLIST

哈喽&#xff0c;大家好&#xff0c;今天给大家介绍一款的在线的PPT编辑器开源框架-PPTLIST&#xff1b;他是一个基于 Vue3.x TypeScript 的在线演示文稿&#xff08;幻灯片&#xff09;应用&#xff0c;还原了大部分 Office PowerPoint 常用功能&#xff0c;支持 文字、图片、…

MSP学习

一、迁移资源调研 完成导入&#xff0c;类似完成选型分析 离线工具调研 账单 二、迁移计划 1、

【教程】新的Selenium!整合了隐藏浏览器指纹等功能

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 前景提要 driver Driver() 常用driver 接口 最后的话 前景提要 新的selenium&#xff0c;整合了隐藏浏览器指纹&#xff0c;非常好用&#x…