动态属性和特性
此笔记记录于《流畅的 python》,大部分为其中的摘要,少部分为笔者自己的理解;笔记为 jupyter 转的 markdown,原始版 jupyter 笔记在这个仓库
关于元编程的一些解释:
Python 中的元编程是指在运行时创建或自定义代码的技术。这涉及到使用 Python 的反射特性和动态性质来编写程序,这些程序可以操纵、生成或修改自身或其他程序的代码。元编程常用于框架开发、代码生成、动态修改类或函数等场景。
Python 中实现元编程的几种方式包括但不限于:
- 使用装饰器
(Decorators)
:装饰器可以修改或增强函数、方法或类的行为,而不需要改变其代码。 - 使用元类
(Metaclasses)
:元类是创建类的“类”。通过自定义元类,可以控制类的创建过程,从而实现复杂的行为。 - 使用
exec()
和eval()
函数:这些函数可以执行存储在字符串或编译对象中的 Python 代码。 - 使用
getattr()
,setattr()
,delattr()
函数:这些函数可以用来动态地操作对象的属性。
得多写一些 python 代码再来看这部分章节
动态特性或属性
动态特性或属性 | 描述 | 示例 |
---|---|---|
动态创建类 | 使用type 函数或自定义元类来动态创建类。 | MyClass = type('MyClass', (BaseClass,), {'attr': value}) |
装饰器 | 函数装饰器和类装饰器用于在不修改原有代码的情况下增加额外功能。 | @decorator def function(): pass |
元类 | 类的类,可以控制类的创建过程。 | class Meta(type): pass class MyClass(metaclass=Meta): pass |
exec() 和 eval() | 执行和评估字符串形式的 Python 代码。 | exec('print("Hello World")') |
getattr(), setattr(), delattr() | 动态地获取、设置或删除对象的属性。 | getattr(obj, 'attr') |
getattr, setattr, delattr | 特殊方法,允许自定义属性访问、设置或删除的行为。 | def __getattr__(self, name): pass |
globals() 和 locals() | 分别返回当前全局和局部符号表的字典,允许动态访问变量。 | globals()['variable_name'] = value |
动态导入 | 使用importlib 模块动态导入模块。 | importlib.import_module('module_name') |
import() | 内置函数,用于动态导入模块。 | __import__('module_name') |
new() | 特殊方法,用于在类实例化时创建新实例。它是在__init__()之前调用的。 | class MyClass(object): def __new__(cls, *args, **kwargs): instance = super(MyClass, cls).__new__(cls) # 初始化操作 return instance |
属性描述符
属性描述符是实现了特定协议的类,该协议包括__get__()
, __set__()
和__delete__()
方法中的至少一个。描述符使你能够创建一个对象,当它被附加到另一个对象的属性时,可以控制对该属性的访问、修改或删除操作。描述符是实现属性和方法装饰器背后的机制。
描述符的类型
类型 | 描述 | 必须实现的方法 |
---|---|---|
数据描述符 | 同时定义了__get__() 和__set__() 方法的描述符。数据描述符具有比实例字典更高的优先级。 | __get__(), __set__() |
非数据描述符 | 只定义了__get__() 方法的描述符。如果一个实例的字典中有与非数据描述符同名的项,则该项的值会覆盖非数据描述符的值。 | __get__() |
描述符的方法
__get__(self, instance, owner)
:用于访问属性。它返回属性的值或者在访问时触发的任何动作。__set__(self, instance, value)
:将在属性分配操作中调用,允许你定义设置属性值时的行为。__delete__(self, instance)
:允许你定义删除属性时的行为。
示例
下面是一个简单的数据描述符示例,它用于类型检查:
python
class TypedProperty:
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"Value must be of type {self.expected_type}")
instance.__dict__[self.name] = value
class MyClass:
name = TypedProperty("name", str)
age = TypedProperty("age", int)
obj = MyClass()
obj.name = "John" # 正确
obj.age = 30 # 正确
# obj.age = "thirty" # 将抛出 TypeError
在这个例子中,TypedProperty
是一个数据描述符,因为它同时定义了__get__()
和__set__()
方法。它被用来确保MyClass
的name
属性是字符串类型,age
属性是整数类型。