為什麼類會擁有其元類的屬性?

2022-05-22 17:51:09 字數 1650 閱讀 1750

最近在學習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)

輸出為:

'basecls'

'uppermeta'

'metabasecls'

'basecls attr'

type object 'c' has no attribute 'topmeta'

根據上面的實驗,可以發現:

c會先在自身的繼承鏈裡查詢,所以列印basecls attr,而不是uppermeta attr。

uppermeta和metabasecls都在其元類的繼承鏈中,所以都可以找到。

topmeta是其元類的元類,並不在其元類的繼承鏈中,找不到,會報錯。

具體的實現細節沒有完全弄清楚,但簡單總結一些規律:

物件(注意這個物件包含例項和類)會先在自己的整個繼承鏈裡面尋找屬性,如果沒有找到,則會在它的類的繼承鏈裡面尋找屬性,而類是元類的例項,換句話說,類的類是元類。所以類會先在自身的繼承鏈裡面查詢屬性,如果找不到,則到它的元類的繼承鏈裡面查詢屬性。

這裡容易想不通的是按照以上解釋,例項的繼承鏈不就是其類的繼承鏈嗎?那不是重複了?

個人是這樣理解,例項是通過object類創造出來,類是通過type類創造出來,所以本質上說例項和類是不同的東西,類有繼承鏈,例項沒有,只有自身的命名空間。所以對於例項來說,先在自己的命名空間裡面查詢屬性,找不到,再在其類的繼承鏈裡尋找屬性。

如果有不對的地方,請大家指出。

什麼是類 物件 屬性 方法 類的成員

類 具有同種屬性的物件稱為類,是個抽象的概念。比如說 汽車 人 狗 神 物件 日常生活中的所有東西都是物件,是類的例項化。比如說 推土車是汽車的例項化 姚明是人的例項化 小白 狗的名字 是狗的例項化 二郎神是神的例項化 屬性 用來描述具體某個物件的特徵的是屬性,是靜態的。比如 姚明身高2.6公尺多 ...

什麼是類 物件 屬性 方法 類的成員

類 具有同種屬性的物件稱為類,是個抽象的概念。比如說 汽車 人 狗 神 物件 日常生活中的所有東西都是物件,是類的例項化。比如說 推土車是汽車的例項化 姚明是人的例項化 小白 狗的名字 是狗的例項化 二郎神是神的例項化 屬性 用來描述具體某個物件的特徵的是屬性,是靜態的。比如 姚明身高2.6公尺多 ...

String類為什麼是final的

首先我們使用new建立乙個string物件的時候比如 string str new string 123 這句話裡面建立了兩個物件,第乙個在系統中建立了乙個 abc 這個字串 然後在創乙個str物件,然後在讓 123 這個字串的引用 創乙個string物件相當於創了兩個。在說說為啥string類設定...