pythonic模块组织 - 如何引用根目录中的文件?

6 python unix module pythonpath

我把我的python代码放在​​一个名为"project"的文件夹中,所以我的代码文件在project/*.py中.我想在其中包含子模块,例如

project/code.py # where code lives
project/mymodule1  # where more code lives
project/mymodule2
Run Code Online (Sandbox Code Playgroud)

每个模块目录都有自己的init .py文件,例如

project/mymodule1/__init__.py
Run Code Online (Sandbox Code Playgroud)

假设我在mymodule1(project/mymodule1/test.py)中有一个文件"test.py",我想从"代码"中引用一些东西,例如导入函数"myfunc"

== project/mymodule1/test.py ==
from code import myfunc
Run Code Online (Sandbox Code Playgroud)

问题是除非用户在他们的PYTHONPATH中放置了"project /"目录,否则将找不到"代码".有没有办法避免这种情况并使用某种"相对路径"来导入myfunc,例如

from ../code import myfunc
Run Code Online (Sandbox Code Playgroud)

基本上,我不想强​​制代码的用户改变PYTHONPATH,除非我可以在我的脚本中以编程方式为它们做.我希望它可以开箱即用.

如何才能做到这一点?两种解决方案都很好:以编程方式改变PYTHONPATH,或者更理想的是,使用某种相对导入来引用"代码",因为即使我不知道"project/code.py"在用户的计算机上的哪个位置,我知道在哪里它与"myfunc"有关.

编辑:有人可以显示包内导入的正确示例吗?我试过,从"mymodule1"做:

from .. import foo
Run Code Online (Sandbox Code Playgroud)

其中"foo"在code.py中,但它不起作用.我在mymodule1中有init .py,所以:

project/code.py
project/mymodule1/__init__.py
project/mymodule1/module1_code.py
Run Code Online (Sandbox Code Playgroud)

其中module1_code.py尝试导入foo,这是在"code.py"中定义的函数.

编辑:我仍然有一个主要的困惑是,即使采用响应我的消息给出的示例,显示项目/ sub1 /测试层次结构,你仍然不能"cd"到sub1并执行"python test.py"并拥有它工作.用户必须位于包含"project"的目录中,并执行"import project.sub1.test".无论用户在哪个目录,我都希望这个工作.在这种情况下,用户必须执行文件"test.py",它位于project/sub1 /中.所以测试用例是:

$ cd project/sub1
$ python test.py
Run Code Online (Sandbox Code Playgroud)

产生错误:

ValueError: Attempted relative import in non-package
Run Code Online (Sandbox Code Playgroud)

怎么能修好?

谢谢.

bjl*_*aub 4

这在 Python 2.5 及更高版本中是可能的。请参阅包内参考文档。

有几点需要注意:

如果您打算让用户在某个地方安装您的软件包(例如使用 distutils 或 setuptools),那么project它可能已经在搜索路径中,您可以将相对导入更改为from project.code import ...或类似。

如果您的用户将包安装到非标准目录(例如他们的主目录、不在 中的其他位置sys.path等),我的观点是,指示用户修改PYTHONPATH而不是以编程方式会减少混乱改变sys.path

如果您根本不希望用户安装您的代码 - 例如,他们只需解压源代码、cd 到 的父目录project并运行脚本 - 然后是包内引用和相对进口可能会很好地工作。

编辑:根据请求,这是一个示例:

假设包布局如下:

project/
    __init__.py (empty)
    code.py
    sub1/
        __init__.py (empty)
        test.py
Run Code Online (Sandbox Code Playgroud)

现在,内容project/code.py是:

# code.py (module that resides in main "project" package)

def foo():
    print "this is code.foo"
Run Code Online (Sandbox Code Playgroud)

并且,内容project/sub1/test.py是:

# test.py (module that resides in "sub1" subpackage of main "project" package)

from ..code import foo
foo()
Run Code Online (Sandbox Code Playgroud)

因此,从相对路径test.py导入名称,它使用包内引用让我们返回到我们正在执行的包的父级(即部分)内的模块。foo..codecode.py..sub1.test

要测试这一点:

shell$ (cd to directory where "project" package is located)
shell$ python
Python 2.6.1 (r261:67515, Aug  2 2010, 20:10:18) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import project.sub1.test
this is code.foo
Run Code Online (Sandbox Code Playgroud)

请注意,语法中的双点from .. import X仅将您带到父包,但您可以在该包中指定模块。

换句话说,from .. import X在这种情况下相当于from project import X,因此X必须是 中的模块project或 中的类/函数/名称project/__init__.py

因此,from ..code import X等价于from project.code import X.