Python: ¿Por qué no se admite la comparación entre listas y tuplas?

Al comparar una tupla con una lista como …

>>> [1,2,3] == (1,2,3) False >>> [1,2,3].__eq__((1,2,3)) NotImplemented >>> (1,2,3).__eq__([1,2,3]) NotImplemented 

Python no los compara en profundidad como se hace con (1,2,3) == (1,2,3) .

Entonces, ¿cuál es la razón de esto? ¿Es porque la lista mutable se puede cambiar en cualquier momento (problemas de seguridad de subprocesos) o qué?

(Sé dónde se implementa esto en CPython, así que no responda dónde , pero por qué se implementa).

Siempre puedes “lanzarlo”

 >>> tuple([1, 2]) == (1, 2) True 

Tenga en cuenta que Python, a diferencia de, por ejemplo, Javascript, está fuertemente tipado , y algunos (¿la mayoría?) Lo preferimos de esa manera.

No hay ninguna razón técnica para que las listas no puedan compararse con las tuplas; Es completamente una decisión de diseño impulsada por la semántica. Para comprobar que no está relacionado con la seguridad de subprocesos, puede comparar listas con otras listas:

 >>> l1 = [1, 2, 3] >>> l2 = [1, 2, 3] >>> l1 == l2 True >>> id(l1) == id(l2) False 

Parece razonable permitir a los usuarios comparar listas y tuplas directamente, pero luego terminas con otras preguntas: ¿se le debería permitir al usuario comparar listas y colas? ¿Qué pasa con los dos objetos que proporcionan iteradores? ¿Qué pasa con lo siguiente?

 >>> s = set([('x', 1), ('y', 2)]) >>> d = dict(s) >>> s == d # This doesn't work False 

Puede complicarse bastante rápido. Los diseñadores de idiomas reconocieron el problema y lo evitaron simplemente evitando que diferentes tipos de colección se comparen directamente entre sí 1 .

Tenga en cuenta que la solución simple (para crear una nueva lista a partir de la tupla y compararlas) es fácil pero ineficiente. Si está trabajando con un gran número de artículos, es mejor que use algo como:

 def compare_sequences(iter1, iter2): iter1, iter2 = iter(iter1), iter(iter2) for i1 in iter1: try: i2 = next(iter2) except StopIteration: return False if i1 != i2: return False try: i2 = next(iter2) except StopIteration: return True return False 

Esto tiene la ventaja de trabajar en cualquiera de las dos secuencias, a un costo obvio en complejidad.


1 Observo que hay una excepción para los sets y frozensets. Y, sin duda, algunos otros que no conozco. Los diseñadores de lenguaje son puristas, excepto cuando vale la pena ser práctico.