如何调试被覆盖的sys.modules条目?

时间:2015-01-07 18:50:14

标签: python numpy

我正在尝试调试导致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在正在运行的Julia进程中嵌入Python解释器,并将导入委托给cpython中的PyImport_ImportModule。上面的问题发生在PyImport_ImportModule的单个调用中,所以我希望这个问题应该对python / cpython的知识负责,但不知道Julia / PyCall。

2 个答案:

答案 0 :(得分:2)

您可以将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),这可能会也可能不会起作用,但它是值得一试!

答案 1 :(得分:1)

感谢@BrenBarn指点我https://stackoverflow.com/a/14778568/744071。以下是我的目的:

importhack.py:

import traceback

old_import = __import__

def my_import(module, *args, **kwargs):
    print "my_import({}) caused by:".format(module)
    traceback.print_stack()
    return old_import(module, *args, **kwargs)

__builtins__['__import__'] = my_import

用法:

>>> import importhack
>>> import numpy

我相信PyCall.jl中的原始问题是在Python解释器完全初始化之前调用PyImport_ImportModule引起的。