修饰器
在 Python 中,修饰器(decorators)是用于修改函数或类方法行为的特殊函数。常用修饰器主要有以下几类:
0. @property
- 作用:将类中的方法转化为属性,使得你可以像访问属性一样调用方法,而不需要使用括号
(). - 实现效果:简化属性访问,隐藏内部实现细节。
-
示例:
-
调用:
person.name而不是person.name()
1. @property. setter
- 作用:允许你对该属性进行赋值操作。如果没有 setter 方法,属性是只读的。
- 示例:
只有这个修饰了,才能修改这个值,否则会出现 AttrubiteError 错误
2. @staticmethod
- 作用:将类中的方法声明为静态方法,不需要通过实例化类来调用方法,也没有对类实例的依赖。
- 实现效果:适合那些不需要访问类或实例属性的方法。
-
示例:
-
调用:
Math.add(5, 3)
3. @classmethod
- 作用:定义一个类方法,第一个参数
cls代表类本身,可以通过类调用,也可以通过实例调用。 - 实现效果:允许修改类的状态或调用类方法。
-
示例:
-
调用:
Person.get_count()或者person.get_count()
4. @staticmethod vs @classmethod
- @staticmethod 不涉及类的状态,也不接收类实例或类本身作为参数。
- @classmethod 可以操作类级别的状态。
5. @lru_cache (functools. lru_cache)
- 作用:缓存函数的返回结果,以提高重复调用时的效率(通常用于递归或密集计算)。
- 实现效果:缓存机制,减少重复计算。
- 示例:
6. @wraps (functools. wraps)
- 作用:用于装饰器函数内部,确保装饰器不会改变原函数的元数据(如函数名、文档字符串等)。
- 实现效果:保持被装饰函数的原有属性。
- 示例:
7. @abstractmethod (abc. abstractmethod)
- 作用:用于抽象类中,要求子类必须实现该方法。
- 实现效果:强制子类提供特定方法的实现。
- 示例:
这些是 Python 中常见且有用的修饰器。通过它们,可以更加简洁和灵活地控制类和函数的行为。
机制
__slots__ 不是一个修饰器,而是 Python 中类的一种机制,用于限制类实例的属性。它可以帮助节省内存,并提高某些情况下的性能。下面详细解释其作用和使用场景。
1. 什么是 __slots__?
通常,Python 中的类实例会将其属性存储在一个名为 __dict__ 的字典中。每次你为类实例添加新属性时,都会在 __dict__ 中添加一个键值对。然而,字典是比较消耗内存的结构,尤其是当你有大量对象实例时。
__slots__ 通过限制类实例只能有特定的属性,避免了为每个实例创建 __dict__,从而节省内存。
2. 使用 __slots__ 的效果
- 限制类实例只能有指定的属性。
- 减少内存使用。
- 禁止动态添加新的属性(如果不在
__slots__中定义)。
3. 示例
class Person:
__slots__ = ['name', 'age'] # 限制只能有 'name' 和 'age' 这两个属性
def __init__(self, name, age):
self.name = name
self.age = age
# 创建一个对象
p = Person('Alice', 30)
# 访问属性
print(p.name) # 输出: Alice
print(p.age) # 输出: 30
# 尝试添加新属性会导致错误
p.address = 'New York' # AttributeError: 'Person' object has no attribute 'address'
4. 优点
-
内存节省:当有大量实例时,使用
__slots__可以显著减少内存消耗。因为每个对象不再有__dict__存储属性。 -
性能优化:访问和设置属性的速度可能会提高,因为它绕过了
__dict__的键值查找过程。
5. 注意事项
- 不适合所有类:如果你需要动态添加属性,或者不确定类的所有属性,可以不使用
__slots__。 -
继承的限制:在子类中,
__slots__的行为可能会带来复杂性。如果子类没有定义__slots__,它将拥有自己的__dict__。 -
无法使用
__dict__和__weakref__:当你使用__slots__时,类实例将不再有__dict__和__weakref__,除非你明确包含它们:
6. 适用场景
- 大量实例化对象:例如在需要创建数百万个对象实例时,使用
__slots__可以显著减少内存占用。 - 固定属性的类:适合那些属性集合固定的类,避免意外地添加新的属性。
总结
__slots__ 是一个用于优化 Python 对象内存使用的工具。它通过限制类实例的属性并取消 __dict__ 的创建来节省空间,并可以提高访问速度。但在灵活性上有所妥协,因此应在内存优化需求较高的场景下使用。
1. __new__ 和 __init__
__new__:负责创建对象实例。__new__是一个静态方法,在实例化时优先调用,返回一个新的实例。__init__:负责初始化实例属性,__new__创建对象后会调用__init__。- 使用场景:当需要控制对象创建过程(如实现单例模式)时使用
__new__。 - 示例:
2. __repr__ 和 __str__
__repr__:定义对象的“官方”字符串表示,主要用于调试和开发。__str__:定义对象的“友好”字符串表示,主要用于用户端展示。- 区别:
__repr__应该尽可能返回一个可以用来重建对象的字符串;__str__更关注可读性。 - 示例:
3. 上下文管理器 (with 语句) 和 __enter__, __exit__
- 作用:
with语句用于简化资源管理(如文件操作、数据库连接),自动处理资源的获取和释放。 __enter__:在with块开始时执行,返回资源对象。__exit__:在with块结束时执行,负责清理资源(如关闭文件、释放锁)。- 示例:
4. 迭代器和生成器
- 迭代器 (
__iter__和__next__):定义可迭代对象,__iter__返回迭代器对象,__next__返回下一个元素。 - 生成器 (
yield):通过yield关键字生成惰性计算序列,每次调用next()时生成下一个值。 - 使用场景:处理大型数据集时,生成器可以节省内存;迭代器可用于自定义迭代行为。
- 示例: :
5. 元类 (metaclass)
- 作用:元类是用于创建类的“类”,它决定了类的创建方式。可以通过自定义元类来控制类的行为或属性。
- 使用场景:当需要动态控制类的创建或修改类的行为时使用。
- 示例:
6. 反射 (getattr, setattr, hasattr)
- 作用:允许动态访问对象的属性或方法,通过名称在运行时获取或修改属性。
- 使用场景:在不确定对象结构时,通过字符串动态访问对象的属性或方法。
- 示例:
7. 装饰器 (decorators)
- 作用:装饰器是用于包装函数或类的函数,允许在不修改原函数或类的前提下增强其功能。
- 使用场景:如日志记录、权限验证、缓存、性能优化等。
- 示例:
8. 运算符重载 (__add__, __mul__, 等)
- 作用:允许自定义类的运算符行为(如
+,*等),通过定义特定的魔法方法来改变这些运算符对类实例的操作。 - 示例:
这些机制在 Python 中非常常用,它们让代码更具表现力、灵活性和可扩展性。