2015-12-29 9 views
5

Ho usato classi astratte in Python con ABCMeta. Quando scrivi un metodo astratto lo tagghi con il decoratore @abstractmethod. Una cosa che ho trovato strano (e diverso dalle altre lingue) è che quando la sottoclasse sovrascrive il metodo della superclasse, non viene fornito alcun decoratore come @override. Qualcuno sa quale potrebbe essere la logica dietro a questo?Perché no @override decorator in Python per facilitare la leggibilità del codice?

Ciò rende leggermente confuso chi legge il codice per stabilire rapidamente quali metodi eseguono l'override/implementano metodi astratti rispetto a metodi che esistono solo nella sottoclasse.

+2

Perché dovresti fornire un decoratore? Un decoratore ti offre l'opportunità di sostituire una funzione con un nuovo oggetto, ma non c'è bisogno di farlo in Python poiché cerca i nomi di una classe dinamicamente (ad esempio l'associazione tardiva), cercando tra le classi in Method Resolution Order (MRO). ogni volta. Pertanto, un metodo definito in una sottoclasse maschera un metodo in una classe genitore * naturalmente *. –

+0

E l'* obiettivo * dei metodi astratti è di assicurare che siano implementati; non è possibile creare un'istanza di una classe con metodi astratti ancora presenti. Non per loro essere distinti dagli altri metodi. –

+3

@MartijnPieters stesso comportamento (MRO) è applicato in Java. L'annotazione '@ Override' è semplicemente per aiutare lo sviluppatore a catturare errori di battitura durante la compilazione (se il nome del metodo è errato, ad esempio). – alfasin

risposta

3

Stai confondendo i decoratori Python con le annotazioni Java. Nonostante la sintassi simile, sono cose completamente diverse. Un'annotazione Java è un'istruzione per il compilatore. Ma un decoratore Python è un codice eseguibile che fa qualcosa di concreto: avvolge la funzione in un'altra funzione che può cambiare ciò che fa. Questo è il caso per abstractmethod tanto quanto qualsiasi altro decoratore; it fa qualcosa, ovvero dice all'ABC che c'è un metodo che ha bisogno di scavalcare.

+0

Mind you, if you really volevo l'annotazione per il tuo (discutibile) vantaggio di leggibilità, è banale ed economico farlo. 'def override (func): return func'. Fatto. Annotazione disponibile Efficacemente libero di applicarlo (al momento dell'importazione, si paga il costo insignificante di chiamare la funzione decoratore di noop), divertirsi. – ShadowRanger

+0

@ShadowRanger Non ho capito in che modo il tuo suggerimento implementa lo stesso comportamento di '@ Override' come previsto da Java. – alfasin

+0

@alfasin: non è così. È solo lì come uno spunto per il programmatore.Potrebbe essere fatto per fare cose più impressionanti (anche se ho il sospetto che richiederebbe metaclassi, dato che il decoratore da solo si applicherebbe prima che il metodo fosse collegato alla classe) come ispezionare ricorsivamente '__bases__' per verificare la presenza di un metodo nella catena ereditaria affermare qualcosa viene in realtà sovrascritto, ma se l'obiettivo principale è una sorta di "commento in lingua" per dire "questo sovrascrive qualcos'altro" in un modo standardizzato per il tuo codice base, questo è ciò. – ShadowRanger

4

Il problema con il tentativo di aggiungere @override è che al momento della definizione del metodo, il decoratore non ha modo di dire se il metodo sovrascrive effettivamente un altro metodo. Non ha accesso alle classi genitore (o alla classe corrente, che nemmeno esiste ancora!).

Se si desidera aggiungere @override, il decoratore @override non può effettivamente eseguire alcun controllo di sostituzione. Hai quindi due opzioni. O ci è senza controllo di override, nel qual caso @override non è migliore di un commento, o il costruttore type deve sapere in particolare su @override e controllarlo in fase di creazione della classe. Una funzionalità di comodità come @override non dovrebbe davvero complicare le parti principali dell'implementazione del sistema di tipi in questo modo. Inoltre, se accidentalmente inserisci @override su un non-metodo, il bug non verrà rilevato finché non proverai a chiamare la funzione decorata e otterrai uno strano Errore TypeError.

+0

Questo non è vero a partire da Python 3.6. –

+0

@NeilG: Sì, ora c'è '__set_name__', quindi potresti implementare un decoratore' @ override' con funzionalità effettive e solo poche strane interazioni (perché dovrebbe restituire un tipo personalizzato invece di una funzione ordinaria). – user2357112

+0

Lo farei contrassegnando i metodi utilizzando un decoratore e quindi eseguendo i controlli in '__init_subclass__', che possono essere forniti da una classe base. –

Problemi correlati