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

2352

En las siguientes definiciones de métodos, lo que hace el *y **hacer por param2?

def foo(param1, *param2):
def bar(param1, **param2):
Todd
fuente
44
ver también stackoverflow.com/questions/6967632/…
Aaron Hall
Consulte también stackoverflow.com/questions/14301967/… para ver un asterisco
simple
24
Esta pregunta es un objetivo duplicado muy popular, pero desafortunadamente a menudo se usa incorrectamente. Tenga en cuenta que esta pregunta se refiere a la definición de funciones con varargs ( def func(*args)). Para una pregunta sobre qué significa en llamadas a funciones ( func(*[1,2])), consulte aquí . Para una pregunta sobre cómo desempaquetar listas de argumentos, vea aquí . Para una pregunta que pregunta qué *significa en literales ( [*[1, 2]]) ver aquí .
Aran-Fey
Puede obtener información sobre su uso en la definición de funciones y llame a la función aquí: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Respuestas:

2239

El *argsy **kwargses un idioma común para permitir un número arbitrario de argumentos para funciones como se describe en la sección más sobre la definición de funciones en la documentación de Python.

El *argsle dará todos los parámetros de la función como una tupla :

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

foo(1)
# 1

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

Le **kwargsdará todos los argumentos de palabras clave, excepto los correspondientes a un parámetro formal como diccionario.

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

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

Ambos modismos pueden mezclarse 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 del *lidioma es desempaquetar listas de argumentos cuando se llama a una función.

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

l = [1,2]

foo(*l)
# 1 2

En Python 3 es posible usarlo *len el lado izquierdo de una tarea ( Desembalaje extendido iterable ), aunque en este contexto proporciona una lista en lugar de una tupla:

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

Dicha función acepta solo 3 argumentos posicionales, y todo lo que sigue *solo puede pasarse como argumentos de palabras clave.

Peter Hoffmann
fuente
99
La salida de [6] está en orden inverso. name one age 27
thanos.a
54
@ thanos.a Los dictados de Python, utilizados semánticamente para pasar argumentos de palabras clave, se ordenan arbitrariamente. Sin embargo, en Python 3.6, se garantiza que los argumentos de palabras clave recordarán el orden de inserción. "El orden de los elementos **kwargsahora corresponde al orden en que los argumentos de palabras clave se pasaron a la función". - docs.python.org/3/whatsnew/3.6.html De hecho, todos los dictados en CPython 3.6 recordarán el orden de inserción como un detalle de implementación, esto se convierte en estándar en Python 3.7.
Aaron Hall
13
Muy preciso, limpio y fácil de entender. Le agradezco que haya notado que se trata de un "operador de desempaque", por lo que podría diferenciarme de pasar por referencia en C. +1
bballdave025
¿Cómo probar la última función con PEP 3102? Lo llamo con func (1,2,3, name = "me", age = 10) y arroja una excepción:got an unexpected keyword argument 'name'
Kok How Teh
@KokHowTeh Debe pasar los kwargs nombrados como están en la función: func (1, 2, 3, kwarg1 = 'me', kwarg2 = 10)
John Aaron
622

También vale la pena señalar que puede usar *y **al llamar funciones también. Este es un acceso directo 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 mydictdeben nombrarse 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'
Lorin Hochstein
fuente
175

El * simple 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 es una secuencia que contiene 2-5.

El doble ** significa que puede haber cualquier número de parámetros con nombre adicionales. 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}
nickd
fuente
55
Quizás foobar(param1, *param2, **param3)se necesite un ejemplo adicional con para completar esta respuesta.
Aniket Thakur
1
@AniketThakur agregó la parte restante aquí .
Raj
148

¿Qué hacen **(estrella doble) y *(estrella) para los parámetros?

Permiten que las funciones se definan para aceptar y que los usuarios pasen cualquier número de argumentos, posicionales ( *) y palabras clave ( **).

Definiendo funciones

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

**kwargspermite cualquier número de argumentos de palabra clave opcionales (parámetros), que estarán en un dict con nombre kwargs.

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

Expansión, pasando cualquier número de argumentos

También puede usar *argsy **kwargspasar 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, xrange de Python 2 no espera explícitamente *args, pero dado que 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

Puede tener argumentos de solo palabras clave después de *args, por ejemplo, aquí, kwarg2debe darse como argumento de palabras 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'})

Además, *se puede usar solo para indicar que siguen los argumentos de palabras clave, sin permitir argumentos posicionales ilimitados.

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

Aquí, kwarg2nuevamente debe haber un argumento de palabra clave explícitamente nombrado:

>>> 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

De nuevo, más simplemente, aquí necesitamos kwargque se nos dé por nombre, no por posición:

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

En este ejemplo, vemos que si intentamos pasar kwargposicionalmente, 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 kwargparámetro como argumento de palabra clave.

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

Demos compatibles con Python 2

*args(normalmente se dice "star-args") y **kwargs(las estrellas pueden estar implícitas diciendo "kwargs", pero sea explícito con "double-star kwargs") son expresiones idiomáticas comunes de Python para usar la notación *y **. Estos nombres de variables específicos no son obligatorios (por ejemplo, podría usar *foosy **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 estar pasando, y a veces incluso cuando nombrar cada variable por separado se volvería muy desordenada y redundante (pero este es un caso donde generalmente es explícito mejor que implícito).

Ejemplo 1

La siguiente función describe cómo se pueden usar y demuestra el comportamiento. Tenga en cuenta que el bargumento nombrado 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, quizás aún no estemos viendo la utilidad. Imagine que tiene 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 siguiente ejemplo demuestra cómo *argsy **kwargspuede 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 tenemos en cuenta 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 por factorización de nuestro código, el cual *args, y **kwargsnos permite hacer, podemos reducir líneas de código, mejorar la legibilidad y facilidad de mantenimiento, y tienen lugares únicos canó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.

Aaron Hall
fuente
48

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

Entonces esta es una definición de función con argumentos posicionales. También puede llamarlo con palabras clave / argumentos nombrados:

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 sabemos 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 la llamada a la función.

Vayamos directamente a un ejemplo y luego discutamos.

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 el operador '*' o '**' se usa en una llamada a función -

El operador '*' desempaqueta la estructura de datos como una lista o tupla en argumentos necesarios para la definición de la función.

El operador '**' desempaqueta un diccionario en argumentos necesarios para la definición de la función.

Ahora estudiemos el uso del operador '*' en la definición de funciones . 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 la definición de la funció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 la definición de la función El operador '**' empaqueta los argumentos recibidos en un diccionario.

Así que recuerda:

En una llamada a función, el '*' descomprime la estructura de datos de tupla o lista en argumentos posicionales o de palabras clave que se recibirán por definición de función.

En una llamada a función, el '**' descomprime la estructura de datos del diccionario en argumentos posicionales o de palabras clave que se recibirán por definición de función.

En una definición de función, el '*' agrupa argumentos posicionales en una tupla.

En una definición de función, '**' incluye argumentos de palabras clave en un diccionario.

Karan Ahuja
fuente
¡Explicación realmente limpia, paso a paso y fácil de seguir!
Aleksandar
gracias Mantenga los votos a favor. [También para más notas mías, estoy en @mrtechmaker en twitter]
Karan Ahuja
32

Esta tabla es útil para usar *y **en la construcción de funciones y llamadas a funciones :

            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 sirve para resumir la respuesta de Lorin Hochstein, pero me parece útil.

Relacionado: los usos para los operadores estrella / splat se han ampliado en Python 3

Brad Solomon
fuente
22

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

ronak
fuente
17

¡Para aquellos de ustedes que aprenden con ejemplos!

  1. El propósito de * es darle la capacidad de definir una función que puede tomar un número arbitrario de argumentos proporcionados como una lista (por ejemplo f(*myList)).
  2. El propósito de **es darle la capacidad de alimentar los argumentos de una función proporcionando un diccionario (por ejemplo f(**{'x' : 1, 'y' : 2})).

Vamos a mostrar esto definiendo una función que toma dos variables normales x, yy puede aceptar más argumentos myArgs, y puede aceptar aún más argumentos myKW. Más adelante, mostraremos cómo alimentar yusando myArgDict.

def f(x, y, *myArgs, **myKW):
    print("# x      = {}".format(x))
    print("# y      = {}".format(y))
    print("# myArgs = {}".format(myArgs))
    print("# myKW   = {}".format(myKW))
    print("# ----------------------------------------------------------------------")

# Define a list for demonstration purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("myEx", *myList, **myDict)
# x      = myEx
# y      = Left
# myArgs = ('Right', 'Up', 'Down')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# y is matched and fed first
# The rest of myArgDict becomes additional arguments feeding myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
# x      = myEx
# y      = 4
# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# Without the stars, the entire provided list and dict become x, and y:
f(myList, myDict)
# x      = ['Left', 'Right', 'Up', 'Down']
# y      = {'Wubba': 'lubba', 'Dub': 'dub'}
# myArgs = ()
# myKW   = {}
# ----------------------------------------------------------------------

Advertencias

  1. ** está reservado exclusivamente para diccionarios.
  2. La asignación de argumento no opcional ocurre primero.
  3. No puede usar un argumento no opcional dos veces.
  4. Si corresponde, **debe venir después *, siempre.
Miladiosos
fuente
14

De la documentación de Python:

Si hay más argumentos posicionales que ranuras de parámetros formales, se genera una excepción TypeError, a menos que esté presente un parámetro formal que use la sintaxis "* identificador"; en este caso, ese parámetro formal recibe una tupla que contiene los argumentos posicionales en exceso (o una tupla vacía si no hubo argumentos posicionales en exceso).

Si algún argumento de palabra clave no corresponde a un nombre de parámetro formal, se genera una excepción TypeError, a menos que esté presente un parámetro formal que usa la sintaxis "** identificador"; en este caso, ese parámetro formal recibe un diccionario que contiene el exceso de argumentos de palabras clave (usando las palabras clave como claves y los valores de argumento como valores correspondientes), o un (nuevo) diccionario vacío si no hubo argumentos de palabras clave en exceso.

Chris Upchurch
fuente
10

* significa recibir argumentos variables como tupla

** significa recibir argumentos variables como diccionario

Usado de la siguiente manera:

1) soltero *

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

foo("two", 3)

Salida:

two
3

2) ahora **

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

bar(dic1="two", dic2=3)

Salida:

dic1 two
dic2 3
ishandutta2007
fuente
8

Quiero dar un ejemplo que otros no hayan mencionado

* también puede desempaquetar un generador

Un ejemplo del documento Python3

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x será [1, 2, 3], unzip_y será [4, 5, 6]

El zip () recibe múltiples argumentos irritables y devuelve un generador.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
Lochu'an Chang
fuente
7

En Python 3.5, también se puede utilizar esta sintaxis en list, dict, tuple, y setmuestra (también llamado a veces literales). Ver PEP 488: Generalizaciones adicionales de desempaque .

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

También permite desempaquetar múltiples iterables en una sola llamada de función.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(Gracias a mgilson por el enlace PEP).

leewz
fuente
1
No estoy seguro de que esto sea una violación de "solo hay una forma de hacerlo". No hay otra forma de inicializar una lista / tupla de múltiples iterables: actualmente debe encadenarlos en un solo iterable que no siempre es conveniente. Puedes leer sobre lo racional en PEP-0448 . Además, esta no es una característica de python3.x, es una característica de python3.5 + :-).
mgilson
@mgilson, eso explicaría por qué no se mencionó antes.
leewz
6

Además de las llamadas a funciones, * args y ** kwargs son útiles en las jerarquías de clases y también evitan tener que escribir el __init__método en Python. Se puede ver un uso similar en marcos como el código Django.

Por ejemplo,

def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])

Una subclase puede ser

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

La subclase se instanciará como

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

Además, una subclase con un nuevo atributo que solo tiene sentido para esa instancia de subclase puede llamar a la clase Base __init__para descargar la configuración de atributos. Esto se hace a través de * args y ** kwargs. kwargs se usa principalmente para que el código sea legible utilizando argumentos con nombre. Por ejemplo,

class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)

que se puede instaurar como

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

El código completo está aquí.

quiet_penguin
fuente
1
1. Básicamente init es un método, por lo que (en este contexto) no es realmente diferente. 2. Use # para comentarios, no "" ", que solo marca cadenas literales. 3. Usar super debería ser la forma preferida, especialmente para su ejemplo con herencia de niveles múltiples.
0xc0de
4

Sobre la base de la respuesta de Nickd ...

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


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


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Salida:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

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

Básicamente, cualquier número de argumentos posicionales puede usar * args y cualquier argumento con nombre (o kwargs, también conocido como argumentos de palabras clave) puede usar ** kwargs.

Raj
fuente
3

*argsy **kwargs: le permite pasar un número variable de argumentos a una función.

*args: se utiliza para enviar una lista de argumentos de longitud variable sin palabras clave a la función:

def args(normal_arg, *argv):
    print("normal argument:", normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals', 'fish', 'duck', 'bird')

Producirá:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

**kwargsle permite pasar una longitud variable de argumentos con clave a una función. Debe usarlo **kwargssi desea manejar argumentos con nombre en una función.

def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print("Your %s is %s." % (key, value))

who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  

Producirá:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
Harvey
fuente
2

Este ejemplo lo ayudaría a recordar *args, **kwargse incluso a superheredar en Python a la vez.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1
Thanhtang
fuente
1

Un buen ejemplo del uso de ambos en una función es:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}
amir jj
fuente
1

TL; DR

A continuación se presentan 6 casos de uso diferentes para *y **en la programación de Python:

  1. Para aceptar cualquier número de argumentos posicionales usando *args:, def foo(*args): pass aquí fooacepta cualquier número de argumentos posicionales, es decir, las siguientes llamadas son válidas foo(1),foo(1, 'bar')
  2. Para aceptar cualquier número de argumentos de palabras clave utilizando **kwargs:, def foo(**kwargs): pass aquí 'foo' acepta cualquier número de argumentos de palabras clave, es decir, las siguientes llamadas son válidas foo(name='Tom'),foo(name='Tom', age=33)
  3. Para aceptar cualquier número de argumentos posicionales y de palabras clave utilizando *args, **kwargs:, def foo(*args, **kwargs): pass aquí fooacepta cualquier número de argumentos posicionales y de palabras clave, es decir, las siguientes llamadas son válidas foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Para hacer cumplir los argumentos de solo palabras clave usando *:, def foo(pos1, pos2, *, kwarg1): pass aquí *significa que foo solo acepta argumentos de palabras clave después de pos2, por lo tanto, foo(1, 2, 3)genera TypeError pero foo(1, 2, kwarg1=3)está bien.
  5. Para no expresar más interés en más argumentos posicionales usando *_(Nota: esto es solo una convención): def foo(bar, baz, *_): pass significa (por convención) foosolo usa bary bazargumentos en su funcionamiento e ignorará a los demás.
  6. Para no expresar más interés en más argumentos de palabras clave usando \**_(Nota: esto es solo una convención): def foo(bar, baz, **_): pass significa (por convención) foosolo usa bary bazargumentos en su funcionamiento e ignorará a los demás.

BONIFICACIÓN: desde Python 3.8 en adelante, se puede usar /en la definición de funciones para imponer parámetros solo posicionales. En el siguiente ejemplo, los parámetros a y b son solo posicionales , mientras que c o d pueden ser posicionales o palabras clave, y se requiere que eof sean palabras clave:

def f(a, b, /, c, d, *, e, f):
    pass
Meysam Sadeghi
fuente
0

TL; DR

Empaqueta argumentos pasados ​​a la función dentro listy dictrespectivamente dentro del cuerpo de la función. Cuando define una firma de función como esta:

def func(*args, **kwds):
    # do stuff

Se puede llamar con cualquier número de argumentos y argumentos de palabras clave. Los argumentos que no son palabras clave se empaquetan en una lista llamada argsdentro del cuerpo de la función y los argumentos de las palabras clave se empaquetan en un dict llamado kwdsdentro del cuerpo de la función.

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

ahora dentro del cuerpo de la función, cuando se llama a la función, hay dos variables locales, argsque es una lista que tiene valor ["this", "is a list of", "non-keyword", "arguments"]y kwdsque es un dictvalor que tiene{"keyword" : "ligma", "options" : [1,2,3]}


Esto también funciona a la inversa, es decir, desde el lado de la persona que llama. por ejemplo si tiene una función definida como:

def f(a, b, c, d=1, e=10):
    # do stuff

puede llamarlo desempacando iterables o asignaciones que tenga en el alcance de la llamada:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)
RBF06
fuente
0

Contexto

  • python 3.x
  • desempacando con **
  • utilizar con formato de cadena

Usar con formato de cadena

Además de las respuestas en este hilo, aquí hay otro detalle que no se mencionó en otra parte. Esto amplía la respuesta de Brad Solomon

Desempacar con **también es útil cuando se usa python str.format.

Esto es algo similar a lo que puede hacer con python f-strings f-string pero con la sobrecarga adicional de declarar un dict para contener las variables (f-string no requiere un dict).

Ejemplo rapido

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.append('''
  Hello {fname} {lname}!

  Today you are {age} years old!

  We love your motto "{motto}" and we agree with you!
  '''.format(**ddvars)) 
  pass

  ## ********************
  ## multiple unpack supported in py 3.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])
dreftymac
fuente
-2
  • def foo(param1, *param2):es un método que puede aceptar un número arbitrario de valores para *param2,
  • def bar(param1, **param2): es un método que puede aceptar un número arbitrario de valores con claves para *param2
  • param1 Es un parámetro simple.

Por ejemplo, la sintaxis para implementar varargs en Java de la siguiente manera:

accessModifier methodName(datatype arg) {
    // method body
}
Premraj
fuente