una propias otra matematicas mandar llamar lista funciones funcion ejemplos diccionario dentro definir python dictionary named-parameters kwargs

python - propias - ¿Cómo llamar a una función con un diccionario que contiene más elementos de los que la función tiene parámetros?



lista de funciones de python (6)

Estoy buscando la mejor manera de combinar una función con un diccionario que contenga más elementos que las entradas de la función

El desempaque de kwarg básico ** falla en este caso:

def foo(a,b): return a + b d = {''a'':1, ''b'':2, ''c'':3} foo(**d) --> TypeError: foo() got an unexpected keyword argument ''c''

Después de algunas investigaciones se me ocurrió el siguiente enfoque:

import inspect # utilities def get_input_names(function): ''''''get arguments names from function'''''' return inspect.getargspec(function)[0] def filter_dict(dict_,keys): return {k:dict_[k] for k in keys} def combine(function,dict_): ''''''combine a function with a dictionary that may contain more items than the function''s inputs '''''' filtered_dict = filter_dict(dict_,get_input_names(function)) return function(**filtered_dict) # examples def foo(a,b): return a + b d = {''a'':1, ''b'':2, ''c'':3} print combine(foo,d) --> 3

Mi pregunta es: ¿es esta una buena manera de lidiar con este problema, o hay una mejor práctica o existe un mecanismo en el lenguaje que quizás falto?


¿Qué tal hacer un decorator que filtraría solo los argumentos de palabras clave permitidos ?

import inspect def get_input_names(function): ''''''get arguments names from function'''''' return inspect.getargspec(function)[0] def filter_dict(dict_,keys): return {k:dict_[k] for k in keys} def filter_kwargs(func): def func_wrapper(**kwargs): return func(**filter_dict(kwargs, get_input_names(func))) return func_wrapper @filter_kwargs def foo(a,b): return a + b d = {''a'':1, ''b'':2, ''c'':3} print(foo(**d))

Lo bueno de este decorador es que es genérico y reutilizable. Y no necesitaría cambiar la forma en que llama y usa sus funciones de destino.


Esto todavía está modificando la función original, pero puede crear un bitbucket kwargs al final de la lista de argumentos:

def foo(a, b, **kwargs): return a + b foo(**{ ''a'': 5, ''b'': 8, ''c'': ''🐘'' }) # 13


Haría algo como esto:

def combine(function, dictionary): return function(**{key:value for key, value in dictionary.items() if key in inspect.getargspec(function)[0]} )

Utilizar:

>>> def this(a, b, c=5): ... print(a, b, c) ... >>> combine(this, {''a'': 4, ''b'': 6, ''c'': 6, ''d'': 8}) 4 6 6 >>> combine(this, {''a'': 6, ''b'': 5, ''d'': 8}) 6 5 5


Su problema radica en la forma en que definió su función, debería definirse así:

def foo(**kwargs):

Y luego, dentro de la función, puede iterar sobre el número de argumentos enviados a la función como tal:

if kwargs is not None: for key, value in kwargs.iteritems(): do something

Puede encontrar más información sobre el uso de ** kwargs en este post - http://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/


También puede usar una función decoradora para filtrar los argumentos de palabras clave que no están permitidos en su función. De usted utiliza la función de signature nueva en 3.3 para devolver su función Signature

from inspect import signature from functools import wraps def decorator(func): @wraps(func) def wrapper(*args, **kwargs): sig = signature(func) result = func(*[kwargs[param] for param in sig.parameters]) return result return wrapper

Desde Python 3.0 puede usar getargspec que está en desuso desde la versión 3.0

import inspect def decorator(func): @wraps(func) def wrapper(*args, **kwargs): argspec = inspect.getargspec(func).args result = func(*[kwargs[param] for param in argspec]) return result return wrapper

Para aplicar su decoración a una función existente, debe pasar su función como argumento a su decorador:

Manifestación:

>>> def foo(a, b): ... return a + b ... >>> foo = decorator(foo) >>> d = {''a'': 1, ''b'': 2, ''c'': 3} >>> foo(**d) 3

Para aplicar su decorador a una nueva función simplemente use @

>>> @decorator ... def foo(a, b): ... return a + b ... >>> foo(**d) 3

También puede definir su función utilizando argumentos de palabras clave arbitrarias **kwargs .

>>> def foo(**kwargs): ... if ''a'' in kwargs and ''b'' in kwargs: ... return kwargs[''a''] + kwargs[''b''] ... >>> d = {''a'': 1, ''b'': 2, ''c'': 3} >>> foo(**d) 3


Todas estas respuestas son incorrectas.

No es posible hacer lo que está pidiendo, porque la función podría declararse así:

def foo(**kwargs): a = kwargs.pop(''a'') b = kwargs.pop(''b'') if kwargs: raise TypeError(''Unexpected arguments: %r'' % kwargs)

Ahora, ¿por qué alguien escribiría eso?

Porque no conocen todos los argumentos de antemano. Aquí hay un caso más realista:

def __init__(self, **kwargs): for name in self.known_arguments(): value = kwargs.pop(name, default) self.do_something(name, value) super().__init__(**kwargs) # The superclass does not take any arguments

Y here hay un código del mundo real que realmente hace esto.

Puede preguntar por qué necesitamos la última línea. ¿Por qué pasar argumentos a una superclase que no toma ninguno? Cooperativa de herencia múltiple . Si mi clase obtiene un argumento que no reconoce, no debería tragarlo, ni debería cometer un error. Debería pasar el argumento a lo largo de la cadena para que otra clase que no conozco pueda manejarlo. Y si nadie lo maneja, entonces el object.__init__() proporcionará un mensaje de error apropiado. Desafortunadamente, las otras respuestas no lo manejarán con gracia. Verán **kwargs y no pasarán ningún argumento o pasarán todos, lo que es incorrecto.

El resultado final : no hay una forma general de descubrir si una llamada de función es legal sin hacerla realmente. inspect es una aproximación cruda, y se desmorona por completo frente a las funciones variad. Variadic no significa "pasa lo que quieras"; significa "las reglas son demasiado complejas para expresar en una firma". Como resultado, mientras que en muchos casos es posible hacer lo que usted está tratando de hacer, siempre habrá situaciones en las que no hay una respuesta correcta.