not - null variable python
¿Por qué en Python hace 0, 0==(0, 0) igual(0, falso) (6)
En Python (verifiqué solo con Python 3.6 pero creo que debería ser válido también para muchas de las versiones anteriores):
(0, 0) == 0, 0 # results in a two element tuple: (False, 0)
0, 0 == (0, 0) # results in a two element tuple: (0, False)
(0, 0) == (0, 0) # results in a boolean True
Pero:
a = 0, 0
b = (0, 0)
a == b # results in a boolean True
¿Por qué el resultado difiere entre los dos enfoques? ¿El operador de igualdad maneja las tuplas de manera diferente?
Agregar un par de paréntesis alrededor del orden en que se realizan las acciones podría ayudarlo a comprender mejor los resultados:
# Build two element tuple comprising of
# (0, 0) == 0 result and 0
>>> ((0, 0) == 0), 0
(False, 0)
# Build two element tuple comprising of
# 0 and result of (0, 0) == 0
>>> 0, (0 == (0, 0))
(0, False)
# Create two tuples with elements (0, 0)
# and compare them
>>> (0, 0) == (0, 0)
True
La coma se usa para
separar expresiones
(usando paréntesis podemos forzar diferentes comportamientos, por supuesto).
Cuando vea los fragmentos que enumeró, la coma
,
los separará y definirá qué expresiones se evaluarán:
(0, 0) == 0 , 0
#-----------|------
expr 1 expr2
La tupla
(0, 0)
también se puede dividir de manera similar.
La coma separa dos expresiones que comprenden los literales
0
.
En el primero, Python está haciendo una tupla de dos cosas:
-
La expresión
(0, 0) == 0
, que se evalúa comoFalse
-
La constante
0
En el segundo es al revés.
Las dos primeras expresiones se analizan como tuplas:
-
(0, 0) == 0
(que esFalse
), seguido de0
-
0
, seguido de0 == (0, 0)
(que sigue siendoFalse
esa manera).
Las expresiones se dividen de esa manera debido a la precedencia relativa del separador de coma en comparación con el operador de igualdad: Python ve una tupla que contiene dos expresiones, una de las cuales es una prueba de igualdad, en lugar de una prueba de igualdad entre dos tuplas.
Pero en su tercer ejemplo,
a = 0, 0
no puede
ser una tupla.
Una tupla es una colección de valores y, a diferencia de una prueba de igualdad, la asignación no tiene valor en Python.
Una asignación no es una expresión, sino una declaración;
no tiene un valor que pueda incluirse en una tupla o cualquier otra expresión circundante.
Si intentara algo como
(a = 0), 0
para forzar la interpretación como una tupla, obtendría un error de sintaxis.
Eso deja la asignación de una tupla a una variable, que podría hacerse más explícita escribiendo
a = (0, 0)
, como la única interpretación válida de
a = 0, 0
.
Lo que ve en las 3 instancias es una consecuencia de la especificación gramatical del lenguaje y cómo se analizan los tokens encontrados en el código fuente para generar el árbol de análisis.
Echar un vistazo a este código de bajo nivel debería ayudarlo a comprender lo que sucede debajo del capó.
Podemos tomar estas declaraciones de Python, convertirlas en código de bytes y luego descompilarlas usando el módulo
dis
:
Caso 1:
(0, 0) == 0, 0
>>> dis.dis(compile("(0, 0) == 0, 0", '''', ''exec''))
1 0 LOAD_CONST 2 ((0, 0))
3 LOAD_CONST 0 (0)
6 COMPARE_OP 2 (==)
9 LOAD_CONST 0 (0)
12 BUILD_TUPLE 2
15 POP_TOP
16 LOAD_CONST 1 (None)
19 RETURN_VALUE
(0, 0)
se compara primero con
0
primero y se evalúa como
False
.
Luego se construye una tupla con este resultado y el último
0
, por lo que obtienes
(False, 0)
.
Caso 2:
0, 0 == (0, 0)
>>> dis.dis(compile("0, 0 == (0, 0)", '''', ''exec''))
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 0 (0)
6 LOAD_CONST 2 ((0, 0))
9 COMPARE_OP 2 (==)
12 BUILD_TUPLE 2
15 POP_TOP
16 LOAD_CONST 1 (None)
19 RETURN_VALUE
Una tupla se construye con
0
como primer elemento.
Para el segundo elemento, se realiza la misma verificación que en el primer caso y se evalúa como
False
, por lo que obtiene
(0, False)
.
Caso 3:
(0, 0) == (0, 0)
>>> dis.dis(compile("(0, 0) == (0, 0)", '''', ''exec''))
1 0 LOAD_CONST 2 ((0, 0))
3 LOAD_CONST 3 ((0, 0))
6 COMPARE_OP 2 (==)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
Aquí, como ves, solo estás comparando esas dos
(0, 0)
tuplas y devolviendo
True
.
Otra forma de explicar el problema: probablemente esté familiarizado con los literales del diccionario
{ "a": 1, "b": 2, "c": 3 }
y literales de matriz
[ "a", "b", "c" ]
y tuples literales
( 1, 2, 3 )
pero de lo que no se da cuenta es que, a diferencia de los literales de diccionario y matriz, los paréntesis que generalmente se ven alrededor de un literal de tupla no son parte de la sintaxis literal . La sintaxis literal para las tuplas es solo una secuencia de expresiones separadas por comas:
1, 2, 3
(un "exprlist" en el lenguaje de la gramática formal para Python ).
Ahora, ¿qué esperas de la matriz literal?
[ 0, 0 == (0, 0) ]
evaluar a? Eso probablemente se parece mucho más a lo que debería ser lo mismo que
[ 0, (0 == (0, 0)) ]
que por supuesto se evalúa a
[0, False]
.
Del mismo modo, con un literal de tupla explícitamente entre paréntesis
( 0, 0 == (0, 0) )
No es sorprendente obtener
(0, False)
.
Pero los paréntesis son opcionales;
0, 0 == (0, 0)
es lo mismo.
Y es por eso que obtienes
(0, False)
.
Si se pregunta por qué los paréntesis alrededor de un literal de tupla son opcionales, es en gran parte porque sería molesto tener que escribir las tareas de desestructuración de esa manera:
(a, b) = (c, d) # meh
a, b = c, d # better
mira este ejemplo:
r = [1,0,1,0,1,1,0,0,0,1]
print(r==0,0,r,1,0)
print(r==r,0,1,0,1,0)
entonces resultado:
False 0 [1, 0, 1, 0, 1, 1, 0, 0, 0, 1] 1 0
True 0 1 0 1 0
entonces la comparación solo se hace con el primer número (0 yr) en el ejemplo.