2016-05-25 8 views
5

Ich habe eine Funktion Convenience-Funktion Wrapper für eine andere Funktion (bar). foo ruft bar auf, führt dann weitere Aufgaben an der Ausgabe aus. Zum Beispiel:Halten von Funktionsaufrufsignaturen für eine Funktion, die eine Obermenge von Argumenten einer anderen Funktion akzeptiert

def bar(bar_arg, bar_kw=None): 
    #do some stuff 
    return ret 

def foo(bar_arg, foo_arg, bar_kw=None, foo_kw=None): 
    ret = bar(bar_arg, bar_kw) 
    ret.some_method(foo_arg, foo_kw=foo_kw) 

würde ich den Anruf Signatur für foo gerne die Schlüsselwörter und Argumente von bar enthalten, so dass ein Benutzer foo weiß, was Inspizieren sie passieren können, jedoch würde ich die vollständige Liste der vermeiden, wie die Aufrechterhaltung Argumente selbst seit bar tendenziell zu ändern, wie das Paket, aus dem es kommt, aktualisiert wird und seine Argumentliste ist lang. Seit foo ruft immer bar mit der vollständigen Liste der Argumente und Schlüsselwörter, die bar akzeptiert, ich sehe nicht, dass ich die Liste selbst pflegen sollte.

Gibt es eine Möglichkeit, die Anrufsignatur für foo basierend auf der Anrufsignatur für bar aufzubauen? Gibt es außerdem eine Möglichkeit, die Eingaben in foo in einem Wörterbuch oder Namespace zu erfassen, so dass ich die Argumente und Schlüsselwörter, die von foo verwendet werden, leicht von denen trennen kann, die von bar verwendet werden?

Hinweis, ich weiß über * Args und ** Kwargs. Sie lassen jedoch die Funktionssignatur mehrdeutig und informieren den Benutzer nicht darüber, welche Argumente und Schlüsselwortargumente zulässig sind.

Edit: Ich sollte beachten, dass mein Anwendungsfall wesentlich komplexer als dieses Beispiel ist. Die aufgerufene externe Funktion (bar) lautet matplotlib.colorbar.ColorbarBase. Die aufrufende Funktion (foo) ist eine Klassenmethode für eine Zeichenklasse, die in zahlreichen eigenen Anwendungen verwendet wird, die andere wahrscheinlich in Zukunft verwenden werden. foo erstellt eine Farbleiste, führt dann zusätzliche Arbeit an der Farbleiste durch, basierend auf zusätzlichen Argumenten und Schlüsselwörtern, die von ColorbarBase nicht akzeptiert werden.

+0

Sie können * wahrscheinlich * einen Dekorateur haben (der die 'bar'-Referenz als Argument erhält), tun Sie das für Sie. – SuperSaiyan

+0

Ich denke du meinst "ret.some_method", und auch "return ret". –

+0

@Alex Danke, bearbeitet. – Vorticity

Antwort

0

Ich denke, die beste Option ist foo weglassen. Halten Sie die API mit den einfachen Bausteinen, die Benutzer benötigen, kurz und bündig, damit sie schnell lernen, wie Sie Ihre Bibliothek verwenden. Programmierer können dann ganz einfach die Komfortfunktionen erstellen, die sie wirklich wollen, und sich nicht von denen ablenken lassen, von denen sie denken, dass sie sie wollen.

Wenn Ihre tatsächlichen Funktionen komplizierter sind als sie in der Frage aussehen, dann aktualisieren Sie die Frage, um das zu zeigen. Gerade jetzt ist es klar und explizit für einen Programmierer, einfach zu schreiben. Jeder Leser weiß genau, was vor sich geht und muss keine lange Argumentliste parsen, und die zusätzliche Codezeile ist in Ordnung.

+0

I stimme generell mit dir überein, aber wie du annimmst, ist mein Anwendungsfall komplexer. Die aufgerufene Funktion ist matplotlib.colorbar.ColorbarBase. Es wird innerhalb einer Klassenmethode aufgerufen, die zusätzliche Arbeit an der resultierenden Farbleiste leistet und zusätzliche Argumente und Schlüsselwörter akzeptiert. Ich dachte, es wäre offensichtlich, dass mein Anwendungsfall komplexer war als der Pseudocode, den ich gepostet habe. – Vorticity

+0

Ich habe gerade meine Antwort bearbeitet, um teilweise zu erklären, dass mein Fall komplexer ist als das Pseudocode-Beispiel. – Vorticity

+1

@Vorticity wenn, sagen wir mal, es gibt keine "bar.some_method", aber es sind mehrere komplizierte Zeilen, dann erwäge * creating * eine 'bar.some_method' oder' some_function (bar) ', so dass du auf simple zurückkommst Bausteine ​​mit sauber getrennten Argumenten. Wenn das nicht gut ist, zeigen Sie den tatsächlichen Code oder einen realistischeren Pseudocode, weil Ihre Beschreibung nicht sehr informativ ist. –

1

Seit bar() Wraps foo() die den ColorbarBase Konstruktor aufruft, einen Dekorateur um den foo() Anruf schreiben. Der Dekorator führt vor dem Aufruf von foo() Änderungen an den übergebenen Argumenten durch.

from matplotlib import pyplot 
import matplotlib as mpl 


def bar(f): 
    def wrapper(*args, **kwargs): 
     # Change args, kwargs for calling foo() 
     f(*new_args,**new_kwargs) 
     return 
return wrapper 


@bar 
def foo(*new_args, **new_kwargs): 
    return mpl.colorbar.ColorbarBase(*new_args, **new_kwargs) 

Beispielsweise gibt die folgende ColorbarBase ein Objekt mit dem Anrufer einen Anfangssatz von Parametern ergeben, der durch bar() dann modifiziert werden. Auf diese Weise basiert die Anrufsignatur für foo() auf der Anrufsignatur für bar().

fig = pyplot.figure(figsize=(8, 3)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
cmap = mpl.cm.cool 
norm = mpl.colors.Normalize(vmin=5, vmax=10) 

ret = foo(ax1, 
      cmap=cmap, 
      norm=norm, 
      orientation='horizontal') 
Verwandte Themen