3

I'm exploring the REPL and I noticed the __builtins__ module.

I entered

>>> __builtins__.

and hit Tab, then Python REPL showed me a list of builtin identifiers, including abs, len, zip and True, False, None etc.

The first test passed without doubt:

>>> __builtins__.zip is zip
True

But the second one didn't:

>>> __builtins__.None is None
   File "<stdin>", line 1
    __builtins__.None is None
                    ^
SyntaxError: invalid syntax

Why?

iBug
  • 35,554
  • 7
  • 89
  • 134

2 Answers2

6

None is a keyword. As such, it can not be used with the dot notation, much like how __builtins__.True, __builtins__.class and __builtins__.def are also a syntax error.

This can be bypassed by using getattr:

print(getattr(__builtins__, 'None') is None)
# True
print(getattr(__builtins__, 'False') is False)
# True
print(getattr(__builtins__, 'True') is True)
# True

Unlike abs, len, zip etc (which are top-level functions), None, True and False are keywords in Python 3 (see https://docs.python.org/3/reference/lexical_analysis.html#keywords).

In Python 2 True and False were not keywords (just a built-in name/constant) (See https://docs.python.org/2/reference/lexical_analysis.html#keywords) so you could reassign to them. As mentioned above this is impossible in Python 3 since they became keywords.

Also see this question: True=False assignment in Python 2.x

With that said, one can still mess around with __builtins__.True in Python 3, but it will not affect the actual True as it used to be in Python 2:

print(getattr(__builtins__, 'True'))
# True
setattr(__builtins__, 'True', False)
print(getattr(__builtins__, 'True'))
# False
print(True)
# True
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • `class` and `def` **do not** show up in the list when I hit Tab after entering `__builtins__.`. – iBug Apr 03 '18 at 10:59
  • 2
    @iBug why does it matter? for what it's worth, `True` and `False` do show up but still cause a syntax error – DeepSpace Apr 03 '18 at 11:01
  • 1
    Neither `class` nor `def` are names bound to objects. Keywords and names are two different sets; their intersection includes `None`, `True` and `False`. – chepner Apr 03 '18 at 11:42
  • 1
    But then, why are None, True and False in the __builtins__ module? – steffen Jul 26 '19 at 16:22
  • @steffen I assume it's in case someone wrote code that expects them to be there (perhaps as part of some weird 2.x backwards-compatibility patch, although I can't imagine offhand how it would actually solve a practical problem). I can't imagine that they'd be included if Python were redesigned from scratch today. – Karl Knechtel Aug 10 '22 at 00:23
1

We can observe this change in the language from the keywords list of Python 2 and Python 3. False, None and True were added as keywords to avoid confusion should someone e.g. try to overwrite one of them.

>>> False=True
>>> False
True

This is valid, but highly misleading, Python 2. Python 3 responds differently:

>>> False=True
  File "<stdin>", line 1
SyntaxError: can't assign to keyword

The History of Python has a writeup on the story of None, True and False. Here's another stack overflow question on the topic. Another effect of this change is that the compiler knows precisely which objects they are, and doesn't need a namespace lookup when they're referenced.

Python 2:

>>> dis.dis(compile("True","foo.py","eval"))
  1           0 LOAD_NAME                0 (True)
              3 RETURN_VALUE

Python 3:

>>> dis.dis(compile("True","foo.py","eval"))
  1           0 LOAD_CONST               0 (True)
              3 RETURN_VALUE
Yann Vernier
  • 15,414
  • 2
  • 28
  • 26