【问题标题】:Unexpected name lookup on properties对属性进行意外名称查找
【发布时间】:2016-08-05 02:03:17
【问题描述】:

考虑这段代码:

class Foo(object):
    @property
    def func(self):
        self.__dict__['func'] = 1 
        return 2

f = Foo()
print f.func
print f.func

它打印2 2。为什么第二次不打印1

【问题讨论】:

  • 你为什么希望它第二次打印 1?
  • f.__dict__['func'] 给出 1

标签: python


【解决方案1】:

因为f.func 其中fFoo 的一个实例,而funcproperty 描述符触发器

Foo.func.__get__(f)

(见Descriptor protocol)。

self.__dict__['func'] = 1 修改f 实例的底层字典。它不会更改 Foo 类的 func 属性。

Foo.func 优先于 f.func= 1,新创建的实例变量),因为

如果一个实例的字典有一个与数据同名的条目 描述符,数据描述符优先。

(从上面的链接复制)。


如果你想替换属性,你必须给Foo.func 赋值:

class Foo(object):
    @property
    def func(self):
        Foo.func = 1 
        return 2

f = Foo()
print(f.func) # 2
print(f.func) # 1

【讨论】:

  • +1 链接。 “如果一个实例的字典有一个与数据描述符同名的条目,则数据描述符优先”几乎可以解释事情。
【解决方案2】:

根据this post,属性查找过程是这样的:

  1. 如果 attrname 是 objectname 的特殊(即 Python 提供的)属性,则返回它。
  2. 检查 objectname.__class__.__dict__ 的 attrname。如果存在并且是数据描述符,则返回描述符结果。搜索所有 相同情况下 objectname.__class__ 的基数。
  3. 检查 objectname.__dict__ 的 attrname,如果找到则返回。如果 objectname 是一个类,也搜索它的基类。如果它是一个类和一个 描述符存在于它或其基中,返回描述符结果。
  4. 检查 objectname.__class__.__dict__ 的 attrname。如果存在且是非数据描述符,则返回描述符结果。如果它 存在,并且不是描述符,只需返回它。如果它存在并且是 数据描述符,我们不应该在这里,因为我们会返回 在第 2 点。搜索 objectname.__class__ 的所有基以查找相同的案例。
  5. 引发 AttributeError。

属性装饰器将键值对添加到对象的类'__dict__,因此它在步骤 2 中被找到。添加到对象的 __dict__ 的名称在步骤 3 中检查。因此在两者之间,属性取优先级。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2013-11-14
    • 2014-02-12
    • 2010-11-24
    • 1970-01-01
    • 2013-03-16
    相关资源
    最近更新 更多