python - example - * args y** kwargs?
subplot title python (11)
* args y ** kwargs son características especiales de magia de Python. Piense en una función que podría tener un número desconocido de argumentos. Por ejemplo, por cualquier motivo, desea tener una función que sume un número desconocido de números (y no desea utilizar la función de suma integrada). Así que escribes esta función:
def sumFunction(*args):
result = 0
for x in args:
result += x
return result
y úsalo como: sumFunction (3,4,6,3,6,8,9).
** Kwargs tiene una función diferente. Con ** kwargs puede dar argumentos de palabra clave arbitrarios a una función y puede acceder a ellos como un diccionario.
def someFunction(**kwargs):
if ''text'' in kwargs:
print kwargs[''text'']
Al llamar a someFunction (text = "foo") se imprimirá foo.
Esta pregunta ya tiene una respuesta aquí:
Así que tengo dificultades con el concepto de *args
y **kwargs
.
Hasta ahora he aprendido que:
-
*args
= lista de argumentos - como argumentos posicionales -
**kwargs
= diccionario - cuyas claves se convierten en argumentos de palabras clave separadas y los valores se convierten en valores de estos argumentos.
No entiendo para qué tarea de programación sería útil.
Tal vez:
Creo que para ingresar listas y diccionarios como argumentos de una función Y al mismo tiempo que un comodín, ¿puedo pasar CUALQUIER argumento?
¿Hay un ejemplo simple para explicar cómo se usan *args
y **kwargs
?
También el tutorial que encontré usaba solo el "*" y un nombre de variable.
¿Son *args
y **kwargs
solo marcadores de posición o usas exactamente *args
y **kwargs
en el código?
Aquí está uno de mis lugares favoritos para usar la sintaxis **
como en el ejemplo final de Dave Webb:
mynum = 1000
mystr = ''Hello World!''
print "{mystr} New-style formatting is {mynum}x more fun!".format(**locals())
No estoy seguro de que sea terriblemente rápido en comparación con el uso de los nombres en sí mismos, ¡pero es mucho más fácil de escribir!
Aquí hay un ejemplo que usa 3 tipos diferentes de parámetros.
def func(required_arg, *args, **kwargs):
# required_arg is a positional-only parameter.
print required_arg
# args is a tuple of positional arguments,
# because the parameter name has * prepended.
if args: # If args is not empty.
print args
# kwargs is a dictionary of keyword arguments,
# because the parameter name has ** prepended.
if kwargs: # If kwargs is not empty.
print kwargs
>>> func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)
>>> func("required argument")
required argument
>>> func("required argument", 1, 2, ''3'')
required argument
(1, 2, ''3'')
>>> func("required argument", 1, 2, ''3'', keyword1=4, keyword2="foo")
required argument
(1, 2, ''3'')
{''keyword2'': ''foo'', ''keyword1'': 4}
Estos parámetros se utilizan normalmente para las funciones de proxy, por lo que el proxy puede pasar cualquier parámetro de entrada a la función de destino.
def foo(bar=2, baz=5):
print bar, baz
def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
print x
foo(*args, **kwargs) # applies the "non-x" parameter to foo
proxy(23, 5, baz=''foo'') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar=''asdas'') # calls foo with bar=''asdas'' and leave baz default argument
Pero como estos parámetros ocultan los nombres de los parámetros reales, es mejor evitarlos.
Imagínese que tiene una función pero no desea restringir la cantidad de parámetros necesarios. Ejemplo:
>>> import operator
>>> def multiply(*args):
... return reduce(operator.mul, args)
Entonces usas esta función como:
>>> multiply(1,2,3)
6
or
>>> numbers = [1,2,3]
>>> multiply(*numbers)
6
Los nombres *args
y **kwargs
o **kw
son puramente por convención. Nos facilita la lectura del código de cada uno.
Un lugar en el que está a mano es cuando se usa el módulo de estructura.
struct.unpack()
devuelve una tupla mientras que struct.pack()
usa un número variable de argumentos. Al manipular datos, es conveniente poder pasar una tupla a struck.pack()
por ejemplo.
tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)
sin esta habilidad estarías obligado a escribir
new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)
lo que también significa que si cambia format_str y cambia el tamaño de la tupla, tendré que volver y editar esa línea realmente larga
Puede echar un vistazo a los documentos de python (docs.python.org en las Preguntas frecuentes), pero más específicamente para una buena explicación, la misteriosa miss args y mister kwargs (cortesía de archive.org) (el enlace original y muerto está aquí ).
En pocas palabras, ambos se usan cuando se usan parámetros opcionales para una función o método. Como dice Dave, * args se usa cuando no sabes cuántos argumentos se pueden pasar, y ** kwargs cuando quieres manejar los parámetros especificados por nombre y valor como en:
myfunction(myarg=1)
Tenga en cuenta que * args / ** kwargs es parte de la sintaxis de llamada de funciones, y no es realmente un operador. Esto tiene un efecto secundario particular con el que me encontré, que es que no se puede usar la expansión * args con la declaración de impresión, ya que la impresión no es una función.
Esto parece razonable:
def myprint(*args):
print *args
Desafortunadamente no se compila (error de sintaxis).
Esto compila:
def myprint(*args):
print args
Pero imprime los argumentos como una tupla, que no es lo que queremos.
Esta es la solución que decidí:
def myprint(*args):
for arg in args:
print arg,
print
Un caso en el que * args y ** kwargs son útiles es cuando se escriben funciones de envoltorio (como los decoradores) que necesitan poder aceptar argumentos arbitrarios para pasar a la función que se está envolviendo. Por ejemplo, un decorador simple que imprime los argumentos y el valor de retorno de la función que se envuelve:
def mydecorator( f ):
@functools.wraps( f )
def wrapper( *args, **kwargs ):
print "Calling f", args, kwargs
v = f( *args, **kwargs )
print "f returned", v
return v
return wrapper
Un lugar donde el uso de *args
y **kwargs
es bastante útil es para subclasificar.
class Foo(object):
def __init__(self, value1, value2):
# do something with the values
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don''t care about the args
print ''myfoo''
super(MyFoo, self).__init__(*args, **kwargs)
De esta manera, puede ampliar el comportamiento de la clase Foo, sin tener que saber demasiado sobre Foo. Esto puede ser muy conveniente si está programando para una API que podría cambiar. MyFoo solo pasa todos los argumentos a la clase Foo.
La sintaxis es el *
y **
. Los nombres *args
y **kwargs
son solo por convención, pero no hay un requisito estricto para usarlos.
*args
cuando no esté seguro de cuántos argumentos podrían pasarse a su función, es decir, le permite pasar un número arbitrario de argumentos a su función. Por ejemplo:
>>> def print_everything(*args):
for count, thing in enumerate(args):
... print( ''{0}. {1}''.format(count, thing))
...
>>> print_everything(''apple'', ''banana'', ''cabbage'')
0. apple
1. banana
2. cabbage
De manera similar, **kwargs
permite manejar argumentos con nombre que no ha definido de antemano:
>>> def table_things(**kwargs):
... for name, value in kwargs.items():
... print( ''{0} = {1}''.format(name, value))
...
>>> table_things(apple = ''fruit'', cabbage = ''vegetable'')
cabbage = vegetable
apple = fruit
Puede utilizar estos junto con argumentos con nombre también. Los argumentos explícitos obtienen valores primero y luego todo lo demás se pasa a *args
y **kwargs
. Los argumentos nombrados vienen primero en la lista. Por ejemplo:
def table_things(titlestring, **kwargs)
También puede usar ambas en la misma definición de función, pero *args
debe aparecer antes de **kwargs
.
También puede usar la sintaxis *
y **
al llamar a una función. Por ejemplo:
>>> def print_three_things(a, b, c):
... print( ''a = {0}, b = {1}, c = {2}''.format(a,b,c))
...
>>> mylist = [''aardvark'', ''baboon'', ''cat'']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat
Como puede ver en este caso, toma la lista (o tupla) de elementos y la desempaqueta. Por esto los relaciona con los argumentos en la función. Por supuesto, podría tener un *
tanto en la definición de función como en la llamada de función.