如果我编码有误并且我做了这样的事情:
__builtins__ = 'abcd'
在我没有编写代码之前 import builtins 有没有办法将 __builtins__ 恢复到它的默认值?
请您参考如下方法:
让我们假设一个比所描述的情况更糟糕的情况:你完全毁掉、核武器、摧毁、歼灭和消灭 __builtins__:
__builtins__.__dict__.clear()
@Matrtijn 的方法将失败,因为每个模块都将具有完全相同的 builtins 实例。
首先,我们必须恢复基本类型:
__builtins__.object = "".__class__.__mro__[-1]
__builtins__.type = object.__class__
根据 python docs , __mro__ 属性:是在方法解析期间查找基类时考虑的类的元组。由于每个 python 现代类都扩展了 object,它允许我们获得 object 类型的实例。
其次,我们将实现类查找。给定一个类名,我们将返回类的类型。为此,我们将使用 type.__subclasses__()递归地(有关更多信息,请参阅 this question):
def all_subclasses_of(cls):
return type.__subclasses__(cls) + [g for s in type.__subclasses__(cls) for g in all_subclasses_of(s)]
def lookup(s):
for cls in all_subclasses_of(object):
if cls.__name__ == s:
return cls
第三,我们将使用 BuiltinImporter 提取已经加载的模块:
bi = lookup('BuiltinImporter')
modules = bi.load_module.__globals__['sys'].modules
我们利用 BuiltinImporter 导入 sys 模块这一事实,然后我们使用 sys.modules : 将模块名称映射到已加载模块的字典。
然后,我们将使用下一步所需的方法和类修补 __builtins__:
__builtins__.hasattr = lambda obj, key: key in obj.__dict__
__builtins__.KeyError = lookup('KeyError')
现在,让奇迹发生吧!
bi.load_module('builtins')
__builtins__ = bi.load_module.__globals__['module_from_spec'](modules['builtins'].__spec__)
我们使用 builtinImporter.load_module 为 builtins 模块生成 __spec__ .然后,我们从生成的规范中加载模块。 并且有效!(我真的不知道为什么,但它确实有效)
但是,新生成的 builtins 模块缺少方法 open 和所有异常。我们必须手动添加它们才能使 import 再次工作:
__builtins__.BaseException = lookup('BaseException')
__builtins__.open = lambda name, mode: modules['io'].FileIO(name, mode)
for error in all_subclasses_of(BaseException):
__builtins__.__dict__[error.__name__] = error
