如何创建并导入包含不确定模块集合的包?
使用Python 3.3或更高版本,我想知道如何创建一个包含不确定数量模块的包,并且希望在导入这个包的时候,所有模块都能自动导入,而不需要一个个手动导入。这样的话,如果以后往这个包里添加了新模块,下次导入这个包时,新模块也能自动加载,不用再对包做其他修改。
在包外部,我希望导入和使用这个包的方式大概是这样的:
import package
package.module.function()
而在包内部,我希望导入和使用兄弟模块的方式大概是这样的:
from . import sibling
sibling.function()
或者这样:
import package.sibling
package.sibling.function()
1 个回答
在Python 3.3或更高版本中,使用pkgutil搜索包目录,并通过importlib加载每个模块。
在包的__init__.py
文件中:
# Import standard modules.
import importlib
import os
import pkgutil
# For each module in the current directory...
for void, module_name, void in pkgutil.iter_modules([os.path.dirname(__file__)]):
# Import the module.
importlib.import_module(__name__+'.'+module_name)
以上内容可以移到一个库中,这样包的__init__.py
就变得简单了:
# Import local modules.
import loader
# Load all modules in the current directory.
loader.load_all_modules(__file__,__name__)
需要注意的是,importlib
这个工具是在Python 3.1中引入的,并在Python 3.3中进行了重要更新,而上述方法在Python 3.1.x或3.2.x中没有经过测试。
https://docs.python.org/3.3/library/importlib.html#importlib.import_module https://docs.python.org/3.3/library/pkgutil.html#pkgutil.iter_modules
其他失败的方法
尝试 1
从包外部,使用绝对导入:
import package.module
这需要知道模块的名称。
尝试 2
从包的__init__.py
中,使用绝对导入:
import module
这同样需要知道模块的名称。
尝试 3
从包的__init__.py
中,设置__all__
:
__all__ = ['module']
这需要使用:
from package import *
这样做会污染命名空间,可能会带来危险,尤其是在这种情况下,因为模块的名称并不明确。
尝试 4
从包的__init__.py
中,使用pkgutil
来识别和导入包中的所有模块,虽然看似可以导入,但实际上只是模拟了原生的导入机制,并没有更新sys.modules
字典。这会导致包内的模块在尝试导入兄弟模块时出现问题,例如:
没有在sys.modules
中列出会导致相对导入失败,并出现以下消息:
父模块''未加载,无法执行相对导入。
http://hg.python.org/cpython/file/f7992397e98d/Lib/importlib/_bootstrap.py#l1518
此外,绝对导入会重新加载被导入的模块。
https://docs.python.org/3.3/library/imp.html#imp.load_module http://python-notes.curiousefficiency.org/en/latest/python_concepts/import_traps.html#the-double-import-trap
尝试 5
从包的__init__.py
中,使用importlib
似乎没有简单的方法来识别可导入的模块和子包,除了可能通过导入所有内容并捕获错误,而这些错误信息可能会让人误解,从而更难发现真正的问题。