2012-06-16 12 views
16

Diciamo che hanno una funzione:argomenti chiave Spacchettare, ma solo quelli che corrispondono alla funzione

def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s" % (a,b,c) 

Ho un dizionario con un po '(o nessuno) degli argomenti di cui sopra, ma anche con le chiavi che sono non chiamato argomenti nella funzione, ad esempio:

d = {'a':1, 'x':4, 'b':2, 'y':5} 

Se chiamo il seguente mi metterò un errore, perché non sono 'x' e 'y' argomenti a parola chiave nella funzione foo.

foo(**d) # error 

C'è un modo elegante di passare gli argomenti da un dizionario per una funzione, ma solo i valori con i tasti che corrispondono gli argomenti della funzione.

Per favore correggimi se la mia terminologia argomento/parametro è off.

risposta

7

@Ashwini Chaudhary ha un modo molto pitioso di risolvere il tuo problema. Tuttavia, richiede la modifica della firma della funzione foo.

Se non si desidera modificare la firma funzione, è possibile utilizzare introspection per scoprire quali argomenti la funzione si aspetta:

arg_count = foo.func_code.co_argcount 
args = foo.func_code.co_varnames[:arg_count] 

args_dict = {} 
for k, v in d.iteritems(): 
    if k in args: 
     args_dict[k] = v 

foo(**args_dict) 
28
def foo(a = None, b=None, c=None,**extras): 
    return "a:%s, b:%s, c:%s" % (a, b, c) 

qui il **extras raccoglierà tutti gli extra di nome/argomenti a parola chiave.

6

Domanda interessante. Penso che la maggior parte delle persone nella vita reale usi l'approccio di @Ashwini Chaudhary.

Sono d'accordo con @Rodrigue che ci sono volte in cui non è possibile modificare la firma della chiamata della funzione (probabilmente il modulo di qualcun altro).

Quando ciò accade, utilizzare una funzione decoratore

from inspect import getargspec 
from funtools import wraps 

def allow_kwargs(foo): 
    argspec = getargspec(foo) 
    # if the original allows kwargs then do nothing 
    if argspec.keywords: 
     return foo 
    @wraps(foo) 
    def newfoo(*args, **kwargs): 
     #print "newfoo called with args=%r kwargs=%r"%(args,kwargs) 
     some_args = dict((k,kwargs[k]) for k in argspec.args if k in kwargs) 
     return foo(*args, **some_args) 
    return newfoo 


# with your function: 
@allow_kwargs 
def foo(a = None, b=None, c=None): 
    return "a:%s, b:%s, c:%s " % (a,b,c) 

# with someone_elses function: 
from some_place import foo 
foo = allow_kwargs(foo) 

@wraps da functools mantiene le __name__ e __doc__ stringhe in tatto. Puoi anche:

  • guardare FunctionMaker dal modulo decoratori ma questo dovrebbe essere un approccio più riutilizzabile.
  • modifica newfoo per consentire che non venga passato alcun vars extra di parole chiave.
Problemi correlati