最近在學習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類設定...