Pregunta

¿Qué hace la media 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 el rendimiento en absoluto? Es rápido o lento?
  3. ¿Cuándo es conveniente y cuando no es así?
  4. ¿Se debería usar en una declaración de la función o en una llamada?
¿Fue útil?

Solución

La única * estrellas descomprime la secuencia / recogida en argumentos posicionales, por lo que se puede hacer esto:

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

values = (1, 2)

s = sum(*values)

Esto desempaquetar la tupla por lo que en realidad se ejecuta como:

s = sum(1, 2)

La doble ** estrellas hace lo mismo, sólo que usando un diccionario y argumentos de este modo con nombre:

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

También se pueden combinar:

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

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

ejecutará como:

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

listas de argumentos Desembalaje de la documentación de Python.


Además, puede definir funciones para tomar *x y **y argumentos, esto permite una función para aceptar cualquier número de argumentos posicionales y / o con nombre que no citados específicamente 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 puede permitirle especificar un gran número de parámetros opcionales sin tener que declararlos.

Y de nuevo, se pueden 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

Otros consejos

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

Me parece esto particularmente útil para cuando se quiere 'tienda' una llamada de función.

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

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 forma de llamar a añadir, aparte de hacer manualmente algo como complemento (prueba [0], examen [1]), que es feo. Además, si hay un número variable de variables, el código podría ser bastante feo, con toda la sentencias if que se necesita.

Otro lugar esto es útil es para la definición de objetos de fábrica (objetos que crean objetos para usted). Suponga que tiene alguna clase de fábrica, que hace que los objetos y los vuelve coches. Se podía hacerlo de modo que myFactory.make_car ( 'rojo', 'BMW', '335ix') crea coche ( 'rojo', 'BMW', '335ix'), y luego lo devuelve.

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

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

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

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

y

Si la sintaxis ** aparece de expresión en la llamada de función, expresión deben evaluar a una asignación, los contenidos de los cuales son tratados como argumentos de palabra clave adicionales. En el caso de una palabra clave que aparece tanto en la expresión y como un argumento de palabra clave explícita, se eleva una excepción TypeError.

En una llamada a la función de la única estrella se vuelve una lista en discusiones separadas (por ejemplo zip(*x) es lo mismo que zip(x1,x2,x3) si x=[x1,x2,x3]) y la doble estrella se vuelve un diccionario en argumentos de palabras clave separadas (por ejemplo f(**k) es la misma que f(x=my_x, y=my_y) si k = {'x':my_x, 'y':my_y}.

En una definición de función que es al revés: la única estrella se vuelve un número arbitrario de argumentos en una lista, y el doble de arranque gira un número arbitrario de argumentos de palabra clave en un diccionario. P.ej. medios def foo(*x) "foo toma un número arbitrario de argumentos y que será accesible a través de la lista x (es decir, si el usuario llama foo(1,2,3), x será [1,2,3])" y medios def bar(**k) "bar toma un número arbitrario de argumentos de palabra clave y que será accesible a través de la k diccionario (es decir, si el usuario llama bar(x=42, y=23), k será {'x': 42, 'y': 23})".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top