問題描述
Python in a Nutshell 描述了獲取屬性時的查找過程.本書區分了兩種情況
Python in a Nutshell describes the lookup procedures when getting an attribute. The book distinguishes two cases
從類中獲取屬性時的查找過程,例如
cls.name
從類中獲取屬性
當您使用語法 C.name
來引用屬性時在類對象 C
上,查找分兩步進行:
When you use the syntax C.name
to refer to an attribute
on a class object C
, the lookup proceeds in two steps:
當
name
是C.__dict__
中的鍵時,C.name
獲取值v
來自C.__dict__['name']
.那么,當v
是一個描述符(即type(v)
提供一個名為__get__
),C.name
的值是調用的結果type(v).__get__(v, None, C)
.當v
不是描述符時,C.name 的值為 v
.
When
name
is a key inC.__dict__
,C.name
fetches the valuev
fromC.__dict__['name']
. Then, whenv
is a descriptor (i.e.,type(v)
supplies a method named__get__
), the value ofC.name
is the result of callingtype(v).__get__(v, None, C)
. Whenv
is not a descriptor, the value ofC.name is v
.
當 name
不是 C.__dict__
中的鍵時,C.name
將查找委托給 C
的基類,這意味著它在 C
上循環祖先類并嘗試對每個類進行名稱查找(在方法中解決順序,如頁面上的方法解決順序"中所述113).
When name
is not a key in C.__dict__
, C.name
delegates the lookup to C
’s base classes, meaning it loops on C
’s
ancestor classes and tries the name lookup on each (in method
resolution order, as covered in "Method resolution order" on page
113).
從實例獲取屬性時的查找過程,例如obj.name
由于在 Python 3 中,每個類對象實際上都是其元類的一個實例(例如 type
類),根據本書,為什么從類中獲取屬性的查找過程和從不同實例中獲取屬性的查找過程?
Since in Python 3, every class object is actually an instance of its metaclass (e.g. type
class), according to the book, why are the lookup procedure for getting an attribute from a class and the lookup procedure for getting an attribute from an instance different?
推薦答案
它們并沒有非常不同,書中的描述涵蓋了它們不同的兩種方式:
They're not very different, and the description from the book covers the two ways in which they differ:
- 在類實例上找到的描述符(在類上找不到之后)不會被調用(
ax = somedescriptor()
其中a
是一個類實例,不是一個類,后跟ax
只會返回你剛剛創建的somedescriptor()
的實例),而在元類實例上找到的描述符,即一個類(在沒有找到之后在元類上)以None
作為它被調用的實例調用(Ax = somedescriptor()
其中A
是元類實例,而不是一個元類,將在您剛剛創建的somedescriptor()
上調用.__get__(None, A)
).這允許像@classmethod
這樣的東西通過將方法綁定到類本身來工作,無論它是在類的實例上還是在類本身上查找. - 類實例沒有父實例"的概念.(類實例本身的命名空間是一個扁平的
dict
,即使與該類實例關聯的屬性是由多個繼承級別的方法定義的),因此基于MRO的查找的想法是獨一無二的到元類實例.
- Descriptors found on a class instance (after not being found on the class) don't get invoked (
a.x = somedescriptor()
wherea
is a class instance, not a class, followed bya.x
will just return the instance ofsomedescriptor()
you just made), while descriptors found on a metaclass instance i.e. a class (after not being found on the metaclass) get invoked withNone
as the instance it was called on (A.x = somedescriptor()
whereA
is a metaclass instance, not a metaclass, will invoke.__get__(None, A)
on thesomedescriptor()
you just made). This allows stuff like@classmethod
to work by binding the method to the class itself whether it's looked up on an instance of the class or the class itself. - Class instances don't have a concept of "parent instances" (the namespace of the class instance itself is a flat
dict
, even if the attributes associated with that class instance were defined by methods from multiple levels of inheritance), so the idea of MRO-based lookup is unique to metaclass instances.
其他一切都差不多,只是本書在這里掩蓋了元類的概念,因為大多數類都是基本 type
的實例,沒有特殊行為.如果您有 type
以外的元類,則在查找類的屬性時會應用完整的實例查找規則(只是該類的類是元類).
Everything else is pretty much the same, it's just that the book is glossing over the concept of metaclasses here, since most classes are instances of the base type
, which has no special behaviors. If you have a metaclass other than type
, the full instance lookup rules apply when looking up attributes on a class (it's just the class of the class is the metaclass).
他們可能在早期試圖避免元類的復雜性,但在這個過程中,實例查找的規則似乎不適用于類;確實如此,只是類在基本查找過程中添加了一些額外的規則.
They were probably trying to avoid the complexity of metaclasses early on, but in the process made it seem like the rules for instance lookup didn't apply to classes; they do, it's just that classes add a couple extra rules to the basic lookup procedure.
這篇關于為什么從類和實例中獲取屬性的查找過程不同?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!