¿Qué hace ** (doble estrella/asterisco) y * (estrella/asterisco) para los parámetros en Python?

16 minutos de lectura

Avatar de usuario de Todd
Todd

Qué hacer *args y **kwargs ¿significar?

def foo(x, y, *args):
def bar(x, y, **kwargs):

  • ver también stackoverflow.com/questions/6967632/…

    – Rusia debe sacar a Putin

    1 de marzo de 2018 a las 20:53


  • Esta pregunta es un objetivo duplicado muy popular, pero desafortunadamente a menudo se usa incorrectamente. Tenga en cuenta que esta pregunta se refiere a definiendo funciones con varargs (def func(*args)). Para una pregunta sobre qué significa en función llamadas (func(*[1,2])) mira aquí. Para una pregunta cómo para descomprimir las listas de argumentos, consulte aquí. Para una pregunta sobre qué * significa en literales ([*[1, 2]]) mira aquí.

    – Aran Fey

    22/03/2019 a las 20:40


  • @ Aran-Fey: creo que un mejor objetivo para “qué significa en las llamadas a funciones” es ¿Qué significa el operador estrella en una llamada a funciones? Su enlace realmente no aborda el uso de **y es una pregunta mucho más estrecha.

    – ShadowRanger

    10 de diciembre de 2020 a las 5:55

  • Esta pregunta es, como muchas preguntas muy antiguas, algo al revés; por lo general, una pregunta debe ser sobre cómo resolver un problema en un código nuevo, en lugar de cómo comprender el código existente. Para esto último, si está cerrando algo más como un duplicado, considere stackoverflow.com/questions/1993727/… (aunque esto solo cubre * y no **).

    – Karl Knechtel

    17 abr a las 4:51

  • stackoverflow.com/questions/3394835/use-of-args-and-kwargs también se cerró como un duplicado de esto, pero es posible que lo encuentre mejor que este.

    – Karl Knechtel

    21 de junio a las 3:31

Avatar de usuario de Peter Hoffmann
Pedro Hoffman

los *args y **kwargs es un modismo común para permitir un número arbitrario de argumentos a funciones como se describe en la sección más sobre la definición de funciones en la documentación de Python.

los *args le dará todos los parámetros de función como una tupla:

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

los **kwargs te daré todo
argumentos de palabras clave salvo las correspondientes a un parámetro formal como diccionario.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name="one", age=27)
# name one
# age 27

Ambos modismos se pueden mezclar con argumentos normales para permitir un conjunto de argumentos fijos y algunos variables:

def foo(kind, *args, **kwargs):
   pass

También es posible usar esto al revés:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Otro uso de la *l el idioma es para descomprimir listas de argumentos al llamar a una función.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

En Python 3 es posible usar *l en el lado izquierdo de una tarea (Desempaquetado Iterable Extendido), aunque da una lista en lugar de una tupla en este contexto:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

También Python 3 agrega nueva semántica (consulte PEP 3102):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Por ejemplo, lo siguiente funciona en Python 3 pero no en Python 2:

>>> x = [1, 2]
>>> [*x]
[1, 2]
>>> [*x, 3, 4]
[1, 2, 3, 4]

>>> x = {1:1, 2:2}
>>> x
{1: 1, 2: 2}
>>> {**x, 3:3, 4:4}
{1: 1, 2: 2, 3: 3, 4: 4}

Tal función acepta solo 3 argumentos posicionales, y todo lo que sigue * solo se pueden pasar como argumentos de palabra clave.

Nota:

  • una pitón dict, utilizados semánticamente para pasar argumentos de palabras clave, están ordenados arbitrariamente. Sin embargo, en Python 3.6, se garantiza que los argumentos de palabras clave recuerdan el orden de inserción.
  • “El orden de los elementos en **kwargs ahora corresponde al orden en que se pasaron los argumentos de palabra clave a la función”. – Novedades en Python 3.6
  • De hecho, todos los dictados en CPython 3.6 recordarán el orden de inserción como un detalle de implementación, esto se vuelve estándar en Python 3.7.

Avatar de usuario de Lorin Hochstein
Lorin Hochstein

También vale la pena señalar que puedes usar * y ** al llamar a funciones también. Este es un atajo que le permite pasar múltiples argumentos a una función directamente usando una lista/tupla o un diccionario. Por ejemplo, si tiene la siguiente función:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Puedes hacer cosas como:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Nota: Las teclas en mydict tienen que ser nombrados exactamente como los parámetros de la función foo. De lo contrario, arrojará un TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'

avatar de usuario de nickd
mella

El solo * significa que puede haber cualquier número de argumentos posicionales adicionales. foo() se puede invocar como foo(1,2,3,4,5). En el cuerpo de foo() param2 hay una secuencia que contiene 2-5.

El doble ** significa que puede haber cualquier número de parámetros adicionales con nombre. bar() se puede invocar como bar(1, a=2, b=3). En el cuerpo de bar() param2 hay un diccionario que contiene {‘a’:2, ‘b’:3 }

Con el siguiente código:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

la salida es

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}

Rusia debe eliminar el avatar de usuario de Putin
Rusia debe sacar a Putin

Que hace ** (doble estrella) y * (estrella) hacer para los parámetros?

Ellos permiten funciones por definir para aceptar y para usuarios a pasar cualquier número de argumentos, posicionales (*) y palabra clave (**).

Definición de funciones

*args permite cualquier número de argumentos posicionales opcionales (parámetros), que se asignarán a una tupla denominada args.

**kwargs permite cualquier número de argumentos de palabras clave opcionales (parámetros), que estarán en un dict llamado kwargs.

Puede (y debe) elegir cualquier nombre apropiado, pero si la intención es que los argumentos sean de semántica no específica, args y kwargs son nombres estándar.

Expansión, pasando cualquier número de argumentos

También puedes usar *args y **kwargs para pasar parámetros de listas (o cualquier iterable) y dictados (o cualquier mapeo), respectivamente.

La función que recibe los parámetros no tiene que saber que se están expandiendo.

Por ejemplo, el xrange de Python 2 no espera explícitamente *argspero como toma 3 enteros como argumentos:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

Como otro ejemplo, podemos usar la expansión dict en str.format:

>>> foo = 'FOO'
>>> bar="BAR"
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Nuevo en Python 3: definición de funciones con argumentos de solo palabras clave

Tu puedes tener argumentos solo de palabra clave después de la *args – por ejemplo, aquí, kwarg2 debe proporcionarse como un argumento de palabra clave, no posicionalmente:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Uso:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar="bar", baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

También, * puede usarse por sí mismo para indicar que siguen argumentos de solo palabra clave, sin permitir argumentos posicionales ilimitados.

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Aquí, kwarg2 de nuevo debe ser un argumento de palabra clave con nombre explícito:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar="bar")
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

Y ya no podemos aceptar argumentos posicionales ilimitados porque no tenemos *args*:

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar="bar")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Nuevamente, más simplemente, aquí requerimos kwarg ser dado por nombre, no posicionalmente:

def bar(*, kwarg=None): 
    return kwarg

En este ejemplo, vemos que si tratamos de pasar kwarg posicionalmente, obtenemos un error:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

Debemos pasar explícitamente el kwarg parámetro como argumento de palabra clave.

>>> bar(kwarg='kwarg')
'kwarg'

Demostraciones compatibles con Python 2

*args (típicamente dicho “star-args”) y **kwargs (las estrellas pueden implicarse al decir “kwargs”, pero sea explícito con “kwargs de doble estrella”) son modismos comunes de Python para usar el * y ** notación. Estos nombres de variables específicas no son necesarios (por ejemplo, podría usar *foos y **bars), pero es probable que una desviación de la convención enfurezca a sus compañeros codificadores de Python.

Por lo general, los usamos cuando no sabemos qué va a recibir nuestra función o cuántos argumentos podemos pasar y, a veces, incluso cuando se nombra cada variable por separado, se vuelve muy complicado y redundante (pero este es un caso en el que generalmente explícito es mejor que implícito).

Ejemplo 1

La siguiente función describe cómo se pueden usar y demuestra el comportamiento. Tenga en cuenta el nombre b el argumento será consumido por el segundo argumento posicional antes:

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))

Podemos consultar la ayuda en línea para la firma de la función, con help(foo)que nos dice

foo(a, b=10, *args, **kwargs)

Llamemos a esta función con foo(1, 2, 3, 4, e=5, f=6, g=7)

que imprime:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

Ejemplo 2

También podemos llamarlo usando otra función, en la que solo proporcionamos a:

def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 

bar(100) huellas dactilares:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Ejemplo 3: uso práctico en decoradores

Bien, tal vez aún no estemos viendo la utilidad. Así que imagina que tienes varias funciones con código redundante antes y/o después del código diferenciador. Las siguientes funciones nombradas son solo pseudocódigo con fines ilustrativos.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on

Es posible que podamos manejar esto de manera diferente, pero ciertamente podemos extraer la redundancia con un decorador, por lo que nuestro ejemplo a continuación demuestra cómo *args y **kwargs puede ser muy útil:

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

Y ahora cada función envuelta se puede escribir de manera mucho más sucinta, ya que eliminamos la redundancia:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

Y al factorizar nuestro código, que *args y **kwargs nos permite hacer, reducimos las líneas de código, mejoramos la legibilidad y el mantenimiento, y tenemos ubicaciones canónicas únicas para la lógica en nuestro programa. Si necesitamos cambiar alguna parte de esta estructura, tenemos un lugar en el que hacer cada cambio.

avatar de usuario de mrtechmaker
mrtechmaker

Primero comprendamos qué son los argumentos posicionales y los argumentos de palabras clave. A continuación se muestra un ejemplo de definición de función con Argumentos posicionales.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Así que esta es una definición de función con argumentos posicionales. También puede llamarlo con palabras clave/argumentos con nombre:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Ahora estudiemos un ejemplo de definición de función con argumentos de palabras clave:

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

También puede llamar a esta función con argumentos posicionales:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Así que ahora conocemos definiciones de funciones con argumentos posicionales y de palabras clave.

Ahora estudiemos el operador ‘*’ y el operador ‘**’.

Tenga en cuenta que estos operadores se pueden utilizar en 2 áreas:

a) Llamada de función

b) definición de función

El uso del operador ‘*’ y el operador ‘**’ en Llamada de función.

Vayamos directamente a un ejemplo y luego discutámoslo.

def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.

Así que recuerda

cuando se utiliza el operador ‘*’ o ‘**’ en un Llamada de función

El operador ‘*’ descomprime la estructura de datos, como una lista o una tupla, en los argumentos necesarios para la definición de la función.

El operador ‘**’ descomprime un diccionario en los argumentos necesarios para la definición de la función.

Ahora estudiemos el uso del operador ‘*’ en definición de función. Ejemplo:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

En función definición el operador ‘*’ empaqueta los argumentos recibidos en una tupla.

Ahora veamos un ejemplo de ‘**’ usado en la definición de función:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

En función definición El operador ‘**’ empaqueta los argumentos recibidos en un diccionario.

Así que recuerda:

en un Llamada de función la ‘*’ desempaqueta estructura de datos de tupla o lista en argumentos posicionales o de palabra clave para ser recibidos por definición de función.

en un Llamada de función la ‘**’ desempaqueta estructura de datos del diccionario en argumentos posicionales o de palabras clave para ser recibidos por definición de función.

en un definición de función la ‘*’ paquetes argumentos posicionales en una tupla.

en un definición de función la ‘**’ paquetes argumentos de palabras clave en un diccionario.

Esta tabla es útil para usar * y ** en función construcción y función llamar:

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Esto realmente solo sirve para resumir la respuesta de Lorin Hochstein, pero me parece útil.

Relacionado: los usos de los operadores estrella/splat han sido expandido en pitón 3

Avatar de usuario de Bill the Lizard
Bill el lagarto

* y ** tienen un uso especial en la lista de argumentos de la función. *
implica que el argumento es una lista y ** implica que el argumento es un diccionario. Esto permite que las funciones tomen un número arbitrario de argumentos.

¿Ha sido útil esta solución?