160

所以,我在 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 不起作用!

我错过了什么?

4

4 回答 4

319

您似乎在 python 2 中使用了经典的旧式类。为了使属性正常工作,您需要使用新式类(在 python 2 中,您必须继承自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
>>> 

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

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

还有一件事一开始并不完全容易发现,那就是顺序:必须首先定义吸气剂。如果你先定义 setter,你会得到 name 'x' is not defined错误。

于 2009-02-28T14:43:40.770 回答
88

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

@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

于 2013-06-30T23:20:33.407 回答
24

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

class testDec(object):
   ....

然后它应该工作。

于 2009-02-28T14:43:22.567 回答
12

如果有人从谷歌来这里,除了上面的答案,我想补充一点,在__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
于 2015-02-11T21:23:33.210 回答