【问题标题】:Why does @foo.setter in Python not work for me?为什么 Python 中的 @foo.setter 对我不起作用?
【发布时间】:2010-10-10 12:43:21
【问题描述】:

所以,我在 Python 2.6 中使用装饰器,但在让它们工作时遇到了一些麻烦。这是我的类文件:

class testDec:

    @property
    def x(self): 
        print 'called getter'
        return self._x

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value

我认为这意味着将 x 视为一个属性,但在 get 和 set 上调用这些函数。所以,我启动了 IDLE 并检查了它:

>>> from testDec import testDec
from testDec import testDec
>>> t = testDec()
t = testDec()
>>> t.x
t.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "testDec.py", line 18, in x
    return self._x
AttributeError: testDec instance has no attribute '_x'
>>> t.x = 5
t.x = 5
>>> t.x
t.x
5

显然,第一次调用按预期工作,因为我调用了 getter,并且没有默认值,它失败了。好的,好的,我明白了。但是,调用assign t.x = 5 似乎创建了一个新属性x,现在getter 不起作用!

我错过了什么?

【问题讨论】:

  • 请用大写字母命名类。您可以对变量和模块文件使用小写。

标签: python decorator new-style-class


【解决方案1】:

您需要使用通过从对象派生类来实现的新型类:

class testDec(object):
   ....

那么它应该可以工作了。

【讨论】:

  • 上面的一切都准备好了。在 python 2.7.x 中,这对我来说是正确启动类中的属性所必需的。
【解决方案2】:

您似乎在 python 2 中使用了classic old-style classes。为了使properties 正常工作,您需要改用new-style classes(在python 2 中您必须使用inherit from object)。只需将您的班级声明为MyClass(object)

class testDec(object):

    @property
    def x(self): 
        print 'called getter'
        return self._x

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value

有效:

>>> k = testDec()
>>> k.x
called getter
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/devel/class_test.py", line 6, in x
    return self._x
AttributeError: 'testDec' object has no attribute '_x'
>>> k.x = 5
called setter
>>> k.x
called getter
5
>>> 

另一个可能导致问题的细节是两个方法需要相同的名称才能使属性起作用。 如果你用这样的不同名称定义 setter,它将不起作用

@x.setter
def x_setter(self, value):
    ...

另外一件一开始并不完全容易发现的事情是顺序:getter 必须首先定义。如果你先定义 setter,你会得到name 'x' is not defined 错误。

【讨论】:

  • 在 Python3 中不再需要 - “经典”类与 setter 一样好:-)
  • 它在 python 3 中有效,因为每个类都是新式类,不再有“经典”类。
  • 如果在这种情况下没有正确处理装饰器,我认为应该收到警告/错误。
【解决方案3】:

对于偶然发现此异常的其他人,请注意:两个函数必须具有相同的名称。如下命名方法会导致异常:

@property
def x(self): pass

@x.setter
def x_setter(self, value): pass

取而代之的是给这两个方法同名

@property
def x(self): pass

@x.setter
def x(self, value): pass

同样重要的是要注意声明的顺序。 getter 必须在文件中的 setter 之前定义,否则你会得到一个NameError: name 'x' is not defined

【讨论】:

  • 这可能会成为“新”的最佳答案,越来越多的人使用 Python 3...
  • 这个答案很棒。我认为要完整,如果您可以说顺序很重要,那就太好了,也就是说,getter 必须在代码中的 setter 之前。否则,您将收到 NameError: name 'x' is not defined 异常。
  • 谢谢。我只是浪费了一天中最好的时间。我从来没有想过这些方法必须被称为相同的东西。真是令人沮丧的小成语!
  • 要了解此答案背后的“原因”,请阅读此处的权威文档:docs.python.org/2/library/functions.html#property 特别注意“完全等效”部分。
【解决方案4】:

如果有人从谷歌来到这里,除了上面的答案,我想补充一点,在基于this answer 从你的类的__init__ 方法调用setter 时需要特别注意 具体来说:

class testDec(object):                                                                                                                                            

    def __init__(self, value):
        print 'We are in __init__'
        self.x = value # Will call the setter. Note just x here
        #self._x = value # Will not call the setter

    @property
    def x(self):
        print 'called getter'
        return self._x # Note the _x here

    @x.setter
    def x(self, value): 
        print 'called setter'
        self._x = value # Note the _x here

t = testDec(17)
print t.x 

Output:
We are in __init__
called setter
called getter
17

【讨论】:

  • 不仅来自 __init__ 方法,还来自类中的任何其他方法。
  • 如果您使用的是 Python3,那么您应该使用 print("xxxxx") 而不是 print "xxxxx"
猜你喜欢
  • 2010-10-08
  • 2016-02-27
  • 2019-01-13
  • 2015-09-07
  • 1970-01-01
  • 2023-04-03
  • 2020-12-16
相关资源
最近更新 更多