从 Python 中的相对路径导入
Posted
技术标签:
【中文标题】从 Python 中的相对路径导入【英文标题】:Importing from a relative path in Python 【发布时间】:2011-11-22 06:55:47 【问题描述】:我有一个存放客户端代码的文件夹、一个存放服务器代码的文件夹,以及一个存放它们之间共享的代码的文件夹
Proj/
Client/
Client.py
Server/
Server.py
Common/
__init__.py
Common.py
如何从 Server.py 和 Client.py 导入 Common.py?
【问题讨论】:
相关:***.com/q/72852/1025391 【参考方案1】:我使用的方法与上面提到的 Gary Beardsley 类似,只是略有改动。
文件名:Server.py
import os, sys
script_path = os.path.realpath(os.path.dirname(__name__))
os.chdir(script_path)
sys.path.append("..")
# above mentioned steps will make 1 level up module available for import
# here Client, Server and Common all 3 can be imported.
# below mentioned import will be relative to root project
from Common import Common
from Client import Client
【讨论】:
【参考方案2】:不要进行相对导入。
来自PEP8:
强烈建议不要使用包内导入的相对导入。
将所有代码放入一个超级包(即“myapp”),并为客户端、服务器和通用代码使用子包。
更新: “Python 2.6 和 3.x 支持正确的相对导入 (...)”。详情请见Dave's answers。
【讨论】:
想象一下,您在“if __name__ == "__main__":
”行之后将一些代码添加到客户端和服务器的末尾。也就是说,您希望能够将它们用作独立脚本。如何正确地做到这一点?我认为这是一个非常常见的用例,应该得到支持。为什么不鼓励?
我很惊讶“不要这样做”是“我如何...”问题的公认答案(好吧,Rails 很有趣,我刚刚遇到了同样的问题,我通过以下方式完成了这项工作:
结合linux命令ln
,我们可以让事情变得简单很多:
1. cd Proj/Client
2. ln -s ../Common ./
3. cd Proj/Server
4. ln -s ../Common ./
而且,现在如果你想将some_stuff
从文件:Proj/Common/Common.py
导入到你的文件:Proj/Client/Client.py
,就像这样:
# in Proj/Client/Client.py
from Common.Common import some_stuff
而且,这同样适用于Proj/Server
,也适用于setup.py
进程,
a same question discussed here,希望对你有帮助!
【讨论】:
【参考方案4】:2014 年 11 月编辑(3 年后):
Python 2.6 和 3.x 支持适当的相对导入,您可以避免做任何不合时宜的事情。使用这种方法,您知道您获得的是 relative 导入,而不是 absolute 导入。 '..' 的意思是,转到我上面的目录:
from ..Common import Common
需要注意的是,这仅在您从包的外部将python作为模块运行时才有效。例如:
python -m Proj
原始的hacky方式
这种方法在某些情况下仍然很常用,在这些情况下,您实际上并没有“安装”您的包。例如,它在 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' 模块。
【讨论】:
不要手动修改python模块路径,可能只是为了快速破解。使用 distutils、setuptools 等学习 Python 包管理通常是解决此类问题的必备技能。 @SaschaGottfried 完全同意,尽管如果您不制作可分发的包,这可能无关紧要。例如,在 Django 中,您永远不会真正使用 distutils 安装您的应用程序,因此上述方法很容易破解。但无论如何,我已经用我这些天要做的事情编辑了答案。 感谢您回答实际问题,而不是宣传正确的技术。进行相对导入有很多充分的理由。 要再上一层,每层使用一个额外的点。 @jxramos ex:from ...myfile
转到 ../../myfile
@WattsInABox 你将如何上到另一个目录中的文件,比如../../mydir2/myfile
?【参考方案5】:
进行相对导入是绝对可以的!以下是 little 'ol me 所做的:
#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
【讨论】:
但是您最好知道 sys.argv[0] 实际指向的位置 - 它(prolly)不是您启动 python 时所在的目录。 这是一个快速破解,有很多陷阱。但问题也好不到哪里去。 写得很清楚,但是Dave's answer 中的原始hack 更好,因为它使用__file__
从当前文件中获取正确的关系【参考方案6】:
默认导入方法已经是“相对”的,来自 PYTHONPATH。默认情况下,PYTHONPATH 与原始源文件的文件夹一起指向某些系统库。如果使用 -m 运行模块,则当前目录将添加到 PYTHONPATH。因此,如果您的程序的入口点在 Proj 内部,那么使用 import Common.Common
应该可以在 Server.py 和 Client.py 中使用。
不要进行相对导入。它不会按照你想要的方式工作。
【讨论】:
如果这是真的,为什么最重要的答案没有这样说?这行得通吗?以上是关于从 Python 中的相对路径导入的主要内容,如果未能解决你的问题,请参考以下文章