valores vacia una tuplas tupla obtener lista funciones extraer elementos datos crear como buscar acceder python tuples iterable-unpacking

vacia - obtener valores de una tupla python



Semántica del desempaquetado de la tupla en python. (6)

Algunas observaciones:

  1. Python procesa los argumentos posicionales antes de los argumentos de palabras clave ( f(c=3, *(1, 2)) en su ejemplo, aún se imprime 1 2 3 ). Esto tiene sentido ya que (i) la mayoría de los argumentos en las llamadas a funciones son posicionales y (ii) la semántica de un lenguaje de programación debe ser inequívoca (es decir, la elección debe hacerse de cualquier manera en el orden en que se procesan los argumentos posicionales y de palabras clave) ).
  2. Si tuviéramos un argumento posicional a la derecha en una llamada de función, sería difícil definir lo que eso significa. Si llamamos f(*(1, 2), 3) , ¿debería ser f(1, 2, 3) o f(3, 1, 2) y por qué cualquier opción tendría más sentido que la otra?
  3. Para una explicación oficial, PEP 3102 proporciona mucha información sobre cómo funcionan las definiciones de funciones. La estrella (*) en una definición de función indica el final de los argumentos de posición (sección Especificación ). Para ver por qué, considere: def g(a, b, *c, d) . No hay forma de proporcionar un valor para d no sea como un argumento de palabra clave (los argumentos posicionales serían ''grabados'' por c ).
  4. Es importante darse cuenta de lo que esto significa: cuando la estrella marca el final de los argumentos posicionales, eso significa que todos los argumentos posicionales deben estar en esa posición o a la izquierda de la misma.

¿Por qué python solo permite que los argumentos con nombre sigan una expresión de desempaquetado de tuplas en una llamada de función?

>>> def f(a,b,c): ... print a, b, c ... >>> f(*(1,2),3) File "<stdin>", line 1 SyntaxError: only named arguments may follow *expression

¿Es simplemente una elección estética, o hay casos en los que permitir esto llevaría a algunas ambigüedades?


En primer lugar, es simple proporcionar una interfaz muy similar utilizando una función de envoltura:

def applylast(func, arglist, *literalargs): return func(*(literalargs + arglist)) applylast(f, (1, 2), 3) # equivalent to f(3, 1, 2)

En segundo lugar, mejorar el intérprete para que admita su sintaxis de forma nativa puede agregar sobrecarga a la actividad muy crítica de la aplicación de la función. Incluso si solo requiere unas cuantas instrucciones adicionales en el código compilado, debido al alto uso de esas rutinas, eso podría constituir una penalización de rendimiento inaceptable a cambio de una característica que no es muy frecuente en una biblioteca de usuarios.


Estoy bastante seguro de que la razón por la que a las personas "naturalmente" no les gusta esto es porque hace que el significado de los argumentos posteriores sea ambiguo, dependiendo de la longitud de la serie interpolada:

def dangerbaby(a, b, *c): hug(a) kill(b) >>> dangerbaby(''puppy'', ''bug'') killed bug >>> cuddles = [''puppy''] >>> dangerbaby(*cuddles, ''bug'') killed bug >>> cuddles.append(''kitten'') >>> dangerbaby(*cuddles, ''bug'') killed kitten

no se puede decir con solo mirar las dos últimas llamadas a dangerbaby cuál funciona como se esperaba y cuál mata a la gatita fluffykins.

Por supuesto, parte de esta incertidumbre también está presente cuando se interpola al final. pero la confusión está restringida a la secuencia interpolada, no afecta a otros argumentos, como el bug .

[Hice una búsqueda rápida para ver si podía encontrar algo oficial. Parece que el prefijo * para varags se introdujo en Python 0.9.8 . La sintaxis anterior se discute aquí y las reglas de cómo funcionó fueron bastante complejas. ya que la adición de argumentos adicionales "tenía que" ocurrir al final cuando no había un marcador *, parece que eso simplemente continuó. finalmente, se menciona aquí una larga discusión sobre listas de argumentos que no fue por correo electrónico.]


Si tiene un parámetro de solo palabras clave de Python 3, como

def f(*a, b=1): ...

entonces puede esperar que algo como f(*(1, 2), 3) establezca a a (1 , 2) b a 3 , pero por supuesto, incluso si la sintaxis que desea está permitida, no lo haría, porque la palabra clave -Sólo los parámetros deben ser solo de palabra clave, como f(*(1, 2), b=3) . Si estuviera permitido, supongo que tendría que establecer a a (1, 2, 3) y dejar b como el valor predeterminado 1 . Entonces, tal vez no sea ambigüedad sintáctica sino ambigüedad en lo que se espera, que es algo que Python trata de evitar.


Sospecho que es por coherencia con la notación en estrella en las definiciones de funciones, que es, después de todo, el modelo para la notación en estrella en las llamadas a funciones.

En la siguiente definición, el parámetro *c absorberá todos los argumentos subsiguientes que no sean de palabras clave, por lo que, obviamente, cuando se llame a f , la única forma de pasar un valor para d será como un argumento de palabra clave.

def f(a, b, *c, d=1): print "slurped", len(c)

(Tales "parámetros de palabras clave solamente" solo se admiten en Python 3. En Python 2 no hay manera de asignar valores después de un argumento destacado, por lo que lo anterior es ilegal).

Por lo tanto, en una definición de función, el argumento destacado debe seguir todos los argumentos posicionales ordinarios. Lo que observaste es que la misma regla se ha extendido a las llamadas de función. De esta manera, la sintaxis en estrella es consistente para declaraciones de funciones y llamadas de funciones.

Otro paralelismo es que solo puede tener un argumento destacado (único) en una llamada a función. Lo siguiente es ilegal, aunque uno podría fácilmente imaginar que está permitido.

f(*(1,2), *(3,4))


cambiar el orden:

def f(c,a,b): print(a,b,c) f(3,*(1,2))