python - 为什么 instance.attribute = value 可以工作,而 __set__ 方法没有在属性中实现?

标签 python properties descriptor

我正在通过属性来研究描述符协议(protocol),我正在这样写我自己的属性:

class my_property(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
           raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel)

class test_my_property(object):
    def __init__(self, value):
        self._val = value

    @my_property
    def val(self):
        return self._val

     @val.setter
     def val(self, value):
         self._val = value

def main():
     c = test_my_property(5)
     print c.val
     c.val = 10
     print c.val
     print type(c).__dict__['val'].__set__

然后我得到:

5
10
AttributeError: 'my_property' object has no attribute '__set__'

我的问题是,既然“__set__”没有定义,那么“c.val = 10”如何工作? 如果"__set__"是my_property从object继承的,那么,为什么会报AttributeError呢?

最佳答案

__set__ 不是继承自对象。获取和设置 val 属性之所以有效,是因为在访问对象的属性时,首先会检查实例,然后检查类。由于您设置了实例属性 val,它会使用它。如果您正在查看一个没有描述符的简单示例,我认为这一点尤其明显,

>>> class Foo(object):
...     val = 5
... 
>>> f = Foo()
>>> f.val  # f doesn't have val so fallback on Foo
5
>>> f.val = 10
>>> f.val  # f now has val so use it
10
>>> del f.val  # oops what now
>>> f.val  # class again
5

上面的例子和你的唯一区别是你的类 val 是(当你完成时)一个属性。

综上所述,您通常不希望将您的属性命名为与将保存其内容的实例属性相同的名称。通常的公式是这样的,

class Foo(object):
    def __init__(self, value):
        self._val = value

    @property
    def val(self):
        return self._val

关于python - 为什么 instance.attribute = value 可以工作,而 __set__ 方法没有在属性中实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30091273/

相关文章:

python - 无法在 macbook air 中创建 conda 环境(Resolvepackagenotfound)

c# - 覆盖属性的 XML 注释

c# - C# 属性总是有备份字段 "behind the scene"吗?

Python类型检查系统

c - 当描述符重叠时,C11 数组初始化的行为是什么?

python - 在 Django 中使用 path() 找不到 404

python - Pandas - 选择列表中的无效条目

python - 如何将 JSON 文件读入 Dataframe?

javascript - 为什么这个 JavaScript 属性返回空字符串,而 JavaScript 函数运行正常?

python - 在 Python 中使用描述符协议(protocol)时如何获取属性名称?