具有描述符和属性对象的属性查找优先级

时间:2018-08-19 21:27:38

标签: python python-3.x function properties

我正在研究描述符,以及它们是如何在属性和函数背后使用的机制。我对在实现描述符与使用属性时如何查找属性感到困惑。

sudo bypass rm -rfv /Volumes/*/.Trashes

输出为:

try:
  sudo bypass rm -rfv /Volumes/*/.Trashes
except 'rm: fts_read: No such file or directory':
  sudo bypass rm -rfv /Volumes/*/.Trashes

这很有意义,因为属性查找顺序为:

  1. 数据描述符
  2. class NonDataDescriptor(object): def __get__(self, instance, owner): return 'non-data descriptor' class DataDescriptor(object): def __get__(self, instance, owner): return 'data descriptor' def __set__(self, instance, value): pass class MyClass(object): descriptor_one = NonDataDescriptor() descriptor_two = DataDescriptor() def __init__(self): self.descriptor_one = 'hello' self.descriptor_two = 'goodbye' mc = MyClass() print(mc.descriptor_one) print(mc.descriptor_two) 中的
  3. 实例属性
  4. 非数据描述符

由于属性实际上只是实现描述符,所以我想知道为什么似乎不遵循这种顺序的属性查找。请参阅以下内容:

hello
data descriptor

输出为:

instance_obj.__dict__

我一直期待着,因为属性对象class MyClass(object): def __init__(self, fname, lname): self._fname = fname self._lname = lname @property def fullname(self): return '{} {}'.format(self._fname, self._lname) mc = MyClass('Bob', 'John') print(mc.fullname) mc.__dict__['fullname'] = 'testing' print(mc.__dict__) print(mc.fullname) 实际上只是一个非数据描述符,因此实例属性Bob John {'_fname': 'Bob', '_lname': 'John', 'fullname': 'testing'} Bob John 将具有优先权。

此外,函数也被实现为非数据描述符,并且遵循此属性查找顺序:

fullname

输出为:

fullname

谁能解释为什么属性对象与众不同?

2 个答案:

答案 0 :(得分:1)

诀窍在于此处的descriptor protocol

  
      
  • 如果实例的字典中具有与数据描述符同名的条目,则数据描述符优先。
  •   
  • 如果实例的词典中具有与非数据描述符同名的条目,则该词典条目优先。
  •   
@property
def fullname(self):
    return '{} {}'.format(self._fname, self._lname)

这是一个数据描述符,因为装饰器返回的property对象始终定义__set__,即使您未定义setter(然后__set__也会引发{{ 1}},请参阅code here

AttributeError

因此,数据描述符优先。

由于其他示例的行为已达到您的预期,因此足以完成您的理解。

答案 1 :(得分:0)

@spectras已经回答了您的问题。我只想提供其他方法来检查描述符:

In [517]: import inspect

In [518]: inspect.isdatadescriptor(type(mc).__dict__['fullname'])
Out[518]: True

In [519]: inspect.isdatadescriptor(MyClass.__dict__['fullname'])
Out[519]: True

因此,即使您未定义setter,@ property始终是数据描述符。在这种情况下,属性分配将引发AttributeError: can't set attribute