Python3 `builtins` 并不总是 `__builtins__`

Dem*_*une 3 python python-3.x

我提出了这个想法如何制作跨模块变量?在 python3 中运行。并且懒得使用变量__builtins__而不是模块builtins。这应该没有区别,因为:

# file spam.py:
import builtins
print (builtins is __builtins__)
print (id(builtins))
print (id(__builtins__))
Run Code Online (Sandbox Code Playgroud)

这是它变得有趣的时候:builtins不是__builtins__在导入时:

$ python3 spam.py 
True
140598001743336
140598001743336

$ python3 -c 'import spam'
False
139755426543080
139755426520904
Run Code Online (Sandbox Code Playgroud)

有谁知道会发生什么?

(给定页面上的评论提到“__builtins__是 CPython 的特性,你真的不应该使用它”,但我很好奇......)

Aza*_*kov 5

我真的不知道为什么,但从文章

框架全局变量有一个__builtins__变量(内置字典,或__name__等于时的内置模块__main__

所以在你的第一种情况 ( __name__ == __main__) 中,你__builtins__作为builtins模块获得,但在第二种情况下 ( __name__ != __main__)__builtins__是一个dict实例,来自docs

的值__builtins__通常是此模块或此模块的__dict__属性值。

测试

稍加修改 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__))
Run Code Online (Sandbox Code Playgroud)

我们会得到类似的东西

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

$ python3 -c 'import spam'
<class 'dict'>
True
2770543697736
2770543697736
Run Code Online (Sandbox Code Playgroud)

结论

正如您和@chepner 已经注意到的那样,__builtins__是一个可以更改的实现细节,所以我们不应该依赖它,尤其是它是一个builtins模块/builtins.__dict__对象。