2011-08-27 11 views
6

Il seguente codice:kwargs Pass con chiave = coppie di valori validi per funzionare

def f(a=1): 
    pass 

kwargs = {} 
kwargs['a'] = 1 
kwargs['b'] = 2 

f(**kwargs) 

(correttamente) solleva un'eccezione:

Traceback (most recent call last): 
    File "tt.py", line 8, in <module> 
    f(**kwargs) 
TypeError: f() got an unexpected keyword argument 'b' 

Esiste un modo, con functools o altro, per ottenere attorno a questo e capire quali argomenti non sono stati utilizzati dalla funzione per poterli passare ad un'altra funzione? Per esempio, potrei avere un'altra funzione:

def g(a=None, b=None): 
    pass 

che voglio chiamare dopo, ad es.

g(**kwargs) 

ma voglio solo b da passare perché a era gia 'utilizzato up' nella funzione precedente.

Ora so che questa non è la codifica ideale, ma ci sono casi in cui può tornare utile, ed è in realtà facile da spiegare all'utente, ad es. "I parametri aggiuntivi saranno passati a f, e tutti i parametri non passati a f saranno passati a g".

risposta

4

È questo che intendi?

def g(**kwargs): 
    a=kwargs.pop('a',None)  
    b=kwargs.pop('b',None) 
    print(a,b) 
def f(**kwargs): 
    a=kwargs.pop('a',None) 
    print(a) 
    g(**kwargs) 

kwargs = {'a':1,'b':2} 

f(**kwargs) 
# 1 
# (None, 2) 
5

Sono un po 'stupito che questa domanda e la paura che si sta facendo qualcosa che si può rimpiangere.

Stai provando a chiamare metodi diversi con lo stesso dizionario fornendo tutti gli argomenti combinati? In tal caso, la complessità richiesta per gestire questo caso non dovrebbe essere affrontata nei metodi chiamati ma il codice chiamante, ad es. adattando il kwargs al metodo specifico di essere chiamato:

def f(a=1): 
    pass 

call_tailored_args(f, kwargs) 

la funzione di supporto sarà attuato in questo modo:

import inspect 

def tailored_args(f, kwargs): 
    relevant_args = {k: v in kwargs if k in inspect.getargspec(f).args} 
    f(**relevant_args) 
1

È possibile utilizzare un decoratore per rimuovere le kwargs tasti aggiuntivi:

def remove_args(fx): 
    def wrap(**kwargs): 
     kwargs2 = copy.copy(kwargs) 

     ret = None 
     done = False 

     while not done: 
      try: 
       ret = fx(**kwargs2) 
       done = True 
      except TypeError, ex: 
       key = re.findall("\'(\w+)\'", ex.message)[0] 
       del kwargs2[key]    # Remove offending key 
       # print "%s removing %s" % (fx.__name__, key) 

     return ret 

    return wrap 


@remove_args 
def f1(a=1): 
    return "f1-ret" 

@remove_args 
def f2(b=1): 
    return "f2-ret" 

kwargs = {"a": 1, "b": 2, "c": 3} 

print f1(**kwargs) 
print f2(**kwargs) 
Problemi correlati