__import__ 覆盖后是否可以恢复?

Is it possible to recover __import__ after overwriting it?

我正在尝试编写一些能够抵抗 __import__ 更改的代码,因为 the Pydev debugger overrides __import__.

所以,我需要一种访问内置 __import__ 函数的方法。

>>> def fake_import(*args, **kwargs): pass # some other implementation here
... 
>>> import __builtin__
>>> __builtin__.__import__ = fake_import
# can I recover the original value of __import__ here?

SO 上有关于 recovering removed built-ins 的问题,但在这种情况下全局已被替换。

查看您 link 的代码,原始 builtins.__import__ 被传递给新的 ImportHookManager 实例并存储为 _system_import 属性。

根据 How to get instance given a method of the instance? 的答案,您可以这样做:

__import__ = __import__.im_self._system_import

恢复原来的功能。请注意,前导下划线将此属性标记为按约定私有,并且 implementation/attribute 名称可以在没有警告的情况下更改。

虽然我还没有找到恢复 __import__ 本身的方法,但使用 ihooks 我可以获得一个功能,就像 __import__ 一样:

import ihooks
ihooks.ModuleImporter().install()

# or
works_just_like__import__ = ihooks.ModuleImporter().import_module

这是一个有点棘手的问题,因为 python 不会对重新加载 __builtin__ 模块感兴趣,因为它没有改变。您将被迫删除 __builtin__ 模块以强制 python 重新导入它。您还可以使用 importlib 绕过 __import__(仅在 python3 中为真,在 python2 中 importlib 求助于 __import__)。

import sys
import importlib

import __builtin__ as old_builtins

class ExampleImporter(object):
    old_import = __import__
    def __init__(self):
       self.count = 0
    def new_import(self, *args, **kwargs):
        self.count += 1
        print(args, kwargs)
        return self.old_import(*args, **kwargs)
importer = ExampleImporter()

old_builtins.__import__ = importer.new_import
assert __import__ == importer.new_import

# remove builtins from modules so as to force its reimport
del sys.modules["__builtin__"]
# in python3 the following bypasses __import__ entirely, but not in python2
new_builtins = importlib.import_module("__builtin__") 
# restore initial state of __builtin__ module (will not delete new names 
# added to __builtin__)
old_builtins.__dict__.update(new_builtins.__dict__)
# Replace new __builtin__ with old __builtin__ module. Otherwise you'll end up with a 
# mess where different modules have different a __builtin__ module.
sys.modules["__builtin__"] = old_builtins
del new_builtins

assert __import__ == importer.old_import
assert importer.count == 1 # would be 0 in python3