我正在开发具有类似如下的文件结构的包:
test.py
package/
__init__.py
foo_module.py
example_module.py
如果我打电话import package
在test.py,我想封装模块出现类似这样的:
>>> 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语句从工作包目录外(即test.py)和包本身(即foo_module.py和example_module.py)内? 一切我尝试让Parent module '' not loaded, cannot perform relative import
或ImportError: No module named 'module_name'
。
此外,作为一个侧面说明(按PEP 8):“用于封装内的进口相对进口强烈建议不要总是使用绝对包路径全部进口,即使现在PEP 328在Python 2.5,它的风格是完全实现。相对明确的进口正在积极鼓励的;绝对进口更轻便,并且通常更具可读性“。
我使用Python 3.3。
我想在包中的所有模块的成员是在包的命名空间,我不希望这些模块本身是在命名空间。
我能够适应的东西,我在Python 2使用自动导入插件在Python 3还努力做到这一点。
概括地说,这里是它的工作原理是:
该软件包的__init_.py
文件导入所有在不与启动相同的包目录中的其他Python文件'_'
(下划线)字符。
然后,它会将所有的名字在导入模块的名称空间给的__init__
模块(这也是包的命名空间)。 请注意,我不得不做出example_module
模块明确import foo
从foo_module
。
这样做,让正在实现它的动态,并且不需要封装模块名称的一个重要方面被硬编码到__init__.py
文件。 当然,这需要更多的代码来完成,但也使得它非常通用的,能与几乎所有的(单级)封装,工作 - 因为当要加入他们会自动导入新的模块,并不再试图导入任何删除从目录。
test.py
:
from package import *
print(example('derp'))
__init__.py
:
def _import_all_modules():
""" Dynamically imports all modules in this package. """
import traceback
import os
global __all__
__all__ = []
globals_, locals_ = globals(), locals()
# Dynamically import all the package modules in this file's directory.
for filename in os.listdir(__name__):
# Process all python files in directory that don't start
# with underscore (which also prevents this module from
# importing itself).
if filename[0] != '_' and filename.split('.')[-1] in ('py', 'pyw'):
modulename = filename.split('.')[0] # Filename sans 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
样式的进口。 我想,这些进口会为你所要求的工作:
进口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
进口test.py
:
from package import example
请注意,如果你正在运行这仅适用test.py
(或东西在包层次的同一级别其他)。 否则,你需要确保包含文件夹package
是在Python模块搜索路径(无论是通过安装包某处Python会寻找它,或者通过添加相应的文件夹到sys.path
)。