最近我阅读了关于Python描述符的官方 HOW-TO,实际上这篇文章来源于Raymond Hettinger很久以前写的一篇文章。但是,阅读了几遍之后,我仍然对其中的一些部分感到困惑。我将引用一些段落,接着是我的疑惑和问题。
如果实例的字典中有与数据描述符同名的条目,则数据描述符优先。如果实例的字典中有与非数据描述符同名的条目,则字典条目优先。
- 如果类的字典中有与数据/非数据描述符同名的条目,它们的优先级是什么?
对于对象,机制在
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)
) 是否仍会进行?直接从这个类或实例的字典中返回属性是否更简单? - 如果一个实例的字典中有与非数据描述符同名的条目,根据第一条引用中的优先规则,字典条目优先,此时转换是否仍会进行?还是只返回其字典中的值?
非数据描述符提供了一种简单的机制,用于变化通常将函数绑定到方法的模式。
- 为什么选择非数据描述符?因为函数/方法只能获取,而不能设置吗?
- 将函数绑定到方法的基本机制是什么?由于类字典将方法存储为函数,如果我们使用类和其实例分别调用相同的方法,底层函数如何知道其第一个参数是否应为self?
函数具有
__get__()
方法,因此当作为属性访问时,它们可以转换为方法。非数据描述符将obj.f(*args)
调用转换为f(obj, *args)
。调用klass.f(*args)
变成了f(*args)
。
- 非数据描述符如何将
obj.f(*args)
调用转换为f(obj, *args)
? - 非数据描述符如何将
klass.f(*args)
调用转换为f(*args)
? - 上述两种转换的基本机制是什么?为什么类和实例之间存在差异?
__get__()
方法在上述情况下扮演什么角色?