假设我有一个自定义元类和一个链接到它的类:
class Meta(type): pass
class A(metaclass=Meta): pass
据我所知,在class A
语句末尾,将执行以下步骤:
Meta('A', (), {})
李>type.__call__(...)
。这是因为type
链接到Meta.__class__
李>type.__call__(...)
依次运行另外两个方法(a__new__
和a__init__
)李>Meta
定义了这两个方法中的一个或两个,那么type.__call__
内部的这些方法将作为Meta.__new__(...)
和/或Meta.__init__(...)
调用李>A
被创建并链接到Meta
(A.__class__
)李>现在,假设我有一个子类A
:
class Meta(type): pass
class A(metaclass=Meta): pass
class B(A): pass
在class B
语句的末尾,以下步骤正确吗
type('B', (), {})
而不是Meta
,因为B.__class__
是type
李>type.__call__(...)
,它依次运行另外两个方法(__new__
和__init__
)李>type.__new__(type, 'B', (A,), {})
李>type.__init__(cls, 'B', (A,), {})
李>假设上述步骤是正确的(我对此表示怀疑),那么B.__class__
不应该给出type
而不是Meta
吗?我的理由是B
是用默认的type
元类创建的。但是打印出来的B.__class__
给出的是Meta
,而不是type
print(B.__class__) #<class '__main__.Meta'>
另外,如果我手动创建一个以A
为父级的类,那么创建的类将再次链接到Meta
C = type.__call__(type, 'C', (A,), {})
print(C.__class__) #<class '__main__.Meta'>
#or
D = type.__new__(type, 'D', (A,), {})
print(D.__class__) #<class '__main__.Meta'>
我的问题是Python如何创建class B/C
以及B/C
如何链接到Meta
所以,这是一个有点令人困惑的问题,可以回答,有些则简化了 只需在交互模式下运行一些示例
但首先,当您声明:
这是对所发生事情的简化
当我们创建新类时,比如在解析类语句
class A:
时,会调用type.__call__
。但是这个调用是在Meta
的类中搜索的。也就是说,“Meta”的“元类”——默认情况下是type
请原谅我: 当我们讨论一个没有自定义元类的普通类E时,通过执行
E()
-Python搜索__call__
方法来创建一个实例,其中E
是一个实例:即它的元类。因为它是类型,所以调用type.__call__
。正如您所说,是type.__call__
调用__new__
和__init__
方法,但不仅仅是元类:它在任何对象实例化中协调这些调用-Python中的任何对象实例化都使用完全相同的机制:普通对象和类:因此,简而言之:当创建一个类a(Meta的实例)时,调用Meta类的
__call__
方法。这将调用元类Meta中的__init__
和__new__
。如果未定义这些方法,则普通属性查找将在Meta的超类中调用这些方法,而也将被称为“type”现在,继续你的问题:当一个人从一个具有自定义元类的类继承时,比如你的
B
类,Python会将其超类中最派生的元类作为自己的元类,而不是type
。无需显式声明自定义元类。实际上,这正是元类需要而不仅仅是类修饰符的原因:这些修饰符只影响声明它们的类,对其他子类没有影响即使在对
type
而不是class
语句的显式调用中,派生类的元类也将是超类的元类。但是,请注意,在这种情况下,我们将对type.__new__
的“metameta”类的调用硬编码,并且忽略了“元类的自定义元类”:如果您想通过编程创建一个具有自定义“meta-class”的类(除学习目的外,任何人都不可能需要该类),那么
types
模块中有一个特殊调用可以实现这一点:最后,请注意,如果一个类的超类有不同的元类,Python将拒绝创建一个类。这在“真实世界”代码中有点常见,当人们试图在带有ORM的框架中使用基类创建抽象类(使用自定义元类)时,通常也有自定义元类:
它可以通过生成继承自的派生元类来修复 两个祖先分支中的元类(这要求两个元类 行为良好,使用
super()
而不是对type
的硬编码调用-但是 维护良好且流行的框架就是如此):正如你后来提到的,事实并非如此
如果
X
类继承了Y
类,那么X
的元类与Y
的元类相同。您可以找到有关data model documentation的详细信息从文档中:
相关问题 更多 >
编程相关推荐