Pregunta * args y ** kwargs? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Entonces 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 separados de palabra clave 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 como un comodín, ¿puedo pasar CUALQUIER argumento?

¿Hay un ejemplo simple para explicar cómo *args y **kwargs ¿son usados?

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

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


1189
2017-08-03 08:28


origen


Respuestas:


La sintaxis es la * y **. Los nombres *args y **kwargs son solo por convención, pero no hay un requisito estricto para usarlos.

Utilizarías *args cuando no está seguro de cuántos argumentos se le pueden pasar a su función, es decir, le permite pasar una cantidad arbitraria 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

Similar, **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 usarlos junto con los argumentos nombrados también. Los argumentos explícitos obtienen valores primero y luego todo lo demás 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 ocurrir antes **kwargs.

También puedes usar el * y ** sintaxis 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 los elementos y los desempaqueta. Por esto los compara con los argumentos en la función. Por supuesto, podrías tener un * tanto en la definición de la función como en la llamada a la función.


1472
2017-08-03 08:38



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

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


442
2017-08-03 08:39



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}

278
2017-08-03 08:42



Este es uno de mis lugares favoritos para usar el ** 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, ¡pero es mucho más fácil escribir!


65
2017-08-03 13:03



Un caso donde * args y ** kwargs son útiles es cuando se escriben funciones de envoltura (como 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

39
2017-08-03 08:40



* args y ** kwargs son características mágicas especiales de Python. Piensa 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 utilizar la función de suma incorporada). Entonces escribes esta función:

def sumFunction(*args):
  result = 0
  for x in args:
    result += x
  return result

y úsalo como: función sum (3,4,6,3,6,8,9).

** Kwargs tiene una función diferente. Con ** kwargs puedes dar argumentos arbitrarios de palabra clave a una función y puedes acceder a ellos como un dictonario.

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

Llamar a alguna función (text = "foo") imprimirá foo.


35
2017-08-03 08:40



Solo imagine que tiene una función pero no desea 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
2017-08-03 08:40



Los nombres *args y **kwargs o **kw son puramente por convención. Nos hace más fácil leer el código de cada uno

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

struct.unpack() devuelve una tupla mientras struct.pack() usa una cantidad variable de argumentos Al manipular datos, es conveniente poder pasar una tupla a struck.pack() p.ej.

tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)

sin esta habilidad se vería 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 el format_str cambia y el tamaño de la tupla cambia, tendré que volver atrás y editar esa larga línea


14
2017-08-03 08:32