我正在尝试调试导致sys.modules['numpy']被覆盖的问题。我在numpy.__init__中添加了一些打印语句,当我尝试导入numpy时,得到以下输出:

numpy.__init__ running
id(sys.modules) = 89034704
id(sys.modules['numpy']) = 161528304
numpy.__init__ running
id(sys.modules) = 89034704
id(sys.modules['numpy']) = 177135864


Numpy具有许多循环导入,它们应按照this answer中的说明工作。但是在我的情况下,不是从sys.modules获取部分初始化的numpy模块,而是再次导入numpy,然后再次执行numpy.__init__,从而导致崩溃。

如何检测sys.modules以获得谁在何时覆盖sys.modules['numpy']的可见性?通常,我会写一个dict子类,但我认为更改sys.modules指向自己的对象并不安全。我尝试覆盖sys.modules.__setattr__,但这是一个只读属性。

上下文:我正在尝试在Julia库PyCall中调试this issue。 PyCall将Python解释器嵌入正在运行的Julia进程中,然后将导入从cpython委托给PyImport_ImportModule。上面的问题只在对PyImport_ImportModule的一次调用中发生,所以我希望这个问题应该能够在python / cpython知识的情况下得到解答,但不知道Julia / PyCall的知识。

最佳答案

您可以将sys.modules从普通的dict更改为prints分配的内容,例如:

import sys
import traceback

class noisydict(dict):
    def __setitem__(self, key, value):
        print('ASSIGNED: key={!r} value={!r} at:'.format(key, value))
        traceback.print_stack()
        return dict.__setitem__(self, key, value)

sys.modules = noisydict(sys.modules)


如果覆盖发生在C​​代码中(这可能直接访问底层的dict.__setitem__而不是像Python代码那样仅执行sys.modules[name] = newmodule),则此方法可能行不通,但值得一试!

09-16 08:38