das docstring von einem Verfahren unter Verwendung von automatisch zu den einer anderen Methode überschreibt

StackOverflow https://stackoverflow.com/questions/71817

  •  09-06-2019
  •  | 
  •  

Frage

Das Problem: Ich habe eine Klasse, die eine Template-Methode execute enthält, die eine andere Methode _execute aufruft. Subklassen sollen _execute überschrieben werden einige spezifische Funktionalität zu implementieren. Diese Funktionalität soll in der docstring von _execute dokumentiert werden. Fortgeschrittene Benutzer können ihre eigenen Subklassen erstellen, um die Bibliothek zu erweitern. ein anderer Benutzer jedoch mit einer solchen Unterklasse nur den Umgang execute verwenden sollte, damit er nicht die richtige docstring sehen, wenn er help(execute) verwendet.

Deshalb wäre es schön, die Basisklasse in einer solchen Art und Weise zu modifizieren, dass die docstring von execute in einer Unterklasse automatisch mit der _execute ersetzt wird. Irgendwelche Ideen, wie könnte dies geschehen?

Ich dachte an metaclasses, dies zu tun, dem Anwender diese vollständig transparent zu machen.

War es hilfreich?

Lösung

Nun, wenn Sie nichts dagegen haben, die ursprüngliche Methode in der Unterklasse kopieren, können Sie die folgende Technik verwendet werden.

import new

def copyfunc(func):
    return new.function(func.func_code, func.func_globals, func.func_name,
                        func.func_defaults, func.func_closure)

class Metaclass(type):
    def __new__(meta, name, bases, attrs):
        for key in attrs.keys():
            if key[0] == '_':
                skey = key[1:]
                for base in bases:
                    original = getattr(base, skey, None)
                    if original is not None:
                        copy = copyfunc(original)
                        copy.__doc__ = attrs[key].__doc__
                        attrs[skey] = copy
                        break
        return type.__new__(meta, name, bases, attrs)

class Class(object):
    __metaclass__ = Metaclass
    def execute(self):
        '''original doc-string'''
        return self._execute()

class Subclass(Class):
    def _execute(self):
        '''sub-class doc-string'''
        pass

Andere Tipps

Gibt es einen Grund, warum Sie nicht die execute Funktion der Basisklasse direkt überschreiben können?

class Base(object):
    def execute(self):
        ...

class Derived(Base):
    def execute(self):
        """Docstring for derived class"""
        Base.execute(self)
        ...stuff specific to Derived...

Wenn Sie nicht möchten, dass die oben genannten tun:

Method-Objekte unterstützen nicht auf das __doc__ Attribut zu schreiben, so haben Sie __doc__ in dem eigentlichen Funktionsobjekt zu ändern. Da Sie nicht die eine in der Basisklasse außer Kraft setzen möchten, würden Sie jede Unterklasse eine eigene Kopie von execute geben müssen:

class Derived(Base):
    def execute(self):
        return Base.execute(self)

    class _execute(self):
        """Docstring for subclass"""
        ...

    execute.__doc__= _execute.__doc__

, aber das ist ähnlich wie auf Umwegen execute neu zu definieren ...

Schauen Sie sich die functools.wraps () Dekorateur; es tut all dies, aber ich weiß nicht ohne weiteres, wenn Sie es in dem richtigen Kontext zu laufen bekommen

Nun, der doc-String wird in __doc__ gespeichert, so dass es nicht allzu schwer sein würde, es erneut zu vergeben basierend auf dem doc-String von _execute nach der Tat.

Grundsätzlich gilt:

class MyClass(object):
    def execute(self):
        '''original doc-string'''
        self._execute()

class SubClass(MyClass):
    def _execute(self):
        '''sub-class doc-string'''
        pass

    # re-assign doc-string of execute
    def execute(self,*args,**kw):
        return MyClass.execute(*args,**kw)
    execute.__doc__=_execute.__doc__

hat Ausführen erneut erklärt werden, dass die doc Schnur befestigt wird für den SubClass auf die Version von ausführen und nicht für MyClass (die sonst mit anderen Unterklassen stören würde).

Das ist kein sehr ordentlich Weg, es zu tun, sondern aus der POV der Nutzer einer Bibliothek soll es das gewünschte Ergebnis. Sie könnten dann diese wickeln in einer Meta-Klasse, um es für die Menschen leichter zu machen, die Nebenklasse sind.

Ich bin damit einverstanden, dass die einfachste, Pythonic Weg, dies zu nähern, ist einfach in Ihren Unterklassen neu definieren ausführen und habe sie die Methode der Basisklasse ausführen nennen:

class Sub(Base):
    def execute(self):
        """New docstring goes here"""
        return Base.execute(self)

Das ist sehr wenig Code zu erreichen, was Sie wollen; Der einzige Nachteil ist, dass Sie diesen Code in jeder Unterklasse wiederholen muss, die Basis erstreckt. Dies ist jedoch ein geringer Preis für das Verhalten zahlen Sie wollen.

Wenn Sie eine schlampige und ausführliche Art und Weise wollen, dafür zu sorgen, dass das docstring für ausführen dynamisch generiert wird, können Sie das Deskriptor-Protokoll verwenden, die hier deutlich weniger Code als die anderen Vorschläge wäre. Das ist ärgerlich, weil Sie nicht nur einen Descriptor auf einer vorhandenen Funktion gesetzt, was bedeutet, dass als eine separate Klasse mit einem __call__ Methode geschrieben werden ausgeführt werden müssen.

Hier ist der Code, dies zu tun, aber bedenken Sie, dass mein obiges Beispiel ist viel einfacher und Pythonic:

class Executor(object):
    __doc__ = property(lambda self: self.inst._execute.__doc__)

    def __call__(self):
        return self.inst._execute()

class Base(object):
    execute = Executor()

class Sub(Base):
    def __init__(self):
        self.execute.inst = self

    def _execute(self):
        """Actually does something!"""
        return "Hello World!"

spam = Sub()
print spam.execute.__doc__  # prints "Actually does something!"
help(spam)                  # the execute method says "Actually does something!"
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top