Skip to content

动态属性和特性

此笔记记录于《流畅的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__()方法。它被用来确保MyClassname属性是字符串类型,age属性是整数类型。