3

I was putting this idea How to make a cross-module variable? in action for python3. And was lazy enough to use the variable __builtins__ instead of the module builtins. Which should make no difference because:

# file spam.py:
import builtins
print (builtins is __builtins__)
print (id(builtins))
print (id(__builtins__))

This is when it gets funny: builtins is not __builtins__ when imported:

$ python3 spam.py 
True
140598001743336
140598001743336

$ python3 -c 'import spam'
False
139755426543080
139755426520904

Does anyone know what happens?

(A comment on the given page mentions "__builtins__ is a CPython peculiarity, you really shouldn't use it", but I'm being curious...)

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
Demi-Lune
  • 1,868
  • 2
  • 15
  • 26
  • 2
    `__builtins__` is an implementation detail, so you shouldn't rely on it being anything in particular. – chepner Feb 18 '19 at 17:41

2 Answers2

5

I don't really know why, but from article

frame globals have a __builtins__ variable (builtins dictionary, or builtins module when __name__ equals __main__)

so in your first case (__name__ == __main__) and you get __builtins__ as builtins module, but in the second case (__name__ != __main__) __builtins__ is a dict instance and from docs:

The value of __builtins__ is normally either this module or the value of this module’s __dict__ attribute.

Test

With slightly modified spam.py

import builtins

if __name__ == '__main__':
    print(type(__builtins__))
    print(__builtins__ is builtins)
    print(id(builtins))
    print(id(__builtins__))
else:
    print(type(__builtins__))
    print(__builtins__ is builtins.__dict__)
    print(id(builtins.__dict__))
    print(id(__builtins__))

we will get something like

$ python3 spam.py 
<class 'module'>
True
2345652270648
2345652270648

$ python3 -c 'import spam'
<class 'dict'>
True
2770543697736
2770543697736

Conclusion

As you & @chepner have already noticed __builtins__ is an implementation detail that can be changed, so we shouldn't rely on it, especially on it being a builtins module/builtins.__dict__ object.

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
1

For CPython implementation,

in the __main__ module: __builtins__ is builtins.
in other module: __builtins__ is builtins.__dict__

Refs:
https://docs.python.org/3/reference/executionmodel.html#builtins-and-restricted-execution http://mathamy.com/whats-the-deal-with-builtins-vs-builtin.html

Kai
  • 356
  • 1
  • 6