2011-08-11 20 views
33

lo tanto, estoy tratando de averiguar la mejor manera (más elegante con la menor cantidad de código) para permitir anulando las funciones específicas de una propiedad (por ejemplo, sólo el captador, sólo el organismo, etc.) en python. Soy fanático de la siguiente manera de hacer propiedades, debido al hecho de que todos sus métodos están encapsulados en el mismo bloque de código sangrado (es más fácil ver dónde se detienen las funciones relacionadas con una propiedad y las funciones relacionadas con la junto comenzar):propiedades imperiosas de pitón

@apply 
def foo(): 
    """A foobar""" 
    def fget(self): 
     return self._foo 
    def fset(self, val): 
     self._foo = val 
    return property(**locals()) 

Sin embargo, si quiero heredar de una clase que define las propiedades de esta manera, y luego, por ejemplo, reemplazar la función setter foo, parece complicado. He hecho un poco de búsqueda y la mayoría de las respuestas que he encontrado han sido definir funciones separadas en la clase base (por ejemplo getFoo y setFoo), crear explícitamente una definición de propiedad de ellos (por ejemplo foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo())), y después se anulan getFoo, setFoo y delFoo según sea necesario.

No me gusta esta solución porque significa que tengo que definir lambas para cada propiedad individual, y luego escribir cada llamada a función (cuando antes podría haber hecho property(**locals())). Tampoco obtengo la encapsulación que tenía originalmente.

Idealmente, lo que le gustaría ser capaz de hacerlo sería algo como esto:

class A(object): 
    def __init__(self): 
     self.foo = 8 
    @apply 
    def foo(): 
     """A foobar""" 
     def fget(self): 
      return self._foo 
     def fset(self, val): 
      self._foo = val 
     return property(**locals()) 

class ATimesTwo(A): 
    @some_decorator 
    def foo(): 
     def fset(self, val): 
      self._foo = val * 2 
     return something 

Y entonces la salida sería algo como:

>>> a = A() 
>>> a.foo 
8 
>>> b = ATimesTwo() 
>>> b.foo 
16 

Básicamente, ATimesTwo hereda el captador función desde A, pero anula la función de configuración. ¿Alguien sabe de una manera de hacer esto (de una manera que se ve similar al ejemplo anterior)? ¿Qué función tendría el some_decorator y qué debería devolver la función foo?

+0

No veo ninguna manera de hacer lo que quiera con un decorador solo porque no tiene acceso al objeto, solo a la función. Supongo que tienes un decorador que devuelve una función que funciona más cuando se llama por primera vez al método, pero luego has sobrescrito el foo inicial. también, como supongo que sabes, no estás realmente usando el lenguaje en el estilo previsto ... pero podrías encontrar una manera de hacerlo con una metaclase. –

+0

Esta pregunta similar puede ser útil: http://stackoverflow.com/questions/237432/python-properties-and-inheritance – stderr

Respuesta

39

Estoy seguro de que ya ha escuchado esto antes, pero apply ha quedado obsoleto durante ocho años, desde Python 2.3. No lo uses Su uso de locals() también es contrario al Zen de Python: explícito es mejor que implícito. Si realmente te gusta el aumento de la sangría, no hay necesidad de crear un objeto de usar y tirar, acaba de hacer

if True: 
    @property 
    def foo(self): 
     return self._foo 
    @foo.setter 
    def foo(self, val): 
     self._foo = val 

Lo que no abusan locals, utilice apply, requerirá la creación de un objeto extra, o necesita una línea después con foo = foo() haciendo que sea más difícil ver el final del bloque. Funciona igual de bien para su forma anticuada de usar property - simplemente haga foo = property(fget, fset) de forma normal.

Si desea anular una propiedad en una subclase arbitraria, se puede utilizar un recipe like this.

Si la subclase sabe donde se define la propiedad, acaba de hacer:

class ATimesTwo(A): 
    @A.foo.setter 
    def foo(self, val): 
     self._foo = val * 2 
+1

"' if True: '" ?? –

37

El pitón docs en el property decorador sugerir el siguiente lenguaje:

class C(object): 
    def __init__(self): 
     self._x = None 
    @property 
    def x(self): 
     return self._x 
    @x.setter 
    def x(self, value): 
     self._x = value 
    @x.deleter 
    def x(self): 
     del self._x 

Y luego subclases pueden anular un solo setter/getter como este:

class C2(C): 
    @C.x.getter 
    def x(self): 
     return self._x * -1 

Este es un pequeño verrugosa porque anulando varios métodos parece que tenga que hacer algo como:

class C3(C): 
    @C.x.getter 
    def x(self): 
     return self._x * -1 
    # C3 now has an x property with a modified getter 
    # so modify its setter rather than C.x's setter. 
    @x.setter 
    def x(self, value): 
     self._x = value * 2 

Por supuesto, en el punto que se está anulando captador, organismo, y Deleter probablemente puede redefinir la propiedad de C3.