2010-01-13 8 views
31

Dans le cadre de répondre à une autre question, j'ai écrit le code suivant dont le comportement semble bizarre au premier coup d'œil:Pourquoi l'affectation à Vrai/Faux ne fonctionne-t-elle pas comme prévu?

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

Quelqu'un peut-il expliquer ce comportement étrange? Je pense que cela a quelque chose à voir avec le modèle d'objet de Python mais je ne suis pas sûr.

C'est la version 2.5.2 sous Cygwin.

+18

est-ce pas une bonne vieille blague '#define vrai false' en action ici? – Amarghosh

+2

Dans la version 3, l'assertion True = False déclenche une erreur sintax, donc je suppose que votre question fait référence à la version 2 – jab

+2

qu'est-ce qui est étrange à ce sujet? soin d'élaborer? – ghostdog74

Répondre

73

Python possède ces deux objets intégrés (parmi d'autres). Ce ne sont que des objets. au début, ils n'ont pas encore de noms, mais pour savoir à quoi nous nous référons, appelons-les 0x600D et 0xBAD.

Avant de commencer à exécuter un script Python (2.x), le nom True se lie à l'objet 0x600D, et le nom False se lie à l'objet 0xBAD, donc quand le programme se réfère à True, il regarde 0x600D .

Parce que 0x600D et 0xBAD savent qu'ils sont généralement utilisés par les noms True et False, c'est ce qu'ils sortie quand ils sont imprimés, à savoir la méthode __str__ de 0x600D retours 'True' et ainsi de suite.

True = False 

se fixe maintenant le nom True à un autre objet. A partir de maintenant, les deux noms True et False se réfèrent au même objet 0xBAD, qui, une fois imprimé, sort False.

True = True 

ne fait pas vraiment quoi que ce soit: Il prend l'objet visé par le nom True et lie le nouveau (et ancien) nom True à cet objet. Depuis (en raison de l'étape précédente) True se réfère à 0xBAD avant cela, il se réfère toujours à 0xBAD après cela. Par conséquent, l'impression sort toujours False.

True = not True 

premier prend l'objet que le nom True est lié, qui est 0xBAD. Il donne cet objet à l'opérateur not. not ne se soucie pas (ou de savoir) quel nom est utilisé ici pour se référer à 0xBAD, il sait juste que lorsqu'il est donné 0xBAD il devrait retourner 0x600D.Cette valeur de retour est ensuite donnée à l'opérateur d'affectation =, liant le nom True à cet objet.

Depuis le nom True maintenant une fois de plus fait référence à l'objet 0x600D, appelant print True sorties True, et le monde est bon à nouveau.

+16

@paxdiablo: De quoi parlez-vous, "mnemonics"? Ce sont les adresses mémoire où chaque bonne implémentation Python devrait contenir ces objets: -P – balpha

+0

@ user127555 Je sais; "l'assignation n'est pas une expression" est l'une de mes fonctionnalités préférées de Python. Mais en ce qui concerne "aucun opérateur d'assignation": Même les [documents officiels] (https://docs.python.org/2/reference/simple_stmts.html) se réfèrent à ce nom. – balpha

17

Dans 2.x, True et False ne sont pas des mots-clés, il est donc possible d'occulter les built-ins de cette manière.

41

Imaginez ceci:

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 

La même chose se passe, mais dans votre version, il est source de confusion, parce que vous ne vous attendez pas que vous pouvez redéfinir Vrai et Faux.

11

Vous pouvez vérifier si Vrai/Faux est un mot clé:

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

Puisqu'il n'est pas (dans ma version), attribuer Vrai = Faux signifie simplement que le nom "True" est une autre "variable".

+1

Juste une note que vous devriez probablement utiliser 'keyword.iskeyword ('True')' à titre d'exemple, puisque la plupart des mots-clés actuels donneront une SyntaxError si elle est utilisée ici. –

+0

@Ig, sure.thanks – ghostdog74

+2

Note: ceci est corrigé dans python 3, True est un [mot-clé] (https://docs.python.org/3/reference/lexical_analysis.html#keywords). –

0

Vous pouvez facilement restaurer les valeurs d'origine à l'aide de simples comparaisons booléennes:

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

ou en convertissant les littéraux entiers à bools:

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