web-dev-qa-db-fra.com

Pourquoi @ foo.setter dans Python ne fonctionne-t-il pas pour moi?

Donc, je joue avec des décorateurs dans Python 2.6, et j'ai du mal à les faire fonctionner. Voici mon dossier de classe:

class testDec:

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

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

Ce que je pensais que cela voulait dire, c'est traiter x comme une propriété, mais appeler ces fonctions sur get et set. Alors, j'ai lancé IDLE et vérifié:

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

Clairement, le premier appel fonctionne comme prévu, puisque j’appelle le getter, qu’il n’ya pas de valeur par défaut et qu’il échoue. OK, bon, je comprends. Cependant, l'appel à assigner t.x = 5 semble créer une nouvelle propriété x, et maintenant le getter ne fonctionne plus!

Qu'est-ce que je rate?

151
TR.

Vous semblez utiliser classes classiques de style ancien dans python 2. Pour que propriétés fonctionne correctement, vous devez utiliser - nouvelles classes de style à la place (dans python 2, vous devez hériter de object ). Déclarez simplement votre classe en tant que 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

Ça marche:

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

Un autre détail qui pourrait poser problème est que les deux méthodes ont besoin du même nom pour que la propriété fonctionne. Si vous définissez le setter avec un nom différent, cela ne fonctionnera pas :

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

Et une dernière chose qui n’est pas tout à fait facile à repérer au début est l’ordre: Le getter doit être défini d’abord . Si vous définissez d'abord le séparateur, vous obtenez name 'x' is not defined Erreur.

294
nosklo

Juste un mot pour les autres personnes qui trébuchent ici à la recherche de cette exception: les deux fonctions doivent avoir le même nom. Nommer les méthodes comme suit donnera lieu à une exception:

@property
def x(self): pass

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

Donnez plutôt le même nom aux deux méthodes

@property
def x(self): pass

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

Il est également important de noter que l'ordre de la déclaration est important. Le getter doit être défini avant le setter dans le fichier sinon vous obtiendrez un NameError: name 'x' is not defined

74
Andrew Hows

Vous devez utiliser les nouvelles classes de style en dérivant votre classe à partir d'objet:

class testDec(object):
   ....

Alors ça devrait marcher.

23
MrTopf

Au cas où quelqu'un viendrait ici de Google, en plus des réponses ci-dessus, je voudrais ajouter que cela nécessite une attention particulière lors de l'appel du setter depuis le __init__ Méthode de votre classe basée sur cette réponse Plus précisément:

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