我试图围绕描述符的概念,我最近没有成功。这个article描述符如何真正帮助,同时它也让我感到困惑。我在这里挣扎着这个例子
为什么m.x
调用def __get__(self, obj, objtype):
class RevealAccess(object):
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print('Retrieving', self.name)
return self.val
def __set__(self, obj, val):
print('Updating', self.name)
self.val = val
>>> class MyClass(object):
... x = RevealAccess(10, 'var "x"')
... y = 5
...
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
我相信我正在努力解决这个问题的原因是因为我对文章
中的以下陈述感到困惑调用的细节取决于obj是对象还是对象 类。对于物体,机器在
object.__getattribute__()
它将b.x
转换为type(b).__dict__['x'].__get__(b, type(b))
。 实现通过提供数据的优先级链来工作 描述符优先于实例变量,实例变量 优先于非数据描述符,并为其分配最低优先级 如果提供了__getattr__()
我不确定作者在这里的对象或类是什么意思。对象是否意味着类的实例?我知道当我们在instance.var
python内部执行instance.__dict__["var"]
时,如果找不到,那么class.__dict__["var"]
。def __get__(self, obj, objtype):
在那个概念之后我有点失去它。任何人都可以解释一下这个例子是如何工作的。如何使用m.x
调用myObjects.Select(obj => obj.total).Distinct().ToList()
定义。如果有人能清除这一点,我将非常感激。
答案 0 :(得分:2)
是的,通过 object ,作者意味着一个实例,而不是一个类。区别在于描述符的存在;描述符是在类上定义的,因此当直接在类上访问该描述符时,在您访问该类实例上的描述符时会遵循不同的路径。
在您的示例中,m
是一个实例。该实例本身没有属性m
('x' in m.__dict__
是False
)。 Python还会查看type(m)
以解析该属性,type(m)
此处为MyClass
。 'x' in MyClass.__dict__
为True
,MyClass.__dict__['x'].__get__
存在,因此Python现在知道该对象是描述符。
因此,因为没有m.__dict__['x']
,但 是type(m).__dict__['x'].__get__
,所以使用m
和type(m)
作为参数调用该方法,导致type(m).__dict__['x'].__get__(m, type(m))
。
如果'x' in MyClass.__dict__
为真但MyClass.__dict__['x'].__get__
不存在(因此对象不是描述符对象),则{{1}将直接返回。
如果您尝试将MyClass.__dict__['x']
属性添加到实例,情况会变得更有趣。在这种情况下,如果存在x
或MyClass.__dict__['x'].__set__
,则使描述符成为 data 描述符。数据描述符总是在平局的情况下获胜。所以如果 MyClass.__dict__['x'].__delete__
和至少有一个 MyClass.__dict__['x'].__get__
或MyClass.__dict__['x'].__set__
存在,那么{{{{{ 1}}也存在。 Python甚至不会寻找它。
但是,如果类上的描述符对象上没有MyClass.__dict__['x'].__delete__
或m.__dict__['x']
方法,那么__set__
将获胜并返回。在这种情况下,描述符是一个常规的非数据描述符,它会丢失到实例属性。
最后但并非最不重要的是,如果__delete__
为false(类上没有对象),则返回m.__dict__['x']
。描述符协议仅应用于在类上找到的对象,而不应用于实例上的属性。
答案 1 :(得分:1)
对象是否意味着类的实例?
是
如何使用
def __get__(self, obj, objtype):
调用m.x
定义。
由于您引用的文档的内容是:
对于对象,机器位于
object.__getattribute__()
,将b.x
转换为type(b).__dict__['x'].__get__(b, type(b))
。
object.__getattribute__
是一种机制,可以实现m.x
之类的操作。所以,明确地说:
m.x
type(m).__dict__['x'].__get__(m, type(m))
MyClass.__dict__['x'].__get__(m, MyClass)
RevealAccess(10, 'var "x"').__get__(m, MyClass)
所以最后一行调用了__get__
类的RevealAccess
方法。