Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
276 views
in Technique[技术] by (71.8m points)

python - Why are the lookup procedures for getting an attribute from a class and from an instance different?

Python in a Nutshell describes the lookup procedures when getting an attribute. The book distinguishes two cases

  • the lookup procedure when getting an attribute from a class, e.g. cls.name

    Getting an attribute from a class

    When you use the syntax C.name to refer to an attribute on a class object C, the lookup proceeds in two steps:

    1. When name is a key in C.__dict__, C.name fetches the value v from C.__dict__['name'] . Then, when v is a descriptor (i.e., type(v) supplies a method named __get__ ), the value of C.name is the result of calling type(v).__get__(v, None, C) . When v is not a descriptor, the value of C.name is v .

    2. 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).

  • the lookup procedure when getting an attribute from an instance, e.g. obj.name

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

They're not very different, and the description from the book covers the two ways in which they differ:

  1. Descriptors found on a class instance (after not being found on the class) don't get invoked (a.x = somedescriptor() where a is a class instance, not a class, followed by a.x will just return the instance of somedescriptor() you just made), while descriptors found on a metaclass instance i.e. a class (after not being found on the metaclass) get invoked with None as the instance it was called on (A.x = somedescriptor() where A is a metaclass instance, not a metaclass, will invoke .__get__(None, A) on the somedescriptor() 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.
  2. 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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...