最近我读了official HOW-TO about Python descriptors,它实际上源自Raymond Hettinger很久以前写的an essay。但在阅读了几次之后,我仍然对它的某些部分感到困惑。我会引用一些段落,然后是我的困惑和问题。
如果实例的字典具有与数据描述符同名的条目,则数据描述符优先。如果实例的字典具有与非数据描述符同名的条目,则字典条目优先。
对于对象,机器位于
object.__getattribute__()
,将b.x
转换为type(b).__dict__['x'].__get__(b, type(b))
。该实现通过优先级链工作,该优先级链使数据描述符优先于实例变量,实例变量优先于非数据描述符,并且如果提供则将最低优先级分配给__getattr__()
。对于课程,机制位于
type.__getattribute__()
,将B.x
转换为B.__dict__['x'].__get__(None, B)
。
b.x
)和类(B.x
)访问的属性之间的差异。但是,这是我的困惑:
b.x
转换为type(b).__dict__['x'].__get__(b, type(b))
和B.x
转换为B.__dict__['x'].__get__(None, B)
)仍然会继续?返回此类或实例的 dict 中的属性直接更简单? 非数据描述符提供了一种简单的机制,可以将通常的绑定函数模式转换为方法。
函数具有
__get__()
方法,以便在作为属性访问时可以将它们转换为方法。非数据描述符将obj.f(*args)
调用转换为f(obj, *args)
。调用klass.f(*args)
变为f(* args)。
obj.f(*args)
调用转换为f(obj, *args)
? klass.f(*args)
调用转换为f(*args)
?__get__()
方法的作用是什么? 答案 0 :(得分:2)
这和班级一样吗?如果类的字典具有与数据/非数据描述符同名的条目,那么它的优先级是什么?
不,如果在超类和子类中都定义了属性,则完全忽略超类值。
如果类或实例的属性不是描述符,那么转换(即将b.x转换为
type(b).__dict__['x'].__get__(b, type(b))
而将B.x转换为B.__dict__['x'].__get__(None, B))
是否仍会继续?
不,它直接返回从类__dict__
获得的对象。或者等效地,是的,如果你假装所有对象默认都有一个忽略其参数并返回__get__()
的方法self
。
如果实例的字典有一个与非数据描述符同名的条目,根据第一个引用中的优先级规则,字典条目优先,此时转换是否还会继续?或者只返回其字典中的值?
您引用的段落中可能没有明确的内容(可能是在其他地方写下来的)是b.x
决定返回b.__dict__['x']
时,在任何情况下都不会调用__get__
。语法__get__
或b.x
决定返回位于类 dict中的对象时,会调用B.x
。
是否选择了非数据描述符,因为只能获取函数/方法,但无法设置?
是的:它们是Python中“旧式”类模型的概括,即使B.f = 42
是生活在B类中的函数对象,也可以说f
。使用不相关的对象覆盖函数对象。另一方面,数据描述符具有不同的逻辑,以支持property
。
将函数绑定到方法的基本机制是什么?由于类字典将方法存储为函数,如果我们分别使用类及其实例调用相同的方法,底层函数如何判断其第一个参数是否应该是self?
要理解这一点,您需要考虑“方法对象”。语法b.f(*args)
等同于(b.f)(*args)
,这是两个步骤。第一步调用f.__get__(b)
;这将返回一个存储b和f的方法对象。第二步调用方法对象,然后通过添加b作为额外参数来调用原始f。这是B.f
不会发生的事情,因为B.f
,即f.__get__(None, B)
,只是f(在Python 3中)。这是在函数对象上设计特殊方法__get__
的方式。