Estou mudando algumas classes minhas de um uso extensivo de getters e setters para um uso mais pythônico de propriedades.
Mas agora estou preso porque alguns dos meus getters ou setters anteriores chamariam o método correspondente da classe base e, em seguida, executariam outra coisa. Mas como isso pode ser feito com propriedades? Como chamar a propriedade getter ou setter na classe pai?
É claro que apenas chamar o próprio atributo dá recursão 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
fonte
Foo.bar.fset(self, c)
um setter herdado? Por que nãoFoo.bar.fset(c)
- sem o "eu" - pensei que isso fosse implicitamente passado?self
get implica na cadeiaFoo.bar.fset
?foo = Foo()
\,foo.bar(c)
não haverá auto- aprovação, mas bar () o receberá do Python. Não sou nenhum especialista em Python, mais ou menos um iniciante também. É apenas um pensamento.self
só é passado implicitamente quando o método é chamado em uma instância de uma classe. Por exemplo, se eu tenho uma classeA
com um métodob(self, arg)
e crio uma instânciac = A()
, chamarc.b(arg)
é equivalente aA.b(c, arg)
Super deve resolver:
return super().bar
No Python 2.x, você precisa usar uma sintaxe mais detalhada:
return super(FooBar, self).bar
fonte
AttributeError
.Há uma alternativa de uso
super
que não requer referência explícita ao nome da classe base.Classe 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
Em B, acessando o getter de propriedade da classe pai A:
Como outros já responderam, é:
Ou em Python 3:
Isso retorna o valor retornado pelo getter da propriedade, não o getter em si, mas é suficiente para estender o getter.
Em B, acessando o configurador de propriedades da classe pai A:
A melhor recomendação que vi até agora é a seguinte:
Eu acredito que este é melhor:
Neste exemplo, ambas as opções são equivalentes, mas usar super tem a vantagem de ser independente das classes base de
B
. SeB
fosse herdar de umaC
classe que também estende a propriedade, você não teria que atualizarB
o código.Código completo de B estendendo a propriedade 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)
Uma ressalva:
A menos que sua propriedade não tenha um setter, você deve definir o setter e o getter,
B
mesmo que apenas altere o comportamento de um deles.fonte
super(B, self.__class__)
funciona exatamente comsuper(class, class)
? Onde está documentado?tentar
@property def bar: return super(FooBar, self).bar
Embora eu não tenha certeza se python suporta a chamada da propriedade da classe base. Uma propriedade é na verdade um objeto chamável que é configurado com a função especificada e então substitui aquele nome na classe. Isso pode significar facilmente que não há nenhuma função super disponível.
Você sempre pode mudar sua sintaxe para usar a função 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
fonte
Algumas pequenas melhorias na resposta de Maxime :
__class__
para evitar a escritaB
. Observe queself.__class__
é o tipo de tempo de execução deself
, mas__class__
semself
é o nome da definição de classe envolvente.super()
é uma abreviação desuper(__class__, self)
.__set__
vez defset
. O último é específico paraproperty
s, mas o primeiro se aplica a todos os objetos semelhantes a propriedades (descritores).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)
fonte
Você pode usar o seguinte modelo:
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 os métodos de propriedade devem ser redefinidos juntos. Se não quiser redefinir todos os métodos, use o seguinte modelo:
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)
fonte
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()
(isto é, a menos que eu esteja faltando alguma coisa em sua explicação)
fonte