元类的有用基类
项目描述
元类是 Python 中一个非常强大的工具。您可以使用它们控制整个类创建过程。
然而,大多数时候,它们太强大了。该模块可帮助您使用元类的一些优点,而无需了解所有细节。它定义了一个基类SubclassInit。从这个类继承可以修改子类的创建过程。
初始化子类
元类的一个非常常见的用例是您只想在创建类后执行一些代码。这可以通过SubclassInit轻松完成 。您只需定义一个方法__init_subclass__,它被隐式视为@classmethod并将在您的类生成的每个子类之后调用。作为参数,它获取类的命名空间。一个例子是一个简单的子类注册:
class Register(SubclassInit):
subclasses = []
def __subclass_init__(cls, ns, **kwargs):
super().__subclass_init__(ns, **kwargs)
Register.subclasses.append(cls)
请注意如何添加关键字参数。这些是类定义行中给出的关键字参数,如下所示:
class Subclass(Base, spam="ham"):
pass
不要忘记正确调用super()!其他类也可能想要初始化子类。这也是为什么你应该传递关键字参数,只取出你需要的那些。
初始化描述符
描述符是一种创建对象属性的强大技术,可以即时计算它们的值。属性是这种描述符的一个简单示例。这些描述符有一个共同的问题:他们不知道自己的名字。使用SubclassInit您可以将 __init_descriptor__方法添加到描述符,一旦类准备好并且描述符的名称已知,该方法就会被调用。
例如,我们可以定义一个使属性成为弱引用的描述符:
import weakref
class WeakAttribute:
def __get__(self, instance, owner):
return instance.__dict__[self.name]()
def __set__(self, instance, value):
instance.__dict__[self.name] = weakref.ref(value)
def __init_descriptor__(self, owner, name):
self.name = name
属性顺序
有时人们对在类中定义属性的顺序感兴趣。SubclassInit留下一个元组,其中所有属性的名称按照它们被定义为名为__attribute_order__的类属性的顺序排列 。请注意,Python 已经定义了一些类属性,例如__module__,其中一些也出现在这个元组中。
举个例子:
class AttributeOrder(SubclassInit):
a = 1
def b(self):
pass
c = 5
assert AttributeOrder.__attribute_order__ == \
('__module__', '__qualname__', 'a', 'b', 'c')