Frage

In Java, zum Beispiel der @Override Annotation bietet nicht nur kompilieren Zeit eine Vorrangprüfung, sondern für hervorragenden Selbst dokumentiert Code macht.

Ich bin nur für die Dokumentation (obwohl, wenn es bis zu einem gewissen checker wie Pylint ein Indikator ist, dass ein Bonus ist). Ich kann einen Kommentar hinzufügen oder irgendwo Docstring, aber was ist der idiomatische Weg eine Überschreibung in Python, um anzuzeigen?

War es hilfreich?

Lösung

UPDATE (2015.05.23): Auf dieser Basis und fwc: s Antwort habe ich ein pip installierbaren Paket https: // Github .com / mkorpela / überschreibt

Von Zeit zu Zeit habe ich am Ende hier oben auf diese Frage suchen. Vor allem die gleichen Fehler in unserer Code-Basis zu sehen, dies geschieht nach (wieder): Jemand eine „Schnittstelle“ implementierende Klasse vergessen hat, während eine Methode in der „Schnittstelle“ ..

Umbenennen

Nun Python ist nicht Java aber Python hat die Macht - und explizite ist besser als implizit -. Und es gibt reale konkrete Fälle in der realen Welt, wo dieses Ding mir geholfen hätte

So, hier ist eine Skizze von Überschreibungen Dekorateur. Diese prüft, ob die Klasse als Parameter angegeben hat die gleiche Methode (oder etwas) Namen wie das Verfahren eingerichtet werden.

Wenn Sie eine bessere Lösung denken kann es bitte hier posten!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

Es funktioniert wie folgt:

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

und wenn Sie eine fehlerhafte Version tun wird es eine Assertion Fehler beim Laden von Klassen erhöhen:

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!

Andere Tipps

Hier ist eine Implementierung, die keine Spezifikation des interface_class Namen erforderlich macht.

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method

Wenn Sie diese Dokumentation zu wollen dient nur, können Sie Ihre eigene Überschreibung Dekorateur definieren:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

Das ist wirklich nichts anderes als Augenschmaus, es sei denn, Sie überschreiben (f) in einer solchen Art und Weise erstellen, die tatsächlich überprüft für eine Überschreibung ist.

Aber dann, dieser Python ist, warum es schreiben, wie es Java war?

Python ist nicht Java. Es gibt natürlich so etwas wirklich nicht als Übersetzungszeit zu überprüfen.

Ich glaube, ein Kommentar in der docstring viel ist. Dies ermöglicht es jedem Benutzer Ihrer Methode help(obj.method) zu geben und sehen, dass das Verfahren eine Überschreibung ist.

Sie können auch explizit eine Schnittstelle mit class Foo(Interface) erweitern, die Benutzern erlaubt, help(Interface.method) zu geben eine Vorstellung über die Funktionalität Ihrer Methode zur Verfügung zu stellen ist, bekommen soll.

Wie andere haben im Gegensatz zu Java sagt, dass es nicht @Overide Tag ist jedoch über Sie Ihre eigenen mit Dekorateure erstellen können jedoch würde ich vorschlagen, die getattrib () verwenden globale Methode anstelle der Verwendung des internen dict, so dass Sie so etwas wie die folgenden bekommen:

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

Wenn Sie Sie wollte konnte getattr () in Ihrem eigenen try catch heben Sie Ihre eigenen Fehler fangen, aber ich denke getattr Methode in diesem Fall besser ist.

Auch fangen diese alle zu einer Klasse gebunden Elemente einschließlich Klassenmethoden und vairables

Improvisieren auf @mkorpela große Antwort , hier ist eine Version mit

präzisere Kontrollen, Benennen und erhöhte Fehlerobjekte

def overrides(interface_class):
    """
    Function override annotation.
    Corollary to @abc.abstractmethod where the override is not of an
    abstractmethod.
    Modified from answer https://stackoverflow.com/a/8313042/471376
    """
    def confirm_override(method):
        if method.__name__ not in dir(interface_class):
            raise NotImplementedError('function "%s" is an @override but that'
                                      ' function is not implemented in base'
                                      ' class %s'
                                      % (method.__name__,
                                         interface_class)
                                      )

        def func():
            pass

        attr = getattr(interface_class, method.__name__)
        if type(attr) is not type(func):
            raise NotImplementedError('function "%s" is an @override'
                                      ' but that is implemented as type %s'
                                      ' in base class %s, expected implemented'
                                      ' type %s'
                                      % (method.__name__,
                                         type(attr),
                                         interface_class,
                                         type(func))
                                      )
        return method
    return confirm_override


Hier ist, wie es in der Praxis aussieht:

NotImplementedError " nicht in Basisklasse implementiert "

class A(object):
    # ERROR: `a` is not a implemented!
    pass

class B(A):
    @overrides(A)
    def a(self):
        pass

Ergebnisse in aussagekräftigeren NotImplementedError Fehler

function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

Fullstack

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 110, in confirm_override
    interface_class)
NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'>


NotImplementedError " erwartet umgesetzt Typ "

class A(object):
    # ERROR: `a` is not a function!
    a = ''

class B(A):
    @overrides(A)
    def a(self):
        pass

Ergebnisse in aussagekräftigeren NotImplementedError Fehler

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>

Fullstack

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 125, in confirm_override
    type(func))
NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>




Die große Sache über @mkorpela Antwort ist die Überprüfung während einiger Initialisierungsphase passiert. Die Prüfung muss nicht „run“ sein. Unter Bezugnahme auf die vorhergehenden Beispiele wird class B nie (B()) initialisiert noch die NotImplementedError noch erhöhen. Das bedeutet, overrides Fehler früher aufgefangen werden.

Basierend auf @ mkorpela die große Antwort, ich habe ein ähnliches Paket geschrieben ( iPromise pypi github ), die viele mehr Kontrollen tut:

Nehmen wir an A erbt von B und C und B erbt von C. iPromise prüft, dass

  • Wenn A.f B.f überschreibt, muss B.f vorhanden sind, und A muss von B. erben (Dies ist die Überprüfung der Überschreibungen Paket).

  • Sie haben nicht das Muster Af erklärt, dass sie überschreibt Bf, die dann erklärt, dass es Cf A hat Vorrang sollte sagen, dass es von Cf überschreibt da B Überschreiben dieser Methode zu stoppen könnte sich entscheiden, und das sollte nicht dazu führen, in Downstream-Updates.

  • Sie haben nicht das Muster A.f erklärt, dass es überschreibt C.F, aber B.f erklärt nicht seine außer Kraft setzen.

  • Sie haben nicht das Muster A.f erklärt, dass es überschreibt C.F, aber B.f erklärt, dass sie von einigen d.f. überschreibt

Es hat auch verschiedene Funktionen zur Markierung und Überprüfung einer abstrakte Methode zu implementieren.

Hear ist am einfachsten und Arbeiten unter Jython mit Java-Klassen:

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top