The Python Oracle

Strange behavior when defining a value for True in Python

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Magical Minnie Puzzles

--

Chapters
00:00 Strange Behavior When Defining A Value For True In Python
00:42 Answer 1 Score 6
01:14 Answer 2 Score 5
01:50 Accepted Answer Score 2
03:27 Thank you

--

Full question
https://stackoverflow.com/questions/1963...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #boolean #booleanexpression

#avk47



ANSWER 1

Score 6


As often happens on here, I think I figured out the answer while I was typing up the question.

There are two "True"s: one is a boolean value, and the other is the variable called True; initially, they're equal to each other. This is why boolean operations like (1==1) can still return True even when the variable called True has been changed - they're returning the boolean value True. Yet they're not equal to the new value of the "True" variable, which is a string.




ANSWER 2

Score 5


That's happening is namespaceing and interactive console hiding it.

Initially you have normal True, which is part of __builtin__ module.

When you redefine True, you're actually defining it in a current module, which in that case is just default one __main__.

Thus you actually have two different objects. __builtin__.True and __main__.True.

In [1]: import __builtin__, __main__

In [2]: True = "a bad idea"

In [3]: __main__.True
Out[3]: 'a bad idea'

In [4]: __builtin__.True
Out[4]: True



ACCEPTED ANSWER

Score 2


To add a bit more to your own answer (should be a comment, but, long and needs formatting):

python2.7
...
>>> import __builtin__
>>> id(True)
7744528
>>> id(__builtin__.True)
7744528
>>> True = 'abc'
>>> id(True)
34386540544

The value from id is (essentially) the internal identity, or "true name" if you like, of an object in Python. (It's literally a C pointer turned into an integer.) The is test compares object-identity.

>>> 1==1
True
>>> id(1==1)
7744528

This shows that the boolean-result of a comparison is the "old" True, the one still available as __builtin__.True.

You re-bound the name __main__.True (your current module at the interpreter >>> prompt is __main__):

>>> True
'abc'
>>> __builtin__.True
True

and:

>>> import __main__
>>> id(__main__.True)
34386540544
>>> __main__.True
'abc'
>>> 

This same thing happens quite often in beginners' Python programs when they write functions like:

def foo(list):
    ...

list is a built-in function, but inside function foo, the name has been re-bound to the argument. Then somewhere in the ... part they get a surprise:

    x = list(y)

They expect this to invoke __builtin__.list, but it tries to call their local variable as a function instead.

(It's possible, but not generally good style, to import __builtin__ and call things through those names instead. It's also possible to re-bind the __builtin__ names, but that's an even worse idea. :-) )