web-dev-qa-db-ja.com

Pythonで@ foo.setterが機能しないのはなぜですか?

だから、私は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

ゲッターを呼び出すので、最初の呼び出しは期待どおりに動作します。デフォルト値はなく、失敗します。わかりました、わかりました。ただし、t.x = 5を割り当てる呼び出しは、新しいプロパティxを作成するようで、ゲッターは機能しません!

私は何が欠けていますか?

151
TR.

classic old-style classes in python 2.を使用しているようです。 properties が正しく機能するためには、使用する必要があります- 新しいスタイルのクラス 代わりに(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
>>> 

問題を引き起こす可能性のあるもう1つの詳細は、両方のメソッドがプロパティが機能するために同じ名前を必要とすることです。 このような別の名前でセッターを定義すると、動作しません

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

最初に見つけるのが完全に簡単ではないもう1つのことは、順序です。ゲッターを最初に定義する必要があります。最初にセッターを定義すると、name 'x' is not definedエラー。

294
nosklo

ここでこの例外を探している他の人々への注意:両方の関数は同じ名前を持つ必要があります。次のようにメソッドに名前を付けると、例外が発生します。

@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

宣言の順序が重要であることに注意することも重要です。ゲッターはファイル内のセッターの前に定義する必要があります。そうしないと、NameError: name 'x' is not defined

74
Andrew Hows

オブジェクトからクラスを派生させることで行う新しいスタイルのクラスを使用する必要があります。

class testDec(object):
   ....

その後、動作するはずです。

23
MrTopf

誰かがグーグルからここに来た場合、上記の答えに加えて、__init__に基づくクラスのメソッド この回答 具体的には:

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