2010-01-13 10 views
31

Como parte de responder a otra pregunta, me escribió el siguiente código cuyo comportamiento parece extraño a primera vista:¿Por qué la asignación a True/False no funciona como esperaba?

print True     # outputs true 
True = False; print True # outputs false 
True = True;  print True # outputs false 
True = not True; print True # outputs true 

¿Puede alguien explicar este comportamiento extraño? Creo que tiene algo que ver con el modelo de objetos de Python, pero no estoy seguro.

Es la versión 2.5.2 en Cygwin.

+18

no es tan buena broma vieja '#define cierto false' en acción aquí? – Amarghosh

+2

En la versión 3, la asignación True = False provoca un error sintax, por lo que supongo que su pregunta se refiere a la versión 2 – jab

+2

¿Qué tiene de extraño? ¿cuidado para elaborar? – ghostdog74

Respuesta

73

Python tiene estos dos (entre otros) objetos incorporados. Son solo objetos; al principio, todavía no tienen ningún nombre, pero para saber a qué nos referimos, llamémoslos 0x600D y 0xBAD.

Antes de comenzar la ejecución de un script en Python (2.x), el nombre True se enlaza con el objeto 0x600D, y el nombre False se enlaza con el objeto 0xBAD, por lo que cuando el programa se refiere a True, se ve en 0x600D .

Debido 0x600D y 0xBAD saben que suelen ser utilizados por los nombres True y False, eso es lo que la salida cuando se imprimen, es decir, el método de 0x600D vuelve 'True' y así sucesivamente __str__.

True = False 

ahora se une el nombre True a un objeto diferente. A partir de ahora, los nombres True y False se refieren al mismo objeto 0xBAD, que, cuando se imprime, genera False.

True = True 

en realidad no hace nada: Se toma el objeto a que se refiere con el nombre True, y se une al nuevo (y viejo) Nombre True a este objeto. Dado que (debido al paso anterior) True se refiere a 0xBAD antes de esto, todavía se refiere a 0xBAD después de esto. Por lo tanto, la impresión sigue emitiendo False.

True = not True 

primera toma el objeto de que el nombre True está obligado a, que es 0xBAD. Da este objeto al operador not. not no importa (o sabe) qué nombre se usa aquí para referirse a 0xBAD, simplemente sabe que cuando se le da 0xBAD debe devolver 0x600D.Este valor de retorno se entrega al operador de asignación =, vinculando el nombre True a este objeto.

Desde el nombre True ahora una vez más se refiere al objeto 0x600D, llamando print True salidas True, y el mundo es bien otra vez.

+16

@paxdiablo: ¿De qué estás hablando, "mnemónicos"? Esas son las direcciones de memoria donde cada buena implementación de Python debería contener estos objetos :-P – balpha

+0

@ user127555 Lo sé; "asignación no es una expresión" es una de mis características favoritas de Python. Pero con respecto a "ningún operador de asignación": incluso los [documentos oficiales] (https://docs.python.org/2/reference/simple_stmts.html) se refieren a este por ese nombre. – balpha

17

En 2.x, Verdadero y Falso no son palabras clave, por lo que es posible sombrear los elementos integrados de esta manera.

41

Imagínese esto en su lugar:

A = True 
B = False 

print A   # true 
A = B; print A # false 
A = A; print A # false, because A is still false from before 
A = not A; print A # true, because A was false, so not A is true 

Exactamente lo mismo que está pasando, pero en su versión es confuso, ya que no se espera que se puede redefinir verdadero y falso.

11

Puede comprobar si Verdadero/Falso es una palabra clave:

>>> import keyword 
>>> keyword.iskeyword('True') 
False 

Ya que no es (en mi versión), la asignación de True = False sólo significa "verdad" es otro nombre "variable".

+1

Solo una nota que probablemente debería usar 'keyword.iskeyword ('True')' como un ejemplo en su lugar, ya que la mayoría de las palabras clave reales darán un SyntaxError si se usan allí. –

+0

@Ig, sure.thanks – ghostdog74

+2

Nota: esto está solucionado en python 3, True es una [palabra clave] (https://docs.python.org/3/reference/lexical_analysis.html#keywords). –

0

Desde aquí se puede restaurar los valores originales utilizando comparaciones booleanas simples:

True = 1==1 
False = 1==0 

o convirtiendo literales enteros a Bools:

True = bool(1) # actually every number except 0 works 
False = bool(0) 
Cuestiones relacionadas