Skip to main content
 首页 » 编程设计

python之Python 的内置 type.__init__(name,bases,dct) 有什么作用吗

2025年05月04日12lonelyxmas

我见过一些 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) 

输出:

a 
b 
<...my system traceback...> 
AttributeError: type object 'Klass' has no attribute 'c' 

显然 dct 不用于更新 Klass.__dict__。据我所知,这没有任何作用。它有作用吗?您是否有可能想要包含它的原因? Klass 和 Klass2 之间有什么有效的区别吗?

注意:我专门讨论 Meta 继承自 type 的情况,而不是一些自定义父类(super class)。

请您参考如下方法:

type.__init__() implementation确实什么都不做,除了验证参数计数和调用object.__init__(cls) (除了一些合理性检查外,它什么都不做)。

但是,对于从其他混合元类继承并必须考虑的元类,使用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'}) 

请注意最后调用 MetaMixin() 的方式(在调用 type.__init__() 之前)。如果 MetaMixin.__init__() 要查询 namespace 字典供自己使用,然后在 MetaFoo.__init__() 中更改 namespace 会改变 MetaMixin.__init__() 在该字典中找到的内容。

因此,对于在元类的 __init__ 方法中使用 super() 的情况,您可能需要检查更复杂的元类层次结构。或者该项目只是为了安全起见,并确保可以在更复杂的场景中继承它们的元类。

namespace 字典参数(您使用的名称 dct)在用作类属性字典之前被复制,因此添加新键在 __init__ 中使用它确实不会改变类字典。