从Python中的相对路径导入


Answers:


140

编辑2014年11月(3年后):

Python 2.6和3.x支持适当的相对导入,在这里您可以避免做任何棘手的事情。使用这种方法,您知道您得到的是相对导入而不是绝对导入。“ ..”表示转到我上方的目录:

from ..Common import Common

请注意,仅当您从包外部将python作为模块运行时,此方法才有效。例如:

python -m Proj

原始的骇客方式

在某些情况下,实际上您从来没有“安装”软件包,这种方法仍然很常用。例如,它在Django用户中很流行。

您可以将Common /添加到您的sys.path中(python用来导入内容的路径列表):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) 只需为您提供当前python文件所在的目录,然后我们导航至该目录的“ Common /”并导入“ Common”模块。


2
请勿手动修改python模块路径,可能仅用于快速破解。使用distutils,setuptools等学习Python软件包管理通常是解决此类问题的必备技能。
Sascha Gottfried 2014年

1
@SaschaGottfried完全同意,尽管如果您不制作可分发的程序包,也可能没关系。例如,在Django中,您从未真正使用distutils安装应用程序,因此上述方法很容易破解。但是无论如何,我已经用这些天的内容编辑了答案。
戴夫

32
感谢您回答实际问题,而不是讲讲适当的技术。有很多充分的理由进行相对进口。
shrewmouse

您将如何提升一个以上的水平?
jxramos

10
要再升一级,请为每个等级使用一个附加的点。@jxramos前:from ...myfile../../myfile
WattsInABox

10

有趣的是,我刚刚遇到了一个相同的问题,我可以通过以下方式获得这项工作:

结合linux命令ln,我们可以使事情变得更加简单:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

而且,现在,如果some_stuff要从file:Proj/Common/Common.py导入到file:中Proj/Client/Client.py,就像这样:

# in Proj/Client/Client.py
from Common.Common import some_stuff

并且,同样适用于Proj/Server,也适用于setup.py过程, 此处讨论的相同问题,希望对您有所帮助!


10

不要做相对导入。

PEP8

强烈建议不要将相对进口用于包装内进口。

将所有代码放入一个超级包(即“ myapp”)中,并将子包用于客户端,服务器和通用代码。

更新:Python 2.6和3.x支持正确的相对导入(...) ”。有关更多详细信息,请参见Dave的答案


1
假设您在“ if __name__ == "__main__":”行之后将一些代码添加到客户端和服务器的末尾。也就是说,您希望能够将它们用作独立脚本。如何正确做?我认为这是一个应该支持的非常普遍的用例。为什么不鼓励?
贾巴2014年

83
我很惊讶,“不这样做”是公认的答案是“我该怎么办?”的问题(当然,除了为Rails <G>。)有偶尔的理由这样做。我使用类似于Dave建议的解决方案。
汤姆·威尔逊

1
@TomWilson:这不是纯粹的“不做”答案。下面有“以这种方式执行”。
米哈尔Šrajer

2
有人应该告诉他们在Numpy的家伙!他们使用相对进口的吨!
奥斯丁

12
此答案不适用于当前版本的Python。引用的部分不再在PEP 8中找到。如今,它看起来像是:“明确的相对进口是绝对进口的一种可接受的替代方法,尤其是当处理复杂的包装布局时,使用绝对进口会不必要地冗长”
moooeeeep

8

进行相对导入绝对可以!这是我的小事:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py

1
但是您最好知道sys.argv [0]实际指向的位置-它(完全)不是启动python时所在的目录。
CarlH 2014年

这是一个快速的技巧,有很多陷阱。但是问题甚至没有更好。
Sascha Gottfried 2014年

1
这写得很清楚,但是Dave回答中的原始技巧会更好,因为它__file__可以从当前文件中获取正确的关系
John Neuhaus

4

从PYTHONPATH开始,默认的导入方法已经是“相对的”。默认情况下,PYTHONPATH是某些系统库以及原始源文件的文件夹。如果使用-m运行以运行模块,则当前目录将添加到PYTHONPATH中。因此,如果程序的入口点位于Proj内,则import Common.Common在Server.py和Client.py内都可以使用。

不要做相对导入。它不会按您希望的那样工作。


1
如果是这样,为什么最重要的答案不这样说?这行不行?
匿名
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.