* args and * * kwargs? [duplicar]


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 separados y los valores se convierten en valores de estos argumentos.

No entiendo para qué tarea de programación sería útil esto.

Tal vez:

Creo que para introducir listas y diccionarios como argumentos de una función Y al mismo tiempo como un comodín, por lo que puedo pasar CUALQUIER argumento?

¿Hay un ejemplo sencillo para explicar cómo se usan *args y **kwargs?

También el tutorial que encontré utiliza solo el "*" y un nombre de variable.

Son *args y **kwargs solo marcadores de posición o utiliza exactamente *args y **kwargs en el código?

Author: d4nyll, 2010-08-03

11 answers

La sintaxis es la * y **. Los nombres *args y **kwargs son solo por convención, pero no hay ningún requisito difícil de usarlos.

Usaría *args cuando no esté seguro de cuántos argumentos se pueden pasar 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

Del mismo modo, **kwargs le 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 los argumentos nombrados también. Los argumentos explícitos obtienen valores primero y luego todo lo demás se pasa a *args y **kwargs. Los argumentos nombrados son los primeros en la lista. Por ejemplo:

def table_things(titlestring, **kwargs)

También puede usar ambos en la misma definición de función, pero *args debe aparecer antes de **kwargs.

También puede usar la sintaxis * y ** cuando llame 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 desempaca. Por esto los hace coincidir con los argumentos en la función. Por supuesto, usted podría tener un * tanto en la definición de la función como en la llamada a la función.

 1496
Author: Dave Webb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-23 15:15:58

Un lugar donde el uso de *args y **kwargs es bastante útil es para la subclase.

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 extender el comportamiento de la clase Foo, sin tener que saber demasiado sobre Foo. Esto puede ser muy conveniente si está programando una API que podría cambiar. MyFoo simplemente pasa todos los argumentos a la clase Foo.

 448
Author: Mark van Lent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-12 13:58:30

Aquí hay un ejemplo que utiliza 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}
 287
Author: Kit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-02 00:50:10

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 si es terriblemente rápido en comparación con solo usar los nombres en sí, pero es mucho más fácil de escribir!

 65
Author: Wayne Werner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 13:03:49

Un caso en el que *args y **kwargs son útiles es cuando se escriben funciones de envoltura (como decoradores) que necesitan ser capaces de aceptar argumentos arbitrarios para pasar a través de la función que se envuelve. 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
 39
Author: jchl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 08:40:34

* args y * * kwargs son características especiales de Python. Piense en una función que podría tener un número desconocido de argumentos. Por ejemplo, por cualquier razón, desea tener una función que suma un número desconocido de números (y no desea usar la función suma incorporada). Así que escribe 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 diffrent. Con * * kwargs puede dar argumentos arbitrarios de palabras clave a una función y usted puede acceder a ellos como un dictonary.

def someFunction(**kwargs):
  if 'text' in kwargs:
    print kwargs['text']

Llamando a someFunction(text="foo") imprimirá foo.

 35
Author: Steven Mohr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 09:35:18

Imagínese que tiene una función pero no quiere restringir el número de parámetros que toma. Ejemplo:

>>> import operator
>>> def multiply(*args):
...  return reduce(operator.mul, args)

Luego usa esta función como:

>>> multiply(1,2,3)
6

or

>>> numbers = [1,2,3]
>>> multiply(*numbers)
6
 17
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 08:40:07

Los nombres *args y **kwargs o **kw son puramente por convención. Hace que sea más fácil para nosotros leer el código del otro

Un lugar que es útil es cuando se utiliza el módulo struct

struct.unpack() devuelve una tupla mientras que struct.pack() utiliza 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 te verías obligado a escribir

new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)

Que también significa el si el format_str cambia y el tamaño de la tupla cambia, tendré que volver atrás y editar esa línea realmente larga

 15
Author: John La Rooy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 08:39:07

Tenga en cuenta que *args/**kwargs es parte de la sintaxis de llamada a funciones, y no es realmente un operador. Esto tiene un efecto secundario particular con el que me encontré, que es que no puede usar la expansión *args con la instrucción print, ya que print no es una función.

Esto parece razonable:

def myprint(*args):
    print *args

Desafortunadamente no 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 resolví on:

def myprint(*args):
    for arg in args:
        print arg,
    print
 9
Author: yoyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 20:29:33

Estos parámetros se usan típicamente para funciones 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 dado que estos parámetros ocultan los nombres de los parámetros reales, es mejor evitarlos.

 7
Author: Rudi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-03 08:41:27

Puedes echar un vistazo a los documentos de python (docs.python.org en las FAQ), pero más específicamente para una buena explicación la misteriosa señorita args y el señor kwargs (cortesía de archive.org) (el enlace original muerto es aquí ).

En pocas palabras, ambos se utilizan cuando se utilizan parámetros opcionales para una función o método. Como dice Dave, * args se usa cuando no sabe cuántos argumentos se pueden pasar, y * * kwargs cuando desea manejar parámetros especificados por nombre y valor como en:

myfunction(myarg=1)
 3
Author: Yoni H,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-22 17:38:57