如何导入包中的模块的成员
我正在开发一个具有类似于以下文件结构的包:
test.py package/ __init__.py foo_module.py example_module.py
如果我在test.py中调用import package
,我想让包模块看起来像这样:
>>> vars(package) mapping_proxy({foo: <function foo at 0x…}, {example: <function example at 0x…})
换句话说,我希望package
中所有模块的成员都在package
的名称空间中,而且我不希望这些模块本身位于名称空间中。 package
不是一个子包。
假设我的文件如下所示:
foo_module.py:
def foo(bar): return bar
example_module.py:
def example(arg): return foo(arg)
test.py:
print(example('derp'))
如何构造test.py,example_module.py和__init__.py中的import语句,以便从package目录(即test.py)之外和包本身(即foo_module.py和example_module.py)中工作? 我尝试的所有东西给Parent module '' not loaded, cannot perform relative import
或ImportError: No module named 'module_name'
。
另外,作为一个旁注(根据PEP 8):“对于包内导入的相对导入是非常不鼓励的,对于所有的导入都要使用绝对的包path,即使现在PEP 328已经在Python 2.5中完全实现,明确的相对import是积极的阻止;绝对import更便携,通常更具可读性。
我正在使用Python 3.3。
你说:
我希望包中的所有模块的成员都在包的名称空间中,我不希望模块本身在名称空间中。
我能够做到这一点,使我在Python 2中使用的东西自动导入插件,也可以在Python 3中工作。
简而言之,它是如何工作的:包的__init__.py文件将所有其他Python文件导入到同一个包目录中,而不是以'_'(下划线)字符开头。 之后,它将导入模块名称空间中的所有名称添加到__init__模块(也是该包的名称空间)中。 注意我必须使example_module
模块明确地从foo_module
import foo
。
这样做的一个重要方面是意识到它是dynamic的,不需要将包模块名称硬编码到__init__.py文件中。 当然,这需要更多的代码来完成,但也使得它非常通用,能够处理任何(单层)包 – 因为它会在添加新模块时自动导入,并停止导入从目录。
test.py :
from package import * print(example('derp'))
__init__.py :
def _import_all_modules(): """dynamically imports all modules in the package""" import traceback import os global __all__ __all__ = [] globals_, locals_ = globals(), locals() # dynamically import all the package modules for filename in os.listdir(__name__): # process all python files in directory that don't start with underscore # (which also keeps this module from importing itself) if filename[0] != '_' and filename.split('.')[-1] in ('py', 'pyw'): modulename = filename.split('.')[0] # filename without extension package_module = '.'.join([__name__, modulename]) try: module = __import__(package_module, globals_, locals_, [modulename]) except: traceback.print_exc() raise for name in module.__dict__: if not name.startswith('_'): globals_[name] = module.__dict__[name] __all__.append(name) _import_all_modules()
foo_module.py :
def foo(bar): return bar
example_module.py :
from package.foo_module import foo # added def example(arg): return foo(arg)
我想你可以通过使用from module import name
样式导入来获得所需的值,而不会混淆你的名称空间。 我认为这些import产品可以满足您的要求:
导入example_module.py
:
from package.foo_module import foo
导入__init__.py
:
from package.foo_module import foo from package.example_module import example __all__ = [foo, example] # not strictly necessary, but makes clear what is public
importtest.py
:
from package import example
请注意,这只适用于运行test.py
(或与包层次结构相同级别的其他东西)。 否则,您需要确保包含package
的文件夹位于python模块searchpath中(可以通过将软件包安装在Python将要查找的地方,或者将相应的文件夹添加到sys.path
)。