簡體   English   中英

Python的內置類型.__ init __(name,bases,dct)有什么作用嗎?

[英]Does Python's builtin type.__init__(name,bases,dct) do anything?

我已經看到了一些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__ 據我所知,這沒有任何作用。 它有作用嗎? 您可能有理由要包含它嗎? KlassKlass2之間有什么有效區別嗎?

注意:我正在專門討論Meta繼承自type而不是某些自定義超類的情況。

type.__init__()實現確實不執行任何操作,除了驗證參數計數並調用object.__init__(cls) (該操作僅進行了一些健全性檢查)。

但是,對於繼承自且必須考慮其他mixin元類的元類 ,請使用super().__init__(name, bases, namespace)確保MRO中的所有元類都被查詢。

例如,當使用多個元類將新的元類作為基礎時,通過super().__init__()調用的內容會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 )用作類屬性字典之前, dct復制 ,因此,在__init__向其添加新鍵實際上並不會改變類字典。

type.__init__僅確保:

  • 如果僅存在1個位置參數,則不會保留任何關鍵字參數,
  • 提供了1或3個位置參數,並且
  • object.__init__被調用,
    • 檢查它是否被正確調用。

__init__方法實際上沒有使用namebasesdct 除了初始調用已經做過的工作之外,沒有其他副作用(例如,檢查參數的有效性)。

結果, 如果超類是type ,則跳過super().__init__(name, bases, dct)的調用不會產生任何負面影響。 但是,類似於從object繼承的類,調用super().__init__是保持面向未來的正確設計-既可以更改繼承層次結構,也可以更改type

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM