¿Qué significa el operador estrella? [duplicar]


Posible Duplicado:
¿Qué significa *args y * * kwargs?

¿Qué significa el operador * en Python, como en código como zip(*x) o f(**k)?

  1. ¿Cómo se maneja internamente en el intérprete?
  2. ¿Afecta en absoluto al rendimiento? Es rápido o lento?
  3. ¿Cuándo es útil y cuándo no?
  4. ¿Debería usarse en una declaración de función o en una llamada?
Author: Peter Mortensen, 2010-05-27

5 answers

La estrella única * descomprime la secuencia / colección en argumentos posicionales, por lo que puede hacer esto:

def sum(a, b):
    return a + b

values = (1, 2)

s = sum(*values)

Esto desempaquetará la tupla para que realmente se ejecute como:

s = sum(1, 2)

La doble estrella ** hace lo mismo, solo usando un diccionario y así llamados argumentos:

values = { 'a': 1, 'b': 2 }
s = sum(**values)

También puedes combinar:

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)

Se ejecutará como:

s = sum(1, 2, c=10, d=15)

Véase también la sección 4.7.4-Desempaquetar Listas de argumentos de la documentación de Python.


Además, puede definir funciones para tomar argumentos *x y **y, esto permite que una función acepte cualquier número de argumentos posicionales y/o con nombre que no estén específicamente nombrados en la declaración.

Ejemplo:

def sum(*values):
    s = 0
    for v in values:
        s = s + v
    return s

s = sum(1, 2, 3, 4, 5)

O con **:

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # returns 1

Esto le permite especificar un gran número de parámetros opcionales sin tener que declararlos.

Y de nuevo, puedes combinar:

def sum(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s

s = sum(1, 2, 3, 4, 5)            # returns 15
s = sum(1, 2, 3, 4, 5, neg=True)  # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15
 732
Author: Lasse Vågsæther Karlsen,
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
2014-08-28 04:18:55

Un pequeño punto: estos no son operadores. Los operadores se utilizan en expresiones para crear nuevos valores a partir de valores existentes (1+2 se convierte en 3, por ejemplo. El * y ** aquí son parte de la sintaxis de las declaraciones y llamadas a funciones.

 36
Author: Ned Batchelder,
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-05-27 16:43:37

Se llama sintaxis de llamada extendida. De la documentación :

Si la expresión syntax *aparece en la llamada a la función, la expresión debe evaluarse como una secuencia. Los elementos de esta secuencia se tratan como si fueran argumentos posicionales adicionales; si hay argumentos posicionales x1,..., xN, y la expresión evalúa a una secuencia y1,..., yM, esto es equivalente a una llamada con M + N argumentos posicionales x1, ..., xN, y1, ..., yM.

Y:

Si la expresión sintaxis **aparece en la llamada a la función, la expresión debe evaluar una asignación, cuyo contenido se trata como argumentos de palabra clave adicionales. En el caso de una palabra clave que aparece tanto en la expresión como en un argumento de palabra clave explícito, se genera una excepción TypeError.

 15
Author: Mark Byers,
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-05-27 15:00:57

Encuentro esto particularmente útil para cuando desea 'almacenar' una llamada a una función.

Por ejemplo, supongamos que tengo algunas pruebas unitarias para una función 'add':

def add(a, b): return a + b
tests = { (1,4):5, (0, 0):0, (-1, 3):3 }
for test, result in tests.items():
   print 'test: adding', test, '==', result, '---', add(*test) == result

No hay otra manera de llamar a add, aparte de hacer manualmente algo como add(test[0], test[1]), que es feo. Además, si hay un número variable de variables, el código podría ponerse bastante feo con todas las sentencias if que necesitaría.

Otro lugar que es útil es para definir objetos de fábrica (objetos que crean objetos para usted). Supongamos que tiene alguna fábrica de clase, que hace objetos de automóviles y los devuelve. Podrías hacerlo para que mi fábrica.make_car ('rojo',' bmw',' 335ix') crea Car ('rojo', 'bmw', '335ix'), luego lo devuelve.

def make_car(*args):
   return Car(*args)

Esto también es útil cuando se quiere llamar a un constructor de superclase.

 14
Author: Donald Miner,
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-05-27 18:45:34

En una llamada a función, la estrella simple convierte una lista en argumentos separados (por ejemplo, zip(*x) es lo mismo que zip(x1,x2,x3) si x=[x1,x2,x3]) y la estrella doble convierte un diccionario en argumentos de palabra clave separados (por ejemplo, f(**k) es lo mismo que f(x=my_x, y=my_y) si k = {'x':my_x, 'y':my_y}.

En una definición de función es al revés: la estrella simple convierte un número arbitrario de argumentos en una lista, y el inicio doble convierte un número arbitrario de argumentos de palabras clave en un diccionario. Por ejemplo, def foo(*x) significa " foo toma una arbitraria número de argumentos y serán accesibles a través de la lista x (es decir, si el usuario llama foo(1,2,3), x será [1,2,3]) "y def bar(**k) significa" bar toma un número arbitrario de argumentos de palabras clave y serán accesibles a través del diccionario k (es decir, si el usuario llama bar(x=42, y=23), k será {'x': 42, 'y': 23})".

 7
Author: sepp2k,
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-05-27 14:18:37