Na przykład w Javie @Override
adnotacja nie tylko zapewnia sprawdzanie zastąpienia w czasie kompilacji, ale także stanowi doskonały samodokumentujący się kod.
Szukam tylko dokumentacji (chociaż jeśli jest to wskaźnik do jakiegoś kratownicy jak pylint, to jest to bonus). Mogę gdzieś dodać komentarz lub dokument, ale jaki jest idiomatyczny sposób wskazania zastąpienia w Pythonie?
Odpowiedzi:
Na podstawie tego i odpowiedzi fwc: s utworzyłem pakiet instalowalny pip https://github.com/mkorpela/overrides
Od czasu do czasu kończę tutaj, patrząc na to pytanie. Zwykle dzieje się tak po (ponownym) zobaczeniu tego samego błędu w naszej bazie kodu: Ktoś zapomniał jakiegoś "interfejsu" implementującego klasę podczas zmiany nazwy metody w "interface" ..
Cóż, Python nie jest Javą, ale Python ma moc - i wyraźne jest lepsze niż ukryte - aw prawdziwym świecie są prawdziwe konkretne przypadki, w których to by mi pomogło.
Oto szkic dekoratora nadpisań. Spowoduje to sprawdzenie, czy klasa podana jako parametr ma taką samą nazwę metody (lub coś), co dekorowana metoda.
Jeśli możesz wymyślić lepsze rozwiązanie, opublikuj je tutaj!
Działa w następujący sposób:
a jeśli zrobisz błędną wersję, spowoduje to błąd asercji podczas ładowania klasy:
źródło
overrides
może skopiować łańcuch dokumentacyjny przesłoniętej metody, jeśli przesłaniająca metoda nie ma własnej.Oto implementacja, która nie wymaga podania nazwy interface_class.
źródło
Jeśli chcesz to tylko do celów dokumentacyjnych, możesz zdefiniować własny dekorator nadpisania:
To naprawdę nic innego jak przyjemne dla oka, chyba że utworzysz override (f) w taki sposób, że faktycznie sprawdza, czy nadpisanie.
Ale w takim razie to jest Python, po co pisać tak, jakby to była Java?
źródło
override
dekoratora.Python to nie Java. Oczywiście nie ma czegoś takiego jak sprawdzanie w czasie kompilacji.
Myślę, że komentarz w dokumentacji jest mnóstwo. Dzięki temu każdy użytkownik Twojej metody może wpisać
help(obj.method)
i zobaczyć, że metoda jest zastąpieniem.Możesz również jawnie rozszerzyć interfejs za pomocą
class Foo(Interface)
, co pozwoli użytkownikom na wpisywanie whelp(Interface.method)
celu zorientowania się, jakie funkcje ma zapewnić Twoja metoda.źródło
@Override
w Javie nie jest dokumentowanie - chodzi o wyłapanie błędu, gdy zamierzałeś nadpisać metodę, ale w końcu zdefiniowałeś nową (np. Ponieważ błędnie wpisałeś nazwę; w Javie może się to również zdarzyć, ponieważ użyłeś niewłaściwy podpis, ale nie jest to problem w Pythonie - ale błąd pisowni nadal istnieje).@Override
oprócz sprawdzania czasu kompilacji, jest dokumentacja.Improwizując na @mkorpela świetna odpowiedź , oto wersja z
bardziej precyzyjne kontrole, nazewnictwo i podniesione obiekty Error
Oto jak to wygląda w praktyce:
NotImplementedError
„ nie zaimplementowano w klasie bazowej ”skutkuje bardziej opisowym
NotImplementedError
błędempełny stos
NotImplementedError
„ oczekiwany zaimplementowany typ ”skutkuje bardziej opisowym
NotImplementedError
błędempełny stos
Wspaniałą rzeczą w odpowiedzi @mkorpela jest to, że sprawdzanie odbywa się podczas fazy inicjalizacji. Kontrola nie musi być przeprowadzana. Odnosząc się do poprzednich przykładów,
class B
nigdy nie jest inicjowany (B()
), aleNotImplementedError
nadal będzie podnosić. Oznacza to, żeoverrides
błędy są wykrywane wcześniej.źródło
overrides.py
. Nie jestem pewien, co jeszcze mogę znacznie poprawić, poza zmianą typów wyjątków zTypeError
naNotImplementedError
.types.MethodType
. To był dobry pomysł w twojej odpowiedzi.Jak powiedzieli inni, w przeciwieństwie do Javy, nie ma tagu @Overide, jednak powyżej możesz stworzyć własny za pomocą dekoratorów, jednak sugerowałbym użycie metody globalnej getattrib () zamiast używania wewnętrznego dyktowania, aby uzyskać coś takiego:
Jeśli chcesz, możesz złapać getattr () we własnej próbie catch, aby podnieść swój własny błąd, ale myślę, że metoda getattr jest lepsza w tym przypadku.
Również to przechwytuje wszystkie elementy związane z klasą, w tym metody klasowe i zmienne
źródło
Na podstawie @ wielką odpowiedź mkorpela za, pisałem podobny pakiet ( ipromise PyPI github ), który robi dużo więcej kontroli:
Załóżmy
A
dziedziczy odB
iC
,B
dziedziczy odC
.Moduł ipromise sprawdza, czy:
Jeśli
A.f
nadpisujeB.f
,B.f
musi istnieć iA
musi dziedziczyć zB
. (To jest czek z pakietu overrides).Nie masz wzorca,
A.f
który deklaruje, że zastępujeB.f
, a następnie deklaruje, że zastępujeC.f
.A
Powinien powiedzieć, że zastępuje from,C.f
ponieważB
może zdecydować o zaprzestaniu zastępowania tej metody, a to nie powinno skutkować aktualizacjami podrzędnymi.Nie masz wzorca,
A.f
który deklaruje przesłonięcieC.f
, aleB.f
nie deklaruje jego przesłonięcia.Nie masz wzorca,
A.f
który deklaruje, że zastępujeC.f
, aleB.f
deklaruje, że zastępuje niektóreD.f
.Posiada również różne funkcje do oznaczania i sprawdzania implementacji metody abstrakcyjnej.
źródło
Hear jest najprostszy i działa pod Jythonem z klasami Java:
źródło
Dekorator, który zrobiłem, nie tylko sprawdził, czy nazwa nadpisującego atrybutu w klasie jest nadrzędną klasy, w której znajduje się atrybut, bez konieczności określania nadrzędnej klasy, ten dekorator również sprawdził, czy nadpisywany atrybut musi być tego samego typu, co nadpisany atrybut. Metody klas są traktowane jak metody, a metody statyczne są traktowane jak funkcje. Ten dekorator działa dla wywołań, metod klas, metod statycznych i właściwości.
Kod źródłowy można znaleźć pod adresem : https://github.com/fireuser909/override
Ten dekorator działa tylko w przypadku klas, które są instancjami override. Do testów uruchom moduł override .__ init__.
źródło
W Pythonie 2.6+ i Pythonie 3.2+ możesz to zrobić ( właściwie to symuluj , Python nie obsługuje przeciążania funkcji, a klasa potomna automatycznie zastępuje metodę rodzica). Możemy do tego użyć dekoratorów. Ale najpierw zwróć uwagę, że Python
@decorators
i Java@Annotations
to zupełnie różne rzeczy. Poprzednia jest opakowaniem z konkretnym kodem, a późniejsza jest flagą kompilatora.W tym celu najpierw zrób
pip install multipledispatch
wynik:
Jedną rzeczą do zapamiętania jest to, że ponieważ Python nie ma bezpośredniego przeciążania funkcji, więc nawet jeśli klasa B nie dziedziczy z klasy A, ale potrzebuje wszystkich tych elementów,
foo
to również musisz użyć @Override (chociaż użycie aliasu „Przeciążenie” będzie wyglądać lepiej w takim przypadku)źródło