[英]Restore __builtins__ to default
If I code a mistake and I do something like this: 如果我编写了一个错误并且执行了以下操作:
__builtins__ = 'abcd'
and before I didn't code import builtins
is there a way to restore __builtins__
to its default value? 在我没有代码
import builtins
之前,有没有办法将__builtins__
恢复为默认值?
Congratulations, you managed to muck up your namespace good and proper! 恭喜,您成功地将您的命名空间做了妥善准备! There is no easy escape from this mess, no.
没有从这个烂摊子容易逃脱,不。
You can grab the name from any Python module you perhaps have imported, or from an imported Python function: 您可以从可能已导入的任何Python模块或导入的 Python函数中获取名称:
__builtins__ = some_python_module.__builtins__
or 要么
__builtins__ = some_python_function.__globals__['__builtins__']
The function has to be one you imported from elsewhere, so that the __globals__
reference points to a different namespace that still has a reference to the __builtins__
mapping. 该函数必须是您从其他位置导入的函数,以便
__globals__
引用指向另一个仍引用__builtins__
映射的命名空间。
One name that I found will almost always work is the __loader__
reference in modules; 我发现几乎可以使用的一个名称是模块中的
__loader__
引用; it is an object with methods that will still give you access a module globals object: 它是一个带有方法的对象,该方法仍然可以让您访问模块全局对象:
__builtins__ = __loader__.find_spec.__func__.__globals__['__builtins__']
Otherwise, restart your Python session, and start again. 否则,请重新启动Python会话,然后重新开始。
Let's assume even a worse case than the described situation: you completely ruin, nuke, destroy, annihilate and wipe out __builtins__
: 让我们假设一个比描述的情况更糟的情况:您完全破坏,核毁,破坏,歼灭并消灭
__builtins__
:
__builtins__.__dict__.clear()
@Matrtijn's method will fail since every module will have the very same builtins
instance. @Matrtijn的方法将失败,因为每个模块都具有完全相同的
builtins
实例。
First, we will have to restore the basic types: 首先,我们必须还原基本类型:
__builtins__.object = "".__class__.__mro__[-1]
__builtins__.type = object.__class__
According to python docs , __mro__
attribute: is a tuple of classes that are considered when looking for base classes during method resolution . 根据python docs ,
__mro__
属性: 是方法解析期间寻找基类时要考虑的类的元组 。 Since every python modern class extends object
, it allows us to gain instance of the object
type. 由于每个python现代类都扩展了
object
,所以它允许我们获取object
类型的实例。
Second, We will implement a class lookup. 其次,我们将实现一个类查找。 Given a class name we will return the class' type.
给定一个类名,我们将返回该类的类型。 For that we will use
type.__subclasses__()
recursively (See this question for more information about that): 为此,我们将递归使用
type.__subclasses__()
(有关此信息,请参阅此问题 ):
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
Third, We'll extract the already loaded modules using BuiltinImporter
: 第三,我们将使用
BuiltinImporter
提取已经加载的模块:
bi = lookup('BuiltinImporter')
modules = bi.load_module.__globals__['sys'].modules
We take advantage of the fact that BuiltinImporter
imports sys
module and then we use sys.modules
: a dictionary that maps module names to modules which have already been loaded . 我们利用
BuiltinImporter
导入sys
模块,然后使用sys.modules
的事实: 一个将模块名称映射到已经加载的模块的字典 。
Then, We will patch __builtins__
with the required methods and classes for the next step: 然后,我们将为
__builtins__
修补所需的方法和类,以进行下一步:
__builtins__.hasattr = lambda obj, key: key in obj.__dict__
__builtins__.KeyError = lookup('KeyError')
And now, for the magic to happen! 而现在,神奇的事情发生了!
bi.load_module('builtins')
__builtins__ = bi.load_module.__globals__['module_from_spec'](modules['builtins'].__spec__)
We generate the __spec__
to the builtins
module using builtinImporter.load_module
. 我们使用
builtinImporter.load_module
生成__spec__
到builtins
模块。 Then, we load the module from the generated spec. 然后,我们从生成的规范中加载模块。 AND IT WORKS!
和它的工作! (I don't really know why, but it indeed works)
(我真的不知道为什么,但是确实有效)
However, the freshly generated builtins
module misses the method open
and all of the exceptions. 但是,新生成的
builtins
模块错过了方法open
和所有异常。 We will have to add them manually to get import
working again: 我们将必须手动添加它们才能使
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.