2016-05-25 15 views
5

Ho una funzione (foo) che è una funzione di funzione comfort per un'altra funzione (bar). foo chiama bar, quindi esegue un altro paio di attività sull'output. Per esempio:Mantenimento delle firme delle chiamate di funzioni coerenti per una funzione che accetta un superset degli argomenti di un'altra funzione

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) 

Vorrei la firma richiesta di foo per contenere le parole chiave e gli argomenti da bar in modo che un utente che controlla foo sa quello che può passare, però, vorrei evitare di mantenere l'elenco completo delle argomenti dal bar tende a cambiare quando il pacchetto da cui proviene viene aggiornato e il suo elenco di argomenti è lungo. Dal foo chiama sempre bar con l'elenco completo di argomenti e parole chiave che bar accetta, non vedo che avrei bisogno di mantenere la lista da solo.

C'è un modo per creare la firma della chiamata per foo in base alla firma della chiamata per bar? Inoltre, esiste un modo per acquisire gli input su foo in un dizionario o uno spazio dei nomi in modo da poter separare facilmente gli argomenti e le parole chiave utilizzati da foo da quelli utilizzati da bar?

Nota, so di * args e ** kwargs. Tuttavia, lasciano ambigua la firma della funzione e non informano l'utente di quali argomenti e argomenti della parola chiave sono consentiti.

Modifica: Devo notare che il mio caso d'uso è significativamente più complesso di questo esempio. La funzione esterna chiamata (bar) è matplotlib.colorbar.ColorbarBase. La funzione di chiamata (foo) è un metodo di classe per una classe di stampa che viene utilizzata in numerose applicazioni personali che altri useranno in futuro. foo crea una barra colori, quindi esegue lavori aggiuntivi sulla barra dei colori in base a argomenti e parole chiave aggiuntivi non accettati da ColorbarBase.

+0

È possibile * probabilmente * avere un decoratore (che ottiene il riferimento 'bar' come argomento) farlo per voi. – SuperSaiyan

+0

Penso che tu intenda "ret.some_method', e anche" return ret ". –

+0

@Alex Grazie, modificato. – Vorticity

risposta

0

Penso che l'opzione migliore sia lasciare fuori foo. Mantieni l'API corta e dolce con solo i semplici blocchi predefiniti di cui gli utenti hanno bisogno per imparare rapidamente come utilizzare la tua libreria. I programmatori possono quindi facilmente creare le funzioni di convenienza che desiderano realmente e non essere distratti da quelli che si ritiene desiderino.

Se le funzioni effettive sono più complicate di quelle nella domanda, aggiornare la domanda per mostrarla. In questo momento è chiaro ed esplicito per un programmatore scrivere semplicemente

my_bar = bar(bar_arg, bar_kw) 
my_bar.some_method(foo_arg, foo_kw=foo_kw) 

per se stessi. Qualsiasi lettore sa esattamente cosa sta succedendo e non deve analizzare una lunga lista di argomenti, e la riga di codice aggiuntiva va bene.

+0

I generalmente sono d'accordo con te, ma, come tu pensi, il mio caso d'uso è più complesso di questo. La funzione chiamata è matplotlib.colorbar.ColorbarBase. Viene chiamato all'interno di un metodo di classe che esegue un lavoro aggiuntivo sulla colorbar risultante e accetta ulteriori argomenti e parole chiave. Ho pensato che sarebbe stato ovvio che il mio caso d'uso fosse più complesso dello pseudocodice che ho postato. – Vorticity

+0

Ho appena modificato la mia risposta per spiegare parzialmente come il mio caso è più complesso dell'esempio pseudocodice. – Vorticity

+1

@Vorticity se, per esempio, non esiste una cosa come "bar.some_method", ma piuttosto molte linee complicate, quindi considera * creando * un 'bar.some_method' o' some_function (bar) 'in modo da poter tornare alla semplice elementi costitutivi con argomenti chiaramente separati. Se non va bene, mostra il codice attuale o qualche pseudocodice più realistico perché la tua descrizione non è molto informativa. –

1

Dal bar() avvolge foo() che chiama il costruttore ColorbarBase, scrivere un decoratore intorno alla chiamata foo(). Il decoratore apporta modifiche agli argomenti passati nella barra prima di chiamare foo().

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) 

Ad esempio, la seguente restituisce un oggetto ColorbarBase al chiamante dare una prima serie di parametri che vengono modificati da bar(). In questo modo la firma della chiamata per foo() si basa sulla firma della chiamata per 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') 
Problemi correlati