从Python中的相对路径导入[重复]

问题描述 投票:0回答:7

我有一个用于存放客户端代码的文件夹、一个用于存放服务器代码的文件夹以及一个用于存放在它们之间共享的代码的文件夹

Proj/
    Client/
        Client.py
    Server/
        Server.py
    Common/
        __init__.py
        Common.py

如何从 Server.py 和 Client.py 导入 Common.py?

python python-3.x import shared-libraries relative-path
7个回答
219
投票

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

Python 2.6 和 3.x 支持适当的相对导入,您可以避免做任何黑客行为。通过这种方法,您知道您正在获得relative导入而不是absolute导入。 '..' 的意思是,转到我上面的目录:

from ..Common import Common

需要注意的是,只有当您从包的outside将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”模块。


12
投票

有趣的是,我刚刚遇到了同样的问题,我通过以下方式完成了这项工作:

结合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
过程, 这里讨论了同样的问题,希望有帮助!


11
投票

做相对导入绝对没问题!这是我所做的:

#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

11
投票

不要进行相对导入。

来自PEP8

强烈建议不要进行包内导入的相对导入。

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

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


6
投票

默认的导入方法已经是“相对”的,来自 PYTHONPATH。 PYTHONPATH 默认情况下与原始源文件的文件夹一起指向某些系统库。如果使用 -m 运行模块,当前目录将添加到 PYTHONPATH 中。因此,如果程序的入口点位于 Proj 内部,那么使用

import Common.Common
应该可以在 Server.py 和 Client.py 中工作。

不要进行相对导入。它不会按照你想要的方式工作。


2
投票

创建一个简单的示例

假设我们在当前工作目录中运行

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 中的示例


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
© www.soinside.com 2019 - 2024. All rights reserved.