从实例中查找属性 [英] Look up an attribute from an instance
问题描述
简而言之,来自 Python
<块引用>从实例中获取属性
当您使用语法 x.name
来引用类 C
的实例 x
,查找分三步进行:
当在
C
(或C
的祖先类之一)中找到name
作为名称时覆盖描述符v
(即type(v)
提供方法__get__
和__set__
)•
x.name
的值是type(v).__get__(v, x, C)
的结果>否则,当
中的一个键时name
是x.__dict__
•
x.name
获取并返回x.__dict__['name']
处的值否则,
x.name
将查找委托给x
的类(根据用于C.name 的相同的两步查找
,就像详细)• 当找到描述符
v
时,属性查找再次是type(v).__get__(v, x, C)
• 当发现非描述符值
v
时,整体属性查找的结果只是v
当这些查找步骤没有找到属性时,Python 会引发 AttributeError
异常.但是,对于 x.name
的查找,当 C
定义或继承特殊方法 __getattr__
,Python 调用 C.__getattr__(x,'name')
而不是提升例外.然后由 __getattr__
返回合适的值或提高适当的异常,通常 AttributeError
.
步骤 1 和步骤 3 的第一部分是否相同?如果是,为什么同一个步骤会出现两次?
当
name
出现在C
(或C
的祖先之一)时,它们是否都发生 "classes) 作为覆盖描述符的名称v
"?
<小时><块引用>
__getattribute__(self, name)
在每次请求访问属性 x.y
时,Python 调用x.__getattribute__('y')
,必须获取和返回属性value 否则引发 AttributeError
.的正常语义属性访问(使用x.__dict__
、C.__slots__
、C
的类属性,x.__getattr__
) 都是由于 object.__getattribute__
.当类 C
覆盖 __getattribute__
时,它必须实现所有它想要提供的属性访问语义.大多数时候,最实现属性访问语义的便捷方法是委托(例如,调用 object.__getattribute__(self, ...)
作为一部分覆盖 __getattribute__
的操作).
步骤 1 和步骤 3 的第一部分是否相同?如果是,为什么同一个步骤出现两次?
第 1 步需要 __get__
和 __set__
(尽管实际上,__set__
或 __delete__
以及 __get__
会触发它).如果通过第 1 步或第 2 步未找到该属性,则无条件执行第 3 步.
当在 C(或 C 的祖先类之一)中找到名称作为覆盖描述符 v 的名称时",它们是否都会发生?
没有.覆盖描述符"触发第 1 步;另一种描述符或非描述符只会在第 3 步中考虑.(官方 Python 文档不使用术语覆盖描述符";它们指的是带有 __set__
或 的描述符>__delete__
作为数据描述符",并且如果数据描述符具有 __get__
,则 __get__
将优先于在实例字典中找到的对象.)
From Python in a Nutshell
Getting an attribute from an instance
When you use the syntax
x.name
to refer to an attribute of instancex
of classC
, the lookup proceeds in three steps:
When
name
is found inC
(or in one ofC
’s ancestor classes) as the name of an overriding descriptorv
(i.e.,type(v)
supplies methods__get__
and__set__
)• The value of
x.name
is the result oftype(v).__get__(v, x, C)
Otherwise, when
name
is a key inx.__dict__
•
x.name
fetches and returns the value atx.__dict__['name']
Otherwise,
x.name
delegates the lookup tox
’s class (according to the same two-step lookup used forC.name
, as just detailed)• When a descriptor
v
is found, the overall result of the attribute lookup is, again,type(v).__get__(v, x, C)
• When a nondescriptor value
v
is found, the overall result of the attribute lookup is justv
When these lookup steps do not find an attribute, Python raises an
AttributeError
exception. However, for lookups ofx.name
, whenC
defines or inherits the special method__getattr__
, Python callsC.__getattr__(x,'name')
rather than raising the exception. It’s then up to__getattr__
to either return a suitable value or raise the appropriate exception, normallyAttributeError
.
Are step 1 and the first part of step 3 the same? If yes, why does the same step appear twice?
Do they both happen "when
name
is found inC
(or in one ofC
’s ancestor classes) as the name of an overriding descriptorv
"?
__getattribute__(self, name)
At every request to access attribute
x.y
, Python callsx.__getattribute__('y')
, which must get and return the attribute value or else raiseAttributeError
. The normal semantics of attribute access (usingx.__dict__
,C.__slots__
,C
’s class attributes,x.__getattr__
) are all due toobject.__getattribute__
. When classC
overrides__getattribute__
, it must implement all of the attribute access semantics it wants to offer. Most often, the most convenient way to implement attribute access semantics is by delegating (e.g., callingobject.__getattribute__(self, ...)
as part of the operation of your override of__getattribute__
).
Are step 1 and the first part of step 3 the same? If yes, why the same step appear twice?
Step 1 requires both __get__
and __set__
(although actually, either __set__
or __delete__
along with __get__
would trigger it). Step 3 happens unconditionally if the attribute isn't found through steps 1 or 2.
Do they both happen "when name is found in C (or in one of C’s ancestor classes) as the name of an overriding descriptor v"?
No. An "overriding descriptor" triggers step 1; another kind of descriptor or a non-descriptor will only be considered in step 3. (The official Python docs don't use the term "overriding descriptor"; they refer to a descriptor with __set__
or __delete__
as a "data descriptor", and if a data descriptor has __get__
, the __get__
will take priority over an object found in an instance dict.)
这篇关于从实例中查找属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!