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


En las siguientes definiciones de métodos, ¿qué hace el * y ** hacer para param2?

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

1574
2017-08-31 15:04


origen


Respuestas:


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

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

In [1]: def foo(*args):
   ...:     for a in args:
   ...:         print a
   ...:         
   ...:         

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

los **kwargs te dará todo argumentos de palabra clave excepto los que corresponden a un parámetro formal como un diccionario.

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

In [6]: 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

Otro uso de la *l idioma es para desempaquetar listas de argumentos cuando llamas a una función.

In [9]: def foo(bar, lee):
   ...:     print bar, lee
   ...:     
   ...:     

In [10]: l = [1,2]

In [11]: 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

Tal función acepta solo 3 argumentos posicionales, y todo después de * solo se puede pasar como argumentos de palabra clave.


1550
2017-08-31 15:17



También vale la pena señalar que puede usar * y ** al llamar 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 claves en mydict tiene que ser nombrado exactamente como los parámetros de la función foo. De lo contrario, lanzará 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'

448
2017-08-31 15:47



El single * significa que puede haber cualquier cantidad de argumentos posicionales adicionales. foo() puede invocarse 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 cantidad de parámetros adicionales nombrados. bar() puede invocarse 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}

128
2017-08-31 15:20



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

Permiten funciones que se definirán para aceptar y para usuarios a pasar cualquier cantidad de argumentos, posicional (*) 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 llamada args.

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

Puede (y debería) 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 cantidad de argumentos

También puedes usar *args y **kwargs pasar parámetros de listas (o cualquier iterable) y dicts (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 *args, pero ya 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 solo de palabras clave

Tu puedes tener solo palabras clave después de la *args - por ejemplo, aquí, kwarg2 debe darse como argumento 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 solo siguen los argumentos de 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 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í requerimos kwarg para 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 un argumento de palabra clave.

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

Demostraciones compatibles con Python 2

*args (típicamente dijo "star-args") y **kwargs (Las estrellas pueden ser implícitas diciendo "kwargs", pero explícitas con "kwargs de doble estrella") son expresiones comunes de Python para usar el * y ** notación. Estos nombres de variables específicos no son necesarios (por ejemplo, podría usar *foos y **bars), pero una desviación de la convención puede enfurecer a tus compañeros codificadores de Python.

Normalmente los utilizamos cuando no sabemos qué va a recibir nuestra función o cuántos argumentos podemos estar aprobando, y algunas veces incluso cuando nombrar cada variable por separado sería muy desordenado y redundante (pero este es un caso donde por lo general 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 el nombrado 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 verificar 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, a la que solo brindamos 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

OK, quizás todavía no veamos la utilidad. Entonces imagine que tiene varias funciones con código redundante antes y / o después del código de diferenciación. Las siguientes funciones nombradas son simplemente 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 envolvente puede escribirse mucho más sucintamente, ya que hemos tenido 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 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 donde realizar cada cambio.


105
2017-10-14 16:34



Primero, comprendamos qué son los argumentos posicionales y los argumentos de palabra 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 los argumentos de palabra clave / 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 palabra 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 las definiciones de funciones con argumentos posicionales así como palabras clave.

Ahora estudiemos el operador '*' y el operador '**'.

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

un) Llamada de función

segundo) definición de función

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

Vamos a ver directamente un ejemplo y luego discutirlo.

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 de función -

El operador '*' descomprime la estructura de datos, como una lista o 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 vamos a estudiar 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 '**' utilizado en la definición de funciones:

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 el '*' desempaquetar estructura de datos de tupla o una lista en argumentos posicionales o de palabra clave para ser recibidos por definición de función.

en un Llamada de función el '**' desempaquetar estructura de datos del diccionario en argumentos posicionales o de palabras clave para recibir por definición de función.

en un definición de función el '*' paquetes argumentos posicionales en una tupla.

en un definición de función el '**' paquetes argumentos de palabra clave en un diccionario.


37
2018-01-20 11:40



* y ** tener un uso especial en la lista de argumentos de funciones. * 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


20
2017-09-11 04:33



De la documentación de Python:

Si hay más argumentos posicionales que espacios de parámetros formales, se genera una excepción TypeError, a menos que exista un parámetro formal que utilice la sintaxis "* identifier"; 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 cualquier argumento de palabra clave no corresponde a un nombre de parámetro formal, se genera una excepción TypeError, a menos que exista un parámetro formal que utilice la sintaxis "** identificador"; en este caso, ese parámetro formal recibe un diccionario que contiene los argumentos de palabras clave sobrantes (utilizando las palabras clave como claves y los valores de los argumentos como valores correspondientes) o un (nuevo) diccionario vacío si no hubo argumentos de exceso de palabra clave.


11
2017-08-31 15:07



Quiero dar un ejemplo que otros no han mencionado

* también puede descomprimir 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 args iretables y devuelve un generador.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

7
2017-11-08 16:50



En Python 3.5, también puede usar esta sintaxis en list, dict, tupley set pantallas (también llamadas a veces literales). Ver PEP 488: generalizaciones de desempaquetado adicionales.

>>> (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 que múltiples iterables sean desempaquetados en una sola llamada de función.

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

(Gracias a mgilson por el enlace PEP).


6
2017-12-08 21:38



Si bien los usos para los operadores de estrella / splat han sido expandido en Python 3, me gusta la siguiente tabla en lo que se refiere al uso de estos operadores con funciones. El operador de splat puede usarse tanto dentro de la función construcción y en la función llamada:

            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 el de Lorin Hochstein responder pero lo encuentro útil.


6
2017-11-30 18:28