2015-12-29 7 views
5

Używam klas abstrakcyjnych w Pythonie z ABCMeta. Gdy piszesz abstrakcyjną metodę, oznaczasz ją dekoratorem @abstractmethod. Jedną z rzeczy, którą odkryłem jako nieparzystą (i w odróżnieniu od innych języków) jest to, że gdy podklasa zastępuje metodę nadklasy, nie ma żadnego dekoratora, takiego jak @override. Czy ktoś wie, jaka może być logika?Dlaczego nie ma dekoratora @override w Pythonie, aby ułatwić odczyt kodu?

To sprawia, że ​​trochę zagmatwane dla kogoś czytającego kod, aby szybko ustalić, które metody zastępują/implementują metody abstrakcyjne w porównaniu do metod, które istnieją tylko w podklasie.

+2

Dlaczego trzeba dostarczyć dekoratora? Dekorator daje możliwość zastąpienia funkcji nowym obiektem, ale nie ma takiej potrzeby w Pythonie, ponieważ dynamicznie wyszukuje nazwy w klasie (np. Późne wiązanie), przeszukując klasy w metodzie MRO (Method Resolution Order) za każdym razem. Zatem metoda zdefiniowana w podklasie maskuje metodę w klasie nadrzędnej * naturalnie *. –

+0

A * celem * abstrakcyjnych metod jest zapewnienie ich wdrożenia; nie można utworzyć instancji klasy, która wciąż zawiera abstrakcyjne metody. Nie należy ich odróżniać od innych metod. –

+3

@ MartijnPieters samo zachowanie (MRO) jest stosowane w Javie. Adnotacja '@ Override' służy jedynie do pomocy programistom przy pisaniu listów podczas kompilacji (jeśli na przykład nazwa metody zawiera literówkę). – alfasin

Odpowiedz

3

Mylicie dekoratorów Pythona z adnotacjami Java. Pomimo podobnej składni, są to zupełnie różne rzeczy. Adnotacja Java jest instrukcją dla kompilatora. Ale dekorator Python to kod wykonywalny, który robi coś konkretnego: zawija funkcję w innej funkcji, która może zmienić to, co robi. Tak jest w przypadku metody abstrakcyjnej tak samo, jak w przypadku każdego innego dekoratora; to robi coś, a mianowicie powiedzieć ABC, że istnieje metoda, która wymaga nadpisania.

+0

Pamiętaj, jeśli naprawdę chciałem adnotacji dla twojej własnej (wątpliwej) korzyści z czytelności, jest to trywialne i tanie. 'def override (func): return func'. Gotowe. Adnotacja dostępna. Skutecznie za darmo do zastosowania (w czasie importu, płacisz trywialny koszt wywoływania funkcji dekoratora noop), baw się dobrze. – ShadowRanger

+0

@ShadowRanger Nie mogłem zrozumieć, w jaki sposób twoja sugestia implementuje takie samo zachowanie @ Override, jakie zapewnia Java. – alfasin

+0

@alfasin: Nie ma. Jest to tylko wskazówka dla programisty.Można by zrobić więcej rzeczy imponujących (choć podejrzewam, że wymagałoby to metaclasses, ponieważ sam dekorator zastosowałby się zanim metoda została dołączona do klasy), jak inspekcja '__bases__' rekursywnie w celu sprawdzenia obecności metody w łańcuchu dziedziczenia twierdzenie, że coś jest faktycznie przesłonięte, ale jeśli głównym celem jest "komentarz w języku", aby powiedzieć "to przesłania coś innego" w znormalizowany sposób dla bazy kodu, robi to. – ShadowRanger

4

Problem z próbą dodania @override polega na tym, że w czasie definiowania metody dekorator nie może stwierdzić, czy metoda faktycznie nadpisuje inną metodę. Nie ma dostępu do klas nadrzędnych (lub bieżącej klasy, która jeszcze nie istnieje!).

Jeśli chcesz dodać @override, dekorator @override nie może w rzeczywistości wykonać żadnego sprawdzenia nadpisania. Masz wtedy dwie opcje. Albo jest bez sprawdzania nadpisywania, w którym to przypadku @override nie jest lepsza niż komentarz, lub konstruktor type musi dokładnie wiedzieć o @override i sprawdzić go w czasie tworzenia klasy. Funkcja wygody, taka jak @override, nie powinna tak naprawdę komplikować głównych części takiej implementacji systemu typu. Ponadto, jeśli przypadkowo umieścisz @override na non-method, błąd pozostanie niewykryty, dopóki nie spróbujesz wywołać funkcji dekorowanej i uzyskać dziwny TypeError.

+0

To nie jest prawda od Pythona 3.6. –

+0

@NeilG: Tak, teraz jest '__set_name__', więc możesz zaimplementować dekorator' @ override' z aktualną funkcjonalnością i tylko kilkoma dziwnymi interakcjami (ponieważ musiałby zwrócić niestandardowy typ zamiast zwykłej funkcji). – user2357112

+0

Zrobiłbym to, zaznaczając metody za pomocą dekoratora, a następnie wykonując kontrole w '__init_subclass__', które mogą być dostarczone przez klasę podstawową. –

Powiązane problemy