T.A*_*.A. 1 python metaclass python-internals
我已经看到了一些Python元类使用super()调用的示例type.__init__()。这是做什么的?
例:
class Meta(type):
def __new__(cls, name, bases, dct):
dct['a']='a'
cls_obj = super(Meta, cls).__new__(cls, name, bases, dct)
return cls_obj
def __init__(cls_obj, name, bases, dct):
cls_obj.b = 'b'
dct['c'] = 'c'
#what does this do
super(Meta, cls_obj).__init__(name, bases, dct)
class Meta2(Meta):
def __init__(cls_obj, name, bases, dct):
cls_obj.b = 'b'
class Klass(metaclass=Meta):
pass
class Klass2(metaclass=Meta2):
pass
if __name__ == '__main__':
print(Klass.a)
print(Klass.b)
print(Klass.c)
Run Code Online (Sandbox Code Playgroud)
输出:
a
b
<...my system traceback...>
AttributeError: type object 'Klass' has no attribute 'c'
Run Code Online (Sandbox Code Playgroud)
显然dct不用于更新Klass.__dict__。据我所知,这没有任何作用。它有作用吗?您可能有理由要包含它吗?有没有之间的任何实际的区别Klass和Klass2?
注意:我是在专门讨论Meta从继承而type不是某些自定义超类的情况。
除了验证参数计数和调用(除了一些健全性检查之外,它什么也不做)之外,该type.__init__()实现确实不执行任何object.__init__(cls)操作。
但是,对于继承自并必须考虑其他mixin元类的元类,使用super().__init__(name, bases, namespace)确保可以查阅MRO中的所有元类。
例如,当使用多个元类将新的元类作为基础时,通过super().__init__()更改称为:
>>> class MetaFoo(type):
... def __init__(cls, name, bases, namespace):
... print(f"MetaFoo.__init__({cls!r}, {name!r}, {bases!r}, {namespace!r})")
... super().__init__(name, bases, namespace)
...
>>> class MetaMixin(type):
... def __init__(cls, name, bases, namespace):
... print(f"MetaMixin.__init__({cls!r}, {name!r}, {bases!r}, {namespace!r})")
... super().__init__(name, bases, namespace)
...
>>> class MetaBar(MetaFoo, MetaMixin):
... def __init__(cls, name, bases, namespace):
... print(f"MetaBar.__init__({cls!r}, {name!r}, {bases!r}, {namespace!r})")
... super().__init__(name, bases, namespace)
...
>>> class Foo(metaclass=MetaFoo): pass
...
MetaFoo.__init__(<class '__main__.Foo'>, 'Foo', (), {'__module__': '__main__', '__qualname__': 'Foo'})
>>> class Bar(metaclass=MetaBar): pass
...
MetaBar.__init__(<class '__main__.Bar'>, 'Bar', (), {'__module__': '__main__', '__qualname__': 'Bar'})
MetaFoo.__init__(<class '__main__.Bar'>, 'Bar', (), {'__module__': '__main__', '__qualname__': 'Bar'})
MetaMixin.__init__(<class '__main__.Bar'>, 'Bar', (), {'__module__': '__main__', '__qualname__': 'Bar'})
Run Code Online (Sandbox Code Playgroud)
注意如何MetaMixin()称为last(在type.__init__()调用之前)。如果MetaMixin.__init__()是咨询namespace字典自己的用途,然后改变namespace在MetaFoo.__init__()会改变什么MetaMixin.__init__()在字典中找到。
因此,对于看到super()在__init__元类方法中使用的情况,您可能需要检查更复杂的元类层次结构。或者该项目只是为了安全起见,并确保可以在更复杂的场景中继承其元类。
在将namespace字典参数(您使用过name dct)用作类属性字典之前,已将其复制,因此,向其中添加新键__init__实际上不会更改类字典。
| 归档时间: |
|
| 查看次数: |
73 次 |
| 最近记录: |