我正在开发一个包含类似于以下文件结构的包:
test.py
package/
__init__.py
foo_module.py
example_module.py
如果我在test.py中调用import package,我希望包模块看起来类似于:
>>> vars(package)
mapping_proxy({foo:
换句话说,我希望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。
我只是盲目地把它放在这里不试试:from package import *怎么样?
@Skyler,在哪个档案?
I want the members of all modules in package to be in package's
namespace, and I do not want the modules themselves to be in the
namespace.
我能够通过调整我在Python 2中使用的东西来自动导入插件以在Python 3中工作。
简而言之,这是它的工作原理:
程序包的__init_.py文件导入同一程序包目录中不以'_'(下划线)字符开头的所有其他Python文件。
然后,它将导入的模块命名空间中的任何名称添加到__init__模块的名称(也是包的名称空间)。注意我必须从foo_module明确地example_module模块example_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)。
+1:例如,来自stdlib的multiprocessing包使用这种技术
如果我直接执行example_module.py或__init__.py,我会收到导入错误,但test.py有效。获得test.py显然是最重要的工作,但有没有办法(没有try / catch)让其他两个工作正常?我想这就是我首先发布这个问题的原因。
这也将模块保存在包的命名空间中。现在我想到了,这是Python的要求吗?
@TylerCrompton:一般来说,没有,没有好办法可以在一个包中运行一个模块作为脚本。可以在example_module.py中添加类似sys.path.append("..")的内容,但它是一个hack并且可能无法正常工作(您也可以尝试-m命令行选项)。 Python开发人员几乎已经说过,在包中运行脚本从根本上是破坏了设计,并且他们不打算永远支持它(尽管它经常被新的Python程序员请求)。
我不确定我理解你关于包命名空间的问题。如果你输入import package.foo_module,你确实会得到foo_module模块,但是如果你只是import package,那么package.foo_module(仅在package.foo和package.bar)不会自动出现任何内容。即使from package import *(通常不鼓励)也应该做正确的事情。