假设我使用__builtins__={}
删除了所有内置函数,是否可以强制重新导入所有基本模块?我考虑过使用_frozen_importlib.BuiltinImporter
,可以使用该方法吗?
目标是看是否可以做到以及如何使自己摆脱这种情况。除了简单地学习python的深奥部分外,它没有用。这是python3 btw。
答案 0 :(得分:1)
在https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html的底部描述了一种在无法访问内置模块名称时非常不切实际的方法。
更新:从thread on Reddit about recovering cleared globals开始,类似的代码片段将为您提供原始的内置文件:
[ c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings' ][0]()._module.__builtins__
通过将此对象重新分配给__builtins__
,可以再次访问内置对象。
>>> __builtins__ = {}
>>> max
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'max' is not defined
>>> __builtins__ = [c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__
>>> max
<built-in function max>
该语句的组成部分的简短说明:
() #tuple instance
().__class__ #the tuple class
().__class__.__base__ #tuple's base class, i.e. `object`
().__class__.__base__.__subclasses__() #every class that inherits from `object`
[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0] #the `warnings.catch_warnings` class
[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module #create a `catch_warnings` instance and access its `_module` attribute, which is the `warnings` module.
[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__ #`warnings.__builtins__` is the builtins module
__builtins__ = [c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__ #assign result to `__builtins__`
答案 1 :(得分:1)
您的问题是proposed as a puzzle in the Python chat room, back in March 2018。
用户Aran-Fey提供的以下解决方案可在REPL中重新恢复内置模块:
__builtins__ = __loader__.create_module(__loader__.find_spec('builtins'))
聊天室中的globals()
(__loader__
)也是一个更困难的变体,它另外清除了proposed命名空间并因此拒绝访问and solved。
请注意,设置__builtins__ = {}
仅禁止访问交互式REPL中的内置名称空间,而不能禁止脚本中的访问,并且在__builtins__
中的查找被视为a CPython implementation detail。
答案 2 :(得分:-1)
正如@Kevin在评论中指出的那样,REPL和脚本之间似乎有所不同。在脚本中,重新分配__builtins__
似乎无效(Python 3.7.3):
# test.py
__builtins__ = {}
print(max([1,2,3]))
def really_weird():
__builtins__ = {"max": lambda x: min(x)}
print(max([1,2,3]))
really_weird()
# Output
3
3
max
并没有改变,即使__builtins__
重新分配了名称(某种)。
在REPL中,可以使用_frozen_importlib.BuiltinImporter
是正确的。
>>> import _frozen_importlib # This must be before reassigning __builtins___, since __builtins__ includes __import__
>>> __builtins__ = {}
>>> max([1,2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'max' is not defined
>>> __builtins__ = _frozen_importlib.BuiltinImporter().load_module("builtins")
>>> max([1,2,3])
3
要注意的一件事:模块名称是builtins
,而不是__builtins__
。
此外,如注释中所述,进行import builtins as b; ... __builtins__ = b
或类似的操作也可以。
如果您不想进行设置工作,@ Kevin的答案也一样,无需事先导入。