爲何類會擁有其元類的屬性?

最近在學習Python的一些設計模式,當看到用元類實現單例模式代碼的時候,發現一個頗有意思的問題,先看代碼:設計模式

class Meta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = type.__call__(cls, *args, **kwargs)
        return cls._instances[cls]

問題是_instances不是元類的屬性嗎?爲何能夠經過cls._instances來訪問?
stackoverflow有人曾提過相同的問題,點這裏能夠看學習

編寫了一些實驗的代碼,以下:設計

class TopMeta(type):
    topmeta = 'topmeta'

class MetaBaseCls:
    metabasecls = 'metabasecls'
    
class UpperMeta(type, MetaBaseCls, metaclass=TopMeta):
    uppermeta = 'uppermeta'
    attr = 'uppermeta attr'

class BaseCls:
    basecls='basecls'
    attr = 'basecls attr'

class C(BaseCls, metaclass=UpperMeta):
    pass


C.basecls
C.uppermeta
C.metabasecls
C.attr
try:
    print(C.topmeta)
except Exception as e:
    print(e)

輸出爲:code

'basecls'

'uppermeta'

'metabasecls'

'basecls attr'

type object 'C' has no attribute 'topmeta'

根據上面的實驗,能夠發現:對象

  1. C會先在自身的繼承鏈裏查找,因此打印basecls attr,而不是uppermeta attr。
  2. uppermeta和metabasecls都在其元類的繼承鏈中,因此均可以找到。
  3. topmeta是其元類的元類,並不在其元類的繼承鏈中,找不到,會報錯。

具體的實現細節沒有徹底弄清楚,但簡單總結一些規律:
對象(注意這個對象包含實例和類)會先在本身的整個繼承鏈裏面尋找屬性,若是沒有找到,則會在它的類的繼承鏈裏面尋找屬性,而類是元類的實例,換句話說,類的類是元類。因此類會先在自身的繼承鏈裏面查找屬性,若是找不到,則到它的元類的繼承鏈裏面查找屬性。繼承

這裏容易想不通的是按照以上解釋,實例的繼承鏈不就是其類的繼承鏈嗎?那不是重複了?
我的是這樣理解,實例是經過object類創造出來,類是經過type類創造出來,因此本質上說實例和類是不一樣的東西,類有繼承鏈,實例沒有,只有自身的命名空間。因此對於實例來講,先在本身的命名空間裏面查找屬性,找不到,再在其類的繼承鏈裏尋找屬性。
若是有不對的地方,請你們指出。get

相關文章
相關標籤/搜索