Pasar kwargs con pares clave = valor no válidos para funcionar

El siguiente código:

def f(a=1):
    pass

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

f(**kwargs)

(correctamente) genera una excepción:

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

¿Hay alguna manera, con functools u otras, de evitar esto y averiguar qué argumentos no fueron utilizados por la función para poder pasarlos a otra función? Por ejemplo, podría tener otra función:

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

que quiero llamar después, con, por ejemplo,

g(**kwargs)

pero solo quiero b ser pasado porque a ya estaba 'agotado' en la función anterior.

Ahora sé que esta no es la codificación ideal, pero hay casos en los que puede ser útil, y en realidad es fácil de explicar al usuario, por ejemplo, "Se pasarán parámetros adicionales af, y cualquier parámetro que no se pase af pasar ag ".

preguntado el 27 de agosto de 11 a las 20:08

3 Respuestas

Estoy un poco sorprendido de que hagas esta pregunta y temo que estés haciendo algo de lo que te arrepientas.

¿Está intentando llamar a diferentes métodos con el mismo diccionario que proporciona todos los argumentos combinados? Si es así, entonces la complejidad requerida para manejar este caso no debe tratarse en los métodos llamados sino en el código de llamada, por ejemplo, adaptando el kwargs al método específico que se va a llamar:

def f(a=1):
    pass

call_tailored_args(f, kwargs)

La función auxiliar se implementaría así:

import inspect

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

Respondido 28 ago 11, 01:08

¿Es esto lo que quieres decir?

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)

Respondido 28 ago 11, 01:08

Puede usar un decorador para eliminar las claves kwargs adicionales:

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)

Respondido 29 ago 11, 03:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.