如何导入包中所有模块的成员?

时间:2013-01-20 16:30:40

标签: python import python-3.x package

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

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语句,以便从包目录外部(即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。

2 个答案:

答案 0 :(得分: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 )。

答案 1 :(得分:2)

  

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

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

简而言之,以下是它的工作原理:

  1. 包的__init_.py文件导入同一包目录中不以'_'(下划线)字符开头的所有其他Python文件。

  2. 然后将导入模块命名空间中的任何名称添加到__init__模块的名称(也是包的名称空间)。注意我必须从example_module明确import foo模块foo_module。{/ p>

  3. 以这种方式执行操作的一个重要方面是实现它是动态的,并且不需要将包模块名称硬编码到__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)