【问题标题】:python data and non-data descriptorspython数据和非数据描述符
【发布时间】:2012-10-12 00:17:01
【问题描述】:

根据Python's documentation

定义了__set__()__get__() 的数据描述符始终覆盖实例字典中的重新定义。

我理解这句话没有问题,但是有人可以为我澄清为什么会有这样的规则吗?毕竟,如果我想覆盖实例字典中的属性,我已经需要明确地inst.__dict__["attr"] = val)这样做,因为天真的inst.attr = val 会调用描述符的__set__ 方法,这(通常)不会覆盖实例字典中的属性。

编辑:为了清楚起见,我了解正在发生的事情,我的问题是为什么要制定这样的规则。

【问题讨论】:

    标签: python descriptor python-descriptors


    【解决方案1】:

    覆盖适用于属于__dict__的描述符。

    Python 将始终查找type(instance).__dict__[attributename].__get__(instance, type(instance)),并且不会使用instance.__dict__ 来搜索实例覆盖。

    这是一个使用人为设计的 Descriptor 类和属性(这是一个带有 __get____set__ 的描述符的示例:

    >>> class Descriptor(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...     def __get__(self, instance, cls):
    ...         print 'Getting %s, with instance %r, class %r' % (self.name, instance, cls)
    ... 
    >>> class Foo(object):
    ...     _spam = 'eggs'
    ...     @property
    ...     def spam(self):
    ...         return self._spam
    ...     @spam.setter
    ...     def spam(self, val):
    ...         self._spam = val
    ... 
    >>> Foo().spam
    'eggs'
    >>> foo = Foo()
    >>> foo.__dict__['spam'] = Descriptor('Override')
    >>> foo.spam
    'eggs'
    

    如您所见,即使我在实例__dict__ 中添加了一个spam 条目,它也被完全忽略,并且仍然使用Foo.spam 属性。 Python 忽略了实例__dict__,因为spam 属性同时定义了__get____set__

    如果您使用没有定义__set__的描述符,则覆盖有效(但不会调用__get__

    >>> class Foo(object):
    ...     desc = Descriptor('Class-stored descriptor')
    ... 
    >>> Foo.desc
    Getting Class-stored descriptor, with instance None, class <class '__main__.Foo'>
    >>> Foo().desc
    Getting Class-stored descriptor, with instance <__main__.Foo object at 0x1018df510>, class <class '__main__.Foo'>
    >>> foo = Foo()
    >>> foo.__dict__['desc'] = Descriptor('Instance-stored descriptor')
    >>> foo.desc
    <__main__.Descriptor object at 0x1018df1d0>
    

    【讨论】:

    • 这里是 CPython 2.7.3 的实现:getset。顺序是数据描述符、实例属性、非数据描述符,最后(仅获取)一个类属性。
    • 是的,我已经理解了那部分。我的问题更多是关于这样一个规则的基本原理;即,我永远不会“意外”覆盖实例中的类的数据描述符(即,我需要访问 dict),那么如果我真的想这样做,为什么要禁止我这样做呢?跨度>
    • @antony:这是一个有意识的决定,更详细的解释见PEP 252;但它的缺点是你不能覆盖 __class__ 实例 __dict__ 中的静态属性。
    • 仍然不相信(再次,我的观点是 Python 的方法通常是“同意的成年人”之一,摆弄 __dict__ 应该会让你得到你想要的——如果我想在尊重描述符协议的同时动态更新属性我可以使用setattr)但我想我不应该在这里争论语言设计。
    • 相反,实现的方法在我看来效率较低:您现在必须检查数据描述符的类型字典,然后检查非描述符属性的实例字典,然后再次检查类型字典对于非数据描述符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2015-06-05
    • 1970-01-01
    相关资源
    最近更新 更多