2009-11-11 13 views
12

Podklasyję obiekt, aby nadpisać metodę, do której chcę dodać jakąś funkcjonalność. Nie chcę całkowicie zastąpić go lub dodać inaczej nazwanej metody, ale pozostać kompatybilnym z metodą superklasy przez dodanie opcjonalnego argumentu do metody. Czy można pracować z *args i **kwargs przechodzić przez wszystkie argumenty do nadklasy i nadal dodawać opcjonalny argument z domyślnym? intuicyjnie wymyślił następujące ale to nie działa:dodanie argumentu ze słowem kluczowym do przesłoniętej metody i użycie ** kwarg

class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, argopt2="foo", **kwargs): 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 

Oczywiście mogę zmusić go do pracy, kiedy jawnie dodać wszystkie argumenty metody nadklasy:

class B(A): 
    def foo(self, arg1, arg2, argopt1="foo", argopt2="bar"): 
     print argopt2 
     A.foo(self, arg1, arg2, argopt1=argopt1) 

Jaki jest właściwy sposób, aby to zrobić, czy muszę wiedzieć i jawnie podać wszystkie przesłonięte argumenty metod?

Odpowiedz

10
class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, **kwargs): 
     argopt2 = kwargs.get('argopt2', default_for_argopt2) 
     # remove the extra arg so the base class doesn't complain. 
     del kwargs['argopt2'] 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 
+5

Możesz użyć pop zamiast get + del. – iny

+0

Zawsze zapominam o dict.pop! –

+3

Twój przykład kończy się niepowodzeniem z 'KeyError', gdy' argopt2' nie jest przekazywane. Użycie 'kwargs.pop ('argopt2', default_for_argopt2)' jest najprostszym sposobem, aby to naprawić. –

1

Kiedy rozszerzasz i metody nadrzędne, zawsze trzeba zdecydować, czy przy użyciu super() jest dobrym pomysłem, a this page jest dobry do tego.

mam nie mówiąc, że super() należy unikać, jak autor artykułu mogą być: Mówię, że super() ma kilka bardzo ważnych Wymagania wstępne, których należy przestrzegać, jeśli nie chcą super() wrócić i ugryźć Cię.

+0

http://fuhm.org/super-harmful/ to dobra lektura. Dziękuję, Teddy – unutbu

6

Jaki jest właściwy sposób to zrobić, nie muszę wiedzieć i jednoznacznie określić wszystkie argumentów metod przesłoniętych?

Jeśli chcesz objąć wszystkie przypadki (a nie tylko polegać na rozmówcy, aby zawsze robić rzeczy na swój sposób, na przykład, zawsze zadzwonić tylko przeszedł według nazwy dodatkowym argumentem, nigdy o położeniu), które mają kodować (lub dynamicznie odkrywać) dużą wiedzę na temat sygnatury metody, którą nadpisujesz - trudno się dziwić: dziedziczenie jest silną formą sprzężenia, a nadpisywanie metod jest jednym ze sposobów, w jakie sprzężenie się przedstawia.

Ty mógłby dynamicznie odkryć nadklasy męska metoda argumenty za pośrednictwem inspect.getargspec, w celu upewnienia się, to nazwać poprawnie ... ale technika ta introspekcja może się trudne, jeśli dwa klas starają się zrobić dokładnie to samo (kiedy już wiesz, że twoja metoda superklasy akceptuje , możesz zrobić niewiele więcej, niż tylko przekazać wszystkie istotne argumenty w górę i mieć nadzieję, że kciukiem, że łańcuch górnych metod ostatecznie czyści porządek przed wywołaniem wersji, która nie jest tak tolerancyjna) .

Takie ceny mogą być warte zapłacenia, gdy projektujesz opakowanie, które ma być dynamicznie stosowane do kalendarzy z szeroką gamą podpisów (zwłaszcza, że ​​w ustawieniu dekoratora można zapłacić olbrzymi koszt introspekcji tylko raz za funkcję, którą dekorujesz, nie za każdym razem, gdy wywoływana jest otoka). Wydaje się mało prawdopodobne, aby była to technika warta uwagi w przypadku takim jak twój, gdzie lepiej wiesz, co tworzysz podklasowo (podklasowanie jest silnym sprzężeniem: robienie tego na ślepo zdecydowanie nie jest wskazane!), Więc możesz równie dobrze przeliterować argumenty jawnie.

Tak, jeśli kod nadklasy ulega drastycznej zmianie (np., zmieniając sygnatury metod), będziesz musiał również dokonać przeglądu podklasy - to jest (część) ceny spadku. Ogólna cena jest na tyle wysoka, że ​​nowy język programowania Go jest całkowicie bez niego - , który wymusza na użytkowniku zastosowanie znakomitej porady do prefer composition over inheritance. W Pythonie całkowita abstynencja od dziedziczenia byłaby po prostu niepraktyczna, ale korzystanie z niej w sposób umiarkowany i umiarkowany (i zaakceptowanie ceny, którą zapłacisz za łączenie, kiedy to robisz) pozostaje wskazane.

+0

+1 za ostrzeżenia dotyczące zmian w podpisie. Ale myślę, że jest wyjątek: można zmienić sygnaturę konstruktora. Problem opisany w pytaniu dotyczy również konstruktora. –

Powiązane problemy