Pregunta

Por lo tanto, estoy jugando con decoradores en Python 2.6, y estoy teniendo algunos problemas para conseguir que funcionen. Aquí está mi archivo de clase:

class testDec:

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

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

Lo que pensé que esto significaba es tratar x como una propiedad, pero llamar a estas funciones en obtener y definir. Por lo tanto, me dispararon hasta ralentí y comprobado:

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

Es evidente que la primera llamada funciona como se esperaba, ya que llamo el comprador, y no hay ningún valor por defecto, y se produce un error. OK, bueno, lo entiendo. Sin embargo, la llamada para asignar t.x = 5 parece crear un nuevo x propiedad, y ahora el comprador no funciona!

¿Qué me falta?

¿Fue útil?

Solución

Estas usando clases clásicas de estilo antiguo en Python 2. Con el fin de propiedades para que funcione correctamente es necesario utilizar clases de nuevo estilo lugar (en Python 2 que debe heredar de object ). Sólo declarar una clase como 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

Funciona:

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

Otro detalle que podría causar problemas es que ambos métodos tienen el mismo nombre para la propiedad para trabajar. Si se define la incubadora con un nombre diferente como esto no va a funcionar

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

Y una cosa más que no es del todo fácil de detectar en un primer momento, es el orden: El captador debe definir primero . Si se define la incubadora primera, se obtiene el error name 'x' is not defined.

Otros consejos

Sólo una nota para otras personas que tropiezan aquí en busca de esta excepción: ambas funciones deben tener el mismo nombre. Naming los métodos como sigue resultará en una excepción:

@property
def x(self): pass

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

En lugar dar ambos métodos el mismo nombre

@property
def x(self): pass

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

También es importante tener en cuenta que el orden de los asuntos de declaración. El comprador debe definirse antes de la incubadora en el archivo o de lo contrario obtendrá un NameError: name 'x' is not defined

Es necesario utilizar las clases de nuevo estilo la que se hace mediante la derivación de la clase de objeto:

class testDec(object):
   ....

A continuación, debería funcionar.

En caso de que alguien viene aquí desde Google, además de las respuestas anteriores me gustaría añadir que esto necesita mucha atención cuando se invoca el colocador del método __init__ de la clase basado en esta respuesta Específicamente:

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top