2

我正在开发一个具有类似于以下文件结构的包:

test.py
package/
    __init__.py
    foo_module.py
    example_module.py

如果我调用import packagetest.py,我希望包模块看起来类似于:

>>> vars(package)
mapping_proxy({foo: <function foo at 0x…}, {example: <function example at 0x…})

换句话说,我希望所有模块的成员都packagepackage's 命名空间中,并且我不希望模块本身在命名空间中。package不是子包。

假设我的文件如下所示:

foo_module.py:

def foo(bar):
    return bar

example_module.py:

def example(arg):
    return foo(arg)

测试.py:

print(example('derp'))

如何构建 test.py、example_module.py 和 __init__.py 中的导入语句,以便在包目录外部(即 test.py)和包本身(即 foo_module.py 和 example_module.py)内工作?我尝试的一切都会给出Parent module '' not loaded, cannot perform relative importImportError: No module named 'module_name'

另外,作为旁注(根据 PEP 8):“非常不鼓励对包内导入进行相对导入。始终对所有导入使用绝对包路径。即使现在 PEP 328 已在 Python 2.5 中完全实现,它的样式明确的相对导入是不鼓励的;绝对导入更便携,通常更具可读性。”

我正在使用 Python 3.3。

4

2 回答 2

2

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.

于 2013-01-20T16:55:32.713 回答
2

我希望包中所有模块的成员都在包的命名空间中,并且我不希望模块本身在命名空间中。

我能够通过调整我在 Python 2 中使用的东西来自动导入插件以在 Python 3 中也能工作来做到这一点。

简而言之,它是这样工作的:

  1. 包的__init__.py文件导入同一包目录中的所有其他 Python 文件,但名称以'_'(下划线)字符开头的文件除外。

  2. 然后它将导入模块名称空间中的任何名称添加到模块名称__init__(也是包的名称空间)的名称中。请注意,我必须example_moduleimport 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 .foo_module import foo  # added

def example(arg):
    return foo(arg)
于 2013-01-20T20:17:54.213 回答