considera lo siguiente:
from functools import partial def add(a, b, c): return 100 * a + 10 * b + c add_part = partial(add, c = 2, b = 1) add_part(3) 312Funciona bien. Sin embargo:
def foo(x, y, z): return x+y+z bar = partial(foo, y=3) bar(1, 2)vómitos:
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: foo() got multiple values for argument 'y'Obviamente me estoy perdiendo algo obvio, pero ¿qué?
La definición de partial() de la documentación oficial de functools es:
def partial(func, /, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = {**keywords, **fkeywords} return func(*args, *fargs, **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc Eso significa que, en su caso, partial() devuelve la función foo() con la firma modificada de la siguiente manera:
>>> from inspect import signature >>> signature(bar) <Signature (x, *, y=3, z)> Para resolver su error, puede proporcionar argumentos de palabras clave a la función bar() :
def foo(x, y, z): return x+y+z bar = partial(foo, y=3) bar(x=1, z=2)De la documentación de Python 3.9 :
Devuelve un nuevo objeto parcial que, cuando se le llame, se comportará como una función llamada con los argumentos posicionales args y los argumentos de palabra clave palabras clave. Si se proporcionan más argumentos a la llamada, se agregan a args. Si se proporcionan argumentos de palabras clave adicionales, amplían y anulan las palabras clave.
def foo(x, y, z): return x+y+z bar = partial(foo, y=3) print(bar.args) # () print(bar.keywords) # {'y': 3} Cuando se llama a bar(1, 2) , bar.args se convierte en (1, 2) y bar.keywords sigue siendo {'y': 3}
Tomando nota de esto, lo siguiente es hacer referencia a "Function Calling Behavior" como se especifica en PEP 3102
Cuando se llama a una función, los argumentos de entrada se asignan a parámetros formales de la siguiente manera:
- Para cada parámetro formal, hay una ranura que se utilizará para contener el valor del argumento asignado a ese parámetro.
- Las ranuras a las que se les han asignado valores se marcan como "llenas". Los espacios que aún no tienen un valor asignado se consideran 'vacíos'.
- Inicialmente, todas las ranuras están marcadas como vacías.
- Los argumentos posicionales se asignan primero, seguidos de los argumentos de palabras clave.
- Para cada argumento posicional:
- Intente vincular el argumento al primer espacio de parámetro vacío. Si el espacio no es un espacio vararg, márquelo como "lleno".
- Si el siguiente espacio vacío es un espacio vararg y no tiene nombre, entonces es un error.
- De lo contrario, si el siguiente espacio vacío es un espacio vararg, todos los argumentos restantes que no son palabras clave se colocan en el espacio vararg.
- Para cada argumento de palabra clave:
- Si hay un parámetro con el mismo nombre que la palabra clave, el valor del argumento se asigna a esa ranura de parámetro. Sin embargo, si la ranura del parámetro ya está llena, entonces eso es un error.
- De lo contrario, si hay un argumento de 'diccionario de palabras clave', el argumento se agrega al diccionario utilizando el nombre de la palabra clave como clave del diccionario, a menos que ya haya una entrada con esa clave, en cuyo caso se trata de un error.
- De lo contrario, si no hay un diccionario de palabras clave ni un parámetro con nombre coincidente, se trata de un error.
- Por fin:
- Si la ranura de vararg aún no está llena, asigne una tupla vacía como su valor.
- Para cada ranura vacía restante: si hay un valor predeterminado para esa ranura, llene la ranura con el valor predeterminado. Si no hay un valor predeterminado, entonces es un error.
Sin embargo, no estoy muy seguro de si lo anterior está actualizado o cómo aplicarlo en esta situación porque no estoy seguro de si la bar tiene parámetros posicionales o varargs.