2015-12-29 6 views
5

Ich habe mit ABCMeta in Python abstrakte Klassen im Einsatz. Wenn Sie eine abstrakte Methode schreiben, markieren Sie sie mit dem Decorator @abstractmethod. Eine Sache, die ich seltsam fand (und im Gegensatz zu anderen Sprachen) ist, dass, wenn die Unterklasse die Superklassenmethode überschreibt, kein Dekorator wie @override bereitgestellt wird. Weiß jemand, was die Logik dahinter sein könnte?Warum kein @override-Dekorator in Python, um die Lesbarkeit des Codes zu verbessern?

Dies macht es für jemanden, der den Code liest, leicht verwirrend, schnell festzustellen, welche Methoden abstrakte Methoden überschreiben/implementieren im Vergleich zu Methoden, die nur in der Unterklasse existieren.

+2

Warum würden Sie brauchen einen Dekorateur zur Verfügung zu stellen? Ein Decorator gibt Ihnen die Möglichkeit, eine Funktion durch ein neues Objekt zu ersetzen, aber in Python ist dies nicht notwendig, da dynamisch nach Namen in einer Klasse gesucht wird (zB späte Bindung) und die Klassen in Method Resolution Order (MRO) durchsucht werden. jedes Mal. Daher maskiert eine in einer Unterklasse definierte Methode eine Methode in einer Elternklasse * natürlich *. –

+0

Und das * Ziel * der abstrakten Methoden ist sicherzustellen, dass sie implementiert werden; Sie können keine Instanz einer Klasse erstellen, für die noch abstrakte Methoden vorhanden sind. Nicht für sie, um sich von anderen Methoden zu unterscheiden. –

+3

@MartijnPieters gleichen Verhaltens (MRO) wird in Java angewendet. Die Annotation '@ Override' dient lediglich dazu, dem Entwickler während der Kompilierungszeit Tippfehler zuzufügen (wenn der Methodenname zum Beispiel falsch geschrieben wurde). – alfasin

Antwort

3

Du verwechselst Python Dekorateure mit Java-Annotationen. Trotz der ähnlichen Syntax sind sie völlig unterschiedliche Dinge. Eine Java-Anmerkung ist eine Anweisung an den Compiler. Aber ein Python-Decorator ist ein ausführbarer Code, der etwas Konkretes tut: Er verpackt die Funktion in eine andere Funktion, die ihre Funktion ändern kann. Dies gilt für das abstrakte Verfahren genauso wie für jeden anderen Dekorateur; es macht etwas, nämlich sagen Sie dem ABC, dass es eine Methode gibt, die überschrieben werden muss.

+0

Wohlgemerkt, wenn Sie wirklich wollte die Annotation für Ihren eigenen (zweifelhaften) Lesbarkeitsvorteil, es ist trivial und billig, es zu tun. 'def override (func): return func'. Erledigt. Anmerkung verfügbar Effektiv frei, um es anzuwenden (zum Zeitpunkt des Imports, zahlen Sie die trivialen Kosten für den Aufruf der Noop Decorator-Funktion), viel Spaß. – ShadowRanger

+0

@ShadowRanger Ich konnte nicht verstehen, wie Ihr Vorschlag das gleiche '@ Override'-Verhalten implementiert wie Java. – alfasin

+0

@alfasin: Es tut es nicht. Es ist nur als Hinweis auf den Programmierer da.Es könnte gemacht werden, um eindrucksvollere Sachen zu machen (obwohl ich vermute, dass es Metaklassen erfordern würde, da der Dekorator alleine angewendet würde, bevor die Methode an die Klasse angehängt wurde) wie rekursives Prüfen von "__bases__", um das Vorhandensein einer Methode in der Vererbungskette zu verifizieren etwas zu behaupten, wird tatsächlich außer Kraft gesetzt, aber wenn das primäre Ziel eine Art "sprachlicher Kommentar" ist, der besagt, dass "dies etwas anderes außer Kraft setzt", so geschieht dies in einer standardisierten Weise für Ihre Code-Basis. – ShadowRanger

4

Das Problem mit dem Versuch, @override hinzuzufügen, ist, dass der Dekorator zur Zeit der Methodendefinition keine Möglichkeit hat festzustellen, ob die Methode tatsächlich eine andere Methode überschreibt oder nicht. Es hat keinen Zugriff auf die Elternklassen (oder die aktuelle Klasse, die noch gar nicht existiert!).

Wenn Sie @override hinzufügen möchten, kann der @override Decorator tatsächlich keine Überschreibungsprüfung durchführen. Sie haben dann zwei Möglichkeiten. Entweder gibt ist keine Überprüfung überschreiben, in diesem Fall @override ist nicht besser als ein Kommentar, oder der type Konstruktor muss speziell über @override wissen und überprüfen Sie es bei der Erstellung der Klasse. Ein Komfortfeature wie @override sollte eigentlich Kernteile der Typsystemimplementierung nicht komplizieren müssen. Wenn Sie versehentlich @override auf eine Nicht-Methode setzen, wird der Fehler unbemerkt bleiben, bis Sie versuchen, die verzierte Funktion aufzurufen und einen seltsamen TypeError zu erhalten.

+0

Dies gilt nicht für Python 3.6. –

+0

@NeilG: Ja, es gibt '__set_name__' jetzt, so dass Sie einen' @ override' Dekorator mit der tatsächlichen Funktionalität und nur ein paar seltsamen Interaktionen implementieren könnten (weil es einen benutzerdefinierten Typ anstelle einer gewöhnlichen Funktion zurückgeben müsste). – user2357112

+0

Ich würde es tun, indem Sie die Methoden mit einem Dekorator markieren, und dann Ihre Prüfungen in '__init_subclass__', die von einer Basisklasse zur Verfügung gestellt werden können. –

Verwandte Themen