我之前有过以下结构(作为更大项目的一部分):
lib/
__init__.py
somemodule.py
__init__.py
为空且somemodule.py
包含一些方法def hello()
。现在,在我的代码库中,有大量的方法导入,特别是from lib.somemodule import hello
。
由于各种原因,我现在希望将somemodule.py
移动到子包中。意思是,我希望结构为:
lib/
sublib/
__init__.py
somemodule.py
__init__.py
并认为如果现在lib/__init__.py
将包含:
from sublib import somemodule
,运行from lib.somemodule import hello
仍然有用(实质上,现在将结构更改“透明”)。
但是,如果某些外部代码运行from lib.somemodule import hello
,则会引发错误ImportError: No module named somemodule
,同时运行from lib import somemodule
。
我很感激我对错误的解释,以及关于如何在文件夹结构发生变化的情况下使from lib.somemodule import hello
运行的任何建议。
答案 0 :(得分:1)
如果您希望from lib.somemodule import hello
有效,则需要在包somemodule
中使用名为lib
的模块。调用from sublib import somemodule
只会将您的模块添加到包的范围,而不是定义导入机制可以找到的新模块。这也是from lib import somemodule
有效的原因。它只从包somemodule
中导入全局变量lib
。
让模块lib/somemodule.py
包含内容
from .sublib.somemodule import *
将是解决该问题的最简单,最干净的方法,可能包括某种DeprecationWarning。然后将来删除一段时间。
以下提示基于the import statement文档中的信息。
检查的第一个地方是
sys.modules
,这是之前导入的所有模块的缓存。
所以一个简单的可以做解决方案是自己编写模块缓存:
import sys
from .sublib import somemodule
sys.modules[__package__+'.somemodule'] = somemodule
也许向sys.meta_path
添加一个查找器可能会更清洁:
import sys
from .sublib import somemodule
class SomemoduleFinder(object):
def find_module(self, fullname, path=None):
if fullname == __package__+'.somemodule':
return self
def load_module(self, fullname):
return somemodule
sys.meta_path.append(SomemoduleFinder())
如果之前有设置,lib/__init__.py
没有直接导入somemodule
,您也可以将导入放在SomemoduleFinder.load_module
方法内以镜像该行为。虽然这只适用于Python 2。
在移植到Python 3时,请查看Python Module Imports - Explicit vs Implicit Relative Imports以防止将来出现可移植性问题。