从 Python 中的相对路径导入[重复]
- 2025-03-04 08:24:00
- admin 原创
- 95
问题描述:
我有一个用于存放客户端代码的文件夹、一个用于存放服务器代码的文件夹和一个用于存放它们之间共享的代码的文件夹
Proj/
Client/
Client.py
Server/
Server.py
Common/
__init__.py
Common.py
如何从 Server.py 和 Client.py 导入 Common.py?
解决方案 1:
编辑于2014年11月(3年后):
Python 2.6 和 3.x 支持正确的相对导入,这样您就可以避免做任何黑客行为。使用此方法,您知道您获得的是相对导入,而不是绝对导入。'..' 表示转到我上级目录:
from ..Common import Common
需要注意的是,这仅在您将 Python 作为模块从包外部运行时才有效。例如:
python -m Proj
原始的 hack 方式
在某些情况下,这种方法仍然很常用,在这种情况下您实际上从未“安装”过您的包。例如,它深受 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:
有趣的是,我刚刚遇到了同样的问题,我通过以下方式完成了这项工作:
结合 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
过程,
这里讨论的相同问题,希望它有所帮助!
解决方案 3:
执行相对导入绝对没问题!下面是我所做的:
#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
解决方案 4:
不要进行相对导入。
来自PEP8:
强烈不建议使用相对导入进行包内导入。
将所有代码放入一个超级包(即“myapp”),并使用子包来存放客户端、服务器和通用代码。
更新:
“ Python 2.6 和 3.x 支持正确的相对导入 (...) ”。有关更多详细信息,请参阅Dave 的回答。
解决方案 5:
默认导入方法已经是“相对”的,来自 PYTHONPATH。默认情况下,PYTHONPATH 是一些系统库以及原始源文件的文件夹。如果您使用 -m 运行模块,则当前目录将添加到 PYTHONPATH。因此,如果您的程序的入口点位于 Proj 内部,那么使用import Common.Common
应该可以在 Server.py 和 Client.py 中工作。
不要进行相对导入。它不会按你希望的方式工作。
解决方案 6:
我使用的方法与上面提到的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
解决方案 7:
创建一个简单的示例
假设我们ls -R
在当前工作目录中运行,结果如下:
./second_karma:
enemy.py import.py __init__.py math
./second_karma/math:
fibonacci.py __init__.py
我们运行这个命令$ python3 second-karma/import.py
*init.py是一个空文件但它应该存在。*
现在让我们看看里面有什么second-karma/import.py
:
from .math.fibonacci import Fibonacci
fib = Fibonacci()
print(fib.get_fibonacci(15))
里面有什么second_karma/math/fibonacci.py
:
from ..enemy import Enemy
class Fibonacci:
enemy: Enemy
def __init__(self):
self.enemy = Enemy(150,900)
print("Class instantiated")
def get_fibonacci(self, which_index: int) -> int:
print(self.enemy.get_hp())
return 4
现在最后一个文件是second_karma/enemy.py
:
class Enemy:
hp: int = 100
attack_low: int = 180
attack_high: int = 360
def __init__(
self,
attack_low: int,
attack_high: int) -> None:
self.attack_low = attack_low
self.attack_high = attack_high
def getAttackPower(
self) -> {"attack_low": int, "attack_high": int}:
return {
"attack_low": self.attack_low,
"attack_high": self.attack_high
}
def get_hp(self) -> int:
return self.hp
现在简单回答一下为什么它不起作用:
Python 有一个包的概念,它基本上是一个包含一个或多个模块以及零个或多个包的文件夹。
当我们启动python时,有两种方法可以做到:
要求 python执行特定模块(
python3 path/to/file.py
)。要求 python执行一个包。
问题是
import.py
提到进口.math
在这种情况下,意思
.math
是“在当前包中查找名为 math 的模块/包”麻烦:
当我执行时,
$ python3 second-karma/import.py
我正在执行一个模块,而不是一个包。因此 python 不知道.
这个上下文中的意思使固定:
python3 -m second_karma.import
现在
import.py
是父包second_karma
,因此您的相对导入将起作用。
重要提示:
这些__init__.py
都是必需的,如果您还没有,您必须先创建它们。
github 上的一个例子
阅读
README.md
以更好地理解在提交之间来回查看以更深入地观察问题。
https://github.com/kasir-barati/my-python-journey/tree/main/second_karma
扫码咨询,免费领取项目管理大礼包!