Python has these two (among others) builtin objects. They are just objects; in the beginning, they don't have any names yet, but to know what we refer to, let's call them 0x600D
and 0xBAD
.
Before starting to execute a Python (2.x) script, the name True
gets bound to the object 0x600D
, and the name False
gets bound to the object 0xBAD
, so when the program refers to True
, it looks at 0x600D
.
Because 0x600D
and 0xBAD
know that they are usually used by the names True
and False
, that's what they output when they get printed, i.e. the __str__
method of 0x600D
returns 'True'
and so on.
True = False
now binds the name True
to a different object. From now on, both names True
and False
refer to the same object 0xBAD
, which, when printed, outputs False
.
True = True
doesn't really do anything: It takes the object referred to by the name True
, and binds the new (and old) name True
to this object. Since (because of the previous step) True
refers to 0xBAD
before this, it still refers to 0xBAD
after this. Hence, printing still outputs False
.
True = not True
first takes the object that the name True
is bound to, which is 0xBAD
. It gives this object to the not
operator. not
doesn't care (or know) what name is used here to refer to 0xBAD
, it just knows that when given 0xBAD
it should return 0x600D
. This return value is then given to the assignment operator =
, binding the name True
to this object.
Since the name True
now once more refers to the object 0x600D
, calling print True
outputs True
, and the world is good again.