简体   繁体   English

将__builtins__恢复为默认值

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM