Python3重新导入__builtins __

时间:2019-06-07 17:45:08

标签: python-3.x

假设我使用__builtins__={}删除了所有内置函数,是否可以强制重新导入所有基本模块?我考虑过使用_frozen_importlib.BuiltinImporter,可以使用该方法吗?

目标是看是否可以做到以及如何使自己摆脱这种情况。除了简单地学习python的深奥部分外,它没有用。这是python3 btw。

3 个答案:

答案 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的答案也一样,无需事先导入。