写入非数据描述符

2024-04-29 08:26:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在学习python中的描述符。我想写一个非数据描述符,但是当我调用classmethod时,将描述符作为其classmethod的类不会调用__get__特殊方法。这是我的例子(没有__set__):

class D(object):

    "The Descriptor"

    def __init__(self, x = 1395):
        self.x = x

    def __get__(self, instance, owner):
        print "getting", self.x
        return self.x


class C(object):

    d = D()

    def __init__(self, d):
        self.d = d

我这样称呼它:

>>> c = C(4)
>>> c.d
4

描述符类的__get__没有得到调用。但当我同时设置__set__时,描述符似乎被激活:

class D(object):

"The Descriptor"

    def __init__(self, x = 1395):
        self.x = x

    def __get__(self, instance, owner):
        print "getting", self.x
        return self.x

    def __set__(self, instance, value):
        print "setting", self.x
        self.x = value

class C(object):

    d = D()

    def __init__(self, d):
        self.d = d

现在我创建一个C实例:

>>> c=C(4)
setting 1395
>>> c.d
getting 4
4

并且__get__, __set__都存在。似乎我缺少了一些关于描述符的基本概念以及如何使用它们。有人能解释__get__, __set__的这种行为吗


Tags: theinstanceselfgetobjectinitdef描述符
1条回答
网友
1楼 · 发布于 2024-04-29 08:26:09

您成功地创建了一个适当的非数据描述符,但随后通过设置实例属性来屏蔽d属性

因为它是一个数据描述符,所以实例属性在本例中获胜。添加__set__方法时,将描述符转换为数据描述符,即使存在实例属性,也始终应用数据描述符(*)

Descriptor Howto开始:

The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing through the base classes of type(a) excluding metaclasses. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined.

If an object defines both __get__() and __set__(), it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are typically used for methods but other uses are possible).

Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.

如果删除实例属性d(从不在实例中设置或删除它),则会调用描述符对象:

>>> class D(object):
...     def __init__(self, x = 1395):
...         self.x = x
...     def __get__(self, instance, owner):
...         print "getting", self.x
...         return self.x
...
>>> class C(object):
...     d = D()
...
>>> c = C()
>>> c.d
getting 1395
1395

再次添加实例属性,描述符将被忽略,因为实例属性获胜:

>>> c.d = 42  # setting an instance attribute
>>> c.d
42
>>> del c.d   # deleting it again
>>> c.d
getting 1395
1395

另请参见Python数据模型参考中的Invoking Descriptors documentation


(*),前提是数据描述符实现了__get__钩子。通过instance.attribute_name访问这样的描述符将返回描述符对象,除非'attribute_name'中存在instance.__dict__

相关问题 更多 >