简体   繁体   English

为什么 Python 中的 @foo.setter 对我不起作用?

[英]Why does @foo.setter in Python not work for me?

So, I'm playing with decorators in Python 2.6, and I'm having some trouble getting them to work.所以,我在 Python 2.6 中使用装饰器,但在让它们工作时遇到了一些麻烦。 Here is my class file:这是我的类文件:

class testDec:

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

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

What I thought this meant is to treat x like a property, but call these functions on get and set.我认为这意味着将x视为属性,但在 get 和 set 上调用这些函数。 So, I fired up IDLE and checked it:所以,我启动了 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

Clearly the first call works as expected, since I call the getter, and there is no default value, and it fails.显然,第一次调用按预期工作,因为我调用了 getter,并且没有默认值,并且失败了。 OK, good, I understand.好的,好的,我明白了。 However, the call to assign tx = 5 seems to create a new property x , and now the getter doesn't work!但是,分配tx = 5的调用似乎创建了一个新属性x ,现在 getter 不起作用!

What am I missing?我错过了什么?

You seem to be using classic old-style classes in python 2. In order for properties to work correctly you need to use new-style classes instead (in python 2 you must inherit from object ).您似乎在 python 2 中使用经典的旧式类。为了使属性正常工作,您需要改用新式类(在 python 2 中,您必须object继承)。 Just declare your class as MyClass(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

It works:有用:

>>> 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
>>> 

Another detail that might cause problems is that both methods need the same name for the property to work.另一个可能导致问题的细节是,两种方法都需要相同的名称才能使属性起作用。 If you define the setter with a different name like this it won't work :如果您使用这样的不同名称定义 setter,它将不起作用

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

And one more thing that is not completely easy to spot at first, is the order: The getter must be defined first .一开始不太容易发现的另一件事是顺序:必须首先定义getter 。 If you define the setter first, you get name 'x' is not defined error.如果您先定义 setter,则会出现name 'x' is not defined错误。

Just a note for other people who stumble here looking for this exception: both functions need to have the same name.只是给那些偶然在这里寻找此异常的其他人的注释:两个函数都需要具有相同的名称。 Naming the methods as follows will result in an exception:如下命名方法将导致异常:

@property
def x(self): pass

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

Instead give both methods the same name而是给这两种方法同名

@property
def x(self): pass

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

It is also important to note that the order of the declaration matters.同样重要的是要注意声明的顺序很重要。 The getter must be defined before the setter in the file or else you will get a NameError: name 'x' is not defined getter 必须在文件中的 setter 之前定义,否则您将收到NameError: name 'x' is not defined

You need to use new-style classes which you do by deriving your class from object:您需要使用通过从对象派生类来实现的新型类:

class testDec(object):
   ....

Then it should work.那么它应该工作。

In case anybody comes here from google, in addition to the above answers I would like to add that this needs careful attention when invoking the setter from the __init__ method of your class based on this answer Specifically:如果有人从谷歌来到这里,除了上面的答案,我想补充一点,在根据这个答案从你的类的__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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM