Estoy cambiando algunas clases mías de un uso extensivo de captadores y definidores a un uso más pitónico de propiedades.
Pero ahora estoy atascado porque algunos de mis getters o setters anteriores llamaban al método correspondiente de la clase base y luego realizaban otra cosa. Pero, ¿cómo se puede lograr esto con propiedades? ¿Cómo llamar al getter o setter de propiedad en la clase principal?
Por supuesto, simplemente llamar al atributo en sí da una recursividad infinita.
class Foo(object):
@property
def bar(self):
return 5
@bar.setter
def bar(self, a):
print a
class FooBar(Foo):
@property
def bar(self):
# return the same value
# as in the base class
return self.bar # --> recursion!
@bar.setter
def bar(self, c):
# perform the same action
# as in the base class
self.bar = c # --> recursion!
# then do something else
print 'something else'
fb = FooBar()
fb.bar = 7
Foo.bar.fset(self, c)
a un setter heredado? ¿Por qué noFoo.bar.fset(c)
, sin el "yo", pensé que esto se pasa implícitamente?self
get de la cadenaFoo.bar.fset
?foo = Foo()
\,foo.bar(c)
no se pasa self , pero bar () lo recibe de Python. No soy un experto en Python, más o menos un principiante también. Es solo un pensamiento.self
solo se pasa implícitamente cuando se llama al método en una instancia de una clase. Por ejemplo, si tengo una claseA
con un métodob(self, arg)
y creo una instanciac = A()
, la llamadac.b(arg)
es equivalente aA.b(c, arg)
Super debería hacer el truco:
return super().bar
En Python 2.x, debe usar la sintaxis más detallada:
return super(FooBar, self).bar
fuente
AttributeError
.Existe un uso alternativo
super
que no requiere hacer referencia explícita al nombre de la clase base.Clase base A:
class A(object): def __init__(self): self._prop = None @property def prop(self): return self._prop @prop.setter def prop(self, value): self._prop = value class B(A): # we want to extend prop here pass
En B, accediendo al getter de propiedad de la clase padre A:
Como otros ya han respondido, es:
O en Python 3:
Esto devuelve el valor devuelto por el captador de la propiedad, no el captador en sí, pero es suficiente para extender el captador.
En B, accediendo al establecedor de propiedades de la clase padre A:
La mejor recomendación que he visto hasta ahora es la siguiente:
Creo que este es mejor:
En este ejemplo, ambas opciones son equivalentes pero usar super tiene la ventaja de ser independiente de las clases base de
B
. SiB
heredara de unaC
clase que también extendiera la propiedad, no tendría que actualizarB
el código.Código completo de B que extiende la propiedad de A:
class B(A): @property def prop(self): value = super(B, self).prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(B, self.__class__).prop.fset(self, value)
Una advertencia:
A menos que su propiedad no tenga un setter, debe definir tanto el setter como el getter
B
incluso si solo cambia el comportamiento de uno de ellos.fuente
super(B, self.__class__)
funciona exactamente consuper(class, class)
? ¿Dónde está documentado?tratar
@property def bar: return super(FooBar, self).bar
Aunque no estoy seguro de si Python admite llamar a la propiedad de la clase base. Una propiedad es en realidad un objeto invocable que se configura con la función especificada y luego reemplaza ese nombre en la clase. Esto podría significar fácilmente que no hay una superfunción disponible.
Sin embargo, siempre puede cambiar su sintaxis para usar la función property ():
class Foo(object): def _getbar(self): return 5 def _setbar(self, a): print a bar = property(_getbar, _setbar) class FooBar(Foo): def _getbar(self): # return the same value # as in the base class return super(FooBar, self)._getbar() def bar(self, c): super(FooBar, self)._setbar(c) print "Something else" bar = property(_getbar, _setbar) fb = FooBar() fb.bar = 7
fuente
Algunas pequeñas mejoras a la respuesta de Maxime :
__class__
para evitar escribirB
. Tenga en cuenta queself.__class__
es el tipo de tiempo de ejecución deself
, pero__class__
sinself
el nombre de la definición de clase adjunta.super()
es una abreviatura desuper(__class__, self)
.__set__
lugar defset
. El último es específico deproperty
s, pero el primero se aplica a todos los objetos similares a propiedades (descriptores).class B(A): @property def prop(self): value = super().prop # do something with / modify value here return value @prop.setter def prop(self, value): # do something with / modify value here super(__class__, self.__class__).prop.__set__(self, value)
fuente
Puede utilizar la siguiente plantilla:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @property def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
¡Nota! Todos los métodos de propiedad deben redefinirse juntos. Si no desea redefinir todos los métodos, utilice la siguiente plantilla en su lugar:
class Parent(): def __init__(self, value): self.__prop1 = value #getter @property def prop1(self): return self.__prop1 #setter @prop1.setter def prop1(self, value): self.__prop1 = value #deleter @prop1.deleter def prop1(self): del self.__prop1 class Child(Parent): #getter @Parent.prop1.getter def prop1(self): return super(Child, Child).prop1.__get__(self) #setter @Parent.prop1.setter def prop1(self, value): super(Child, Child).prop1.__set__(self, value) #deleter @Parent.prop1.deleter def prop1(self): super(Child, Child).prop1.__delete__(self)
fuente
class Base(object): def method(self): print "Base method was called" class Derived(Base): def method(self): super(Derived,self).method() print "Derived method was called" d = Derived() d.method()
(es decir, a menos que me falte algo en tu explicación)
fuente