Zmieniam niektóre z moich klas z szerokiego użycia metod pobierających i ustawiających na bardziej Pythonowe użycie właściwości.
Ale teraz utknąłem, ponieważ niektóre z moich poprzednich metod pobierających lub ustawiających wywoływałyby odpowiednią metodę klasy bazowej, a następnie wykonywałyby coś innego. Ale jak można to osiągnąć za pomocą właściwości? Jak wywołać metodę pobierającą lub ustawiającą właściwość w klasie nadrzędnej?
Oczywiście samo wywołanie atrybutu daje nieskończoną rekurencję.
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
źródło
Foo.bar.fset(self, c)
setera odziedziczonego? Dlaczego nieFoo.bar.fset(c)
- bez „ja” - myślałem, że to zostało w domyśle przekazane?self
get sugeruje z łańcuchaFoo.bar.fset
?foo = Foo()
\,foo.bar(c)
nie zostanie przekazane self , ale bar () odbiera je z Pythona. Nie jestem ekspertem od Pythona, mniej więcej też początkującym. To tylko myśl.self
jest przekazywana niejawnie tylko wtedy, gdy metoda jest wywoływana na wystąpieniu klasy. Na przykład, jeśli mam klasęA
z metodąb(self, arg)
i tworzę instancjęc = A()
, wywołaniec.b(arg)
jest równoważneA.b(c, arg)
Super powinien załatwić sprawę:
return super().bar
W Pythonie 2.x musisz użyć bardziej szczegółowej składni:
return super(FooBar, self).bar
źródło
AttributeError
.Istnieje alternatywne użycie,
super
które nie wymaga jawnego odwoływania się do nazwy klasy bazowej.Klasa podstawowa 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
W B, uzyskując dostęp do metody pobierającej właściwość klasy nadrzędnej A:
Jak już odpowiedzieli inni, jest to:
Lub w Pythonie 3:
Zwraca to wartość zwracaną przez metodę pobierającą właściwości, a nie sam pobierający, ale wystarczy rozszerzyć funkcję pobierającą.
W B, uzyskując dostęp do setera właściwości klasy nadrzędnej A:
Najlepsza rekomendacja, jaką do tej pory widziałem, jest następująca:
Uważam, że ten jest lepszy:
W tym przykładzie obie opcje są równoważne, ale użycie super ma tę zaletę, że jest niezależne od klas bazowych
B
. GdybyB
dziedziczyć zC
klasy, która również rozszerza właściwość, nie musiałbyś aktualizowaćB
kodu.Pełny kod B rozszerzający właściwość 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)
Jedno zastrzeżenie:
Jeśli twoja właściwość nie ma metody ustawiającej, musisz zdefiniować zarówno metodę ustawiającą, jak i pobierającą,
B
nawet jeśli zmieniasz zachowanie tylko jednego z nich.źródło
super(B, self.__class__)
dokładnie działa zsuper(class, class)
? Gdzie to jest udokumentowane?próbować
@property def bar: return super(FooBar, self).bar
Chociaż nie jestem pewien, czy Python obsługuje wywoływanie właściwości klasy bazowej. Właściwość jest w rzeczywistości wywoływalnym obiektem, który jest konfigurowany za pomocą określonej funkcji, a następnie zastępuje tę nazwę w klasie. Może to łatwo oznaczać, że nie ma dostępnej super funkcji.
Zawsze możesz jednak zmienić składnię, aby użyć funkcji 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
źródło
Kilka drobnych ulepszeń w odpowiedzi Maxime :
__class__
aby uniknąć pisaniaB
. Zauważ, żeself.__class__
jest to typ środowiska wykonawczegoself
, ale__class__
bezself
jest nazwą otaczającej definicji klasy.super()
jest skrótem dlasuper(__class__, self)
.__set__
zamiastfset
. Ta ostatnia jest specyficzna dlaproperty
s, ale pierwsza dotyczy wszystkich obiektów podobnych do własności (deskryptorów).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)
źródło
Możesz użyć następującego szablonu:
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)
Uwaga! Wszystkie metody właściwości muszą zostać ponownie zdefiniowane razem. Jeśli nie chcesz przedefiniowywać wszystkich metod, użyj zamiast tego następującego szablonu:
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)
źródło
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()
(to znaczy chyba, że czegoś mi brakuje w twoim wyjaśnieniu)
źródło