Si tomamos b = [1,2,3]
y tratamos de hacer:b+=(4,)
Regresa b = [1,2,3,4]
, pero si intentamos hacerlo b = b + (4,)
no funciona.
b = [1,2,3]
b+=(4,) # Prints out b = [1,2,3,4]
b = b + (4,) # Gives an error saying you can't add tuples and lists
Esperaba b+=(4,)
fallar ya que no puedes agregar una lista y una tupla, pero funcionó. Así que intenté b = b + (4,)
esperar obtener el mismo resultado, pero no funcionó.
python
python-3.x
list
tuples
Supun Dasantha Kuruppu
fuente
fuente
Respuestas:
El problema con las preguntas de "por qué" es que generalmente pueden significar varias cosas diferentes. Trataré de responder a cada una que creo que tengas en mente.
"¿Por qué es posible que funcione de manera diferente?" lo cual es respondido por ej . esto . Básicamente,
+=
trata de usar diferentes métodos del objeto:__iadd__
(que solo está marcado en el lado izquierdo), vs__add__
y__radd__
("suma inversa", marcado en el lado derecho si el lado izquierdo no tiene__add__
) para+
."¿Qué hace exactamente cada versión?" En resumen, el
list.__iadd__
método hace lo mismo quelist.extend
(pero debido al diseño del lenguaje, todavía hay una asignación de vuelta).Esto también significa, por ejemplo, que
+
, por supuesto, crea un nuevo objeto, pero explícitamente requiere otra lista en lugar de intentar extraer elementos de una secuencia diferente."¿Por qué es útil que + = haga esto? Es más eficiente; el
extend
método no tiene que crear un nuevo objeto. Por supuesto, esto tiene algunos efectos sorprendentes a veces (como arriba), y en general Python no se trata realmente de eficiencia , pero estas decisiones se tomaron hace mucho tiempo."¿Cuál es la razón para no permitir agregar listas y tuplas con +?" Ver aquí (gracias, @ splash58); Una idea es que (tupla + lista) debería producir el mismo tipo que (lista + tupla), y no está claro de qué tipo debería ser el resultado.
+=
no tiene este problema, porquea += b
obviamente no debería cambiar el tipo dea
.fuente
|
, así que eso arruina un poco mi ejemplo. Si más tarde pienso en un ejemplo más claro, lo cambiaré.|
para conjuntos es un operador de conmutación, pero+
para las listas no lo es. Por esa razón, no creo que el argumento sobre la ambigüedad de tipo sea particularmente fuerte. Dado que el operador no conmuta, ¿por qué requerir lo mismo para los tipos? Uno podría estar de acuerdo en que el resultado tiene el tipo de lhs. Por otro lado, al restringirlist + iterator
, se alienta al desarrollador a ser más explícito sobre su intención. Si desea crear una nueva lista que contiene el material dea
extenderse por las cosas deb
que ya hay una manera de hacer esto:new = a.copy(); new += b
. Es una línea más pero cristalina.a += b
comporta de manera diferente quea = a + b
no es la eficiencia. En realidad, Guido consideró el comportamiento elegido menos confuso. Imagine una función que recibe una listaa
como argumento y luego lo hacea += [1, 2, 3]
. Esta sintaxis ciertamente parece que está modificando la lista en su lugar, en lugar de crear una nueva lista, por lo que se tomó la decisión de que debería comportarse de acuerdo con la intuición de la mayoría de las personas sobre el resultado esperado. Sin embargo, el mecanismo también tuvo que funcionar para tipos inmutables comoint
s, lo que condujo al diseño actual.a += b
una taquigrafíaa = a + b
, como lo hizo Ruby, pero puedo entender cómo llegamos allí.No son equivalentes:
es la abreviatura de:
mientras
+
concatena listas, entonces por:intentas concatenar una tupla en una lista
fuente
Cuando haces esto:
se convierte a esto:
Debajo del capó que llama
b.extend((4,))
,extend
acepta un iterador y por eso también funciona:pero cuando haces esto:
se convierte a esto:
aceptar solo objeto de lista.
fuente
De los documentos oficiales, para los tipos de secuencia mutable, ambos:
se definen como:
Lo cual es diferente de ser definido como:
Esto también significa que cualquier tipo de secuencia funcionará
t
, incluida una tupla como en su ejemplo.¡Pero también funciona para rangos y generadores! Por ejemplo, también puedes hacer:
fuente
Los operadores de asignación "aumentada" como
+=
se introdujeron en Python 2.0, que se lanzó en octubre de 2000. El diseño y la justificación se describen en PEP 203 . Uno de los objetivos declarados de estos operadores era el apoyo de las operaciones en el lugar. Escriturase supone que actualiza la lista
a
en su lugar . Esto es importante si hay otras referencias a la listaa
, por ejemplo, cuándoa
se recibió como argumento de función.Sin embargo, la operación no siempre puede ocurrir en el lugar, ya que muchos tipos de Python, incluidos los enteros y las cadenas, son inmutables , por lo que, por ejemplo,
i += 1
un enteroi
no puede funcionar en su lugar.En resumen, se suponía que los operadores de asignación aumentada trabajarían en su lugar cuando fuera posible y, de lo contrario, crearían un nuevo objeto. Para facilitar estos objetivos de diseño,
x += y
se especificó que la expresión se comportara de la siguiente manera:x.__iadd__
se define,x.__iadd__(y)
se evalúa.x.__add__
se implementax.__add__(y)
se evalúa.y.__radd__
se implementay.__radd__(x)
se evalúa.El primer resultado obtenido por este proceso se asignará nuevamente a
x
(a menos que ese resultado sea elNotImplemented
singleton, en cuyo caso la búsqueda continúa con el siguiente paso).Este proceso permite la implementación de tipos que admiten la modificación en el lugar
__iadd__()
. Los tipos que no admiten la modificación en el lugar no necesitan agregar ningún método mágico nuevo, ya que Python recurrirá automáticamente a esencialmentex = x + y
.Así que finalmente lleguemos a su pregunta real: por qué puede agregar una tupla a una lista con un operador de asignación aumentada. De memoria, la historia de esto fue más o menos así: el
list.__iadd__()
método se implementó simplemente para llamar allist.extend()
método ya existente en Python 2.0. Cuando se introdujeron los iteradores en Python 2.1, ellist.extend()
método se actualizó para aceptar iteradores arbitrarios. El resultado final de estos cambios fue quemy_list += my_tuple
funcionó a partir de Python 2.1. Ellist.__add__()
método, sin embargo, nunca se debe apoyar iteradores arbitrarias como el argumento de la derecha - esto fue considerado inapropiado para un lenguaje fuertemente tipado.Personalmente, creo que la implementación de operadores aumentados terminó siendo demasiado compleja en Python. Tiene muchos efectos secundarios sorprendentes, por ejemplo, este código:
La segunda línea se eleva
TypeError: 'tuple' object does not support item assignment
, pero la operación se realiza con éxito de todos modos ,t
será([42, 44], [43])
después de ejecutar la línea que genera el error.fuente
La mayoría de la gente esperaría que X + = Y sea equivalente a X = X + Y. De hecho, la Referencia de bolsillo de Python (4ª edición) de Mark Lutz dice en la página 57 "Los siguientes dos formatos son más o menos equivalentes: X = X + Y, X + = Y ". Sin embargo, las personas que especificaron Python no los hicieron equivalentes. Posiblemente fue un error que resultará en horas de tiempo de depuración por parte de programadores frustrados durante el tiempo que Python permanezca en uso, pero ahora es como Python lo es. Si X es un tipo de secuencia mutable, X + = Y es equivalente a X.extend (Y) y no a X = X + Y.
fuente
Como se explica aquí , si
array
no implementa el__iadd__
método,b+=(4,)
sería una falta de personal,b = b + (4,)
pero obviamente no lo es, también loarray
hace el__iadd__
método de implementación . Aparentemente, la implementación del__iadd__
método es algo como esto:Sin embargo, sabemos que el código anterior no es la implementación real del
__iadd__
método, pero podemos suponer y aceptar que hay algo parecido alextend
método, que aceptatupple
entradas.fuente