从Python中的相对路径导入

发布于 2024-12-06 05:41:40 字数 250 浏览 3 评论 0原文

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

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

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

I have a folder for my client code, a folder for my server code, and a folder for code that is shared between them

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

How do I import Common.py from Server.py and Client.py?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

过潦 2024-12-13 05:41:40

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

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

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”模块。

EDIT Nov 2014 (3 years later):

Python 2.6 and 3.x supports proper relative imports, where you can avoid doing anything hacky. With this method, you know you are getting a relative import rather than an absolute import. The '..' means, go to the directory above me:

from ..Common import Common

As a caveat, this will only work if you run your python as a module, from outside of the package. For example:

python -m Proj

Original hacky way

This method is still commonly used in some situations, where you aren't actually ever 'installing' your package. For example, it's popular with Django users.

You can add Common/ to your sys.path (the list of paths python looks at to import things):

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

os.path.dirname(__file__) just gives you the directory that your current python file is in, and then we navigate to 'Common/' the directory and import 'Common' the module.

土豪 2024-12-13 05:41:40

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

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

Funny enough, a same problem I just met, and I get this work in following way:

combining with linux command ln , we can make thing a lot simper:

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

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

And, now if you want to import some_stuff from file: Proj/Common/Common.py into your file: Proj/Client/Client.py, just like this:

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

And, the same applies to Proj/Server, Also works for setup.py process,
a same question discussed here, hope it helps !

狼亦尘 2024-12-13 05:41:40

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

#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

Doing a relative import is absolulutely OK! Here's what little 'ol me does:

#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
爱,才寂寞 2024-12-13 05:41:40

不要进行相对导入。

来自 PEP8

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

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

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

Don't do relative import.

From PEP8:

Relative imports for intra-package imports are highly discouraged.

Put all your code into one super package (i.e. "myapp") and use subpackages for client, server and common code.

Update:
"Python 2.6 and 3.x supports proper relative imports (...)". See Dave's answers for more details.

最后的乘客 2024-12-13 05:41:40

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

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

The default import method is already "relative", from the PYTHONPATH. The PYTHONPATH is by default, to some system libraries along with the folder of the original source file. If you run with -m to run a module, the current directory gets added to the PYTHONPATH. So if the entry point of your program is inside of Proj, then using import Common.Common should work inside both Server.py and Client.py.

Don't do a relative import. It won't work how you want it to.

痴情换悲伤 2024-12-13 05:41:40

我使用的方法与上面提到的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

Approch used by me is similar to Gary Beardsley mentioned above with small change.

Filename: 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
秋叶绚丽 2024-12-13 05:41:40

创建一个简单的示例

假设我们在当前工作目录中运行 ls -R ,结果如下:

./second_karma:
enemy.py  import.py  __init__.py  math

./second_karma/math:
fibonacci.py  __init__.py

我们运行此命令 $ python3 secondary-karma/import.py

< strong>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 secondary-karma/import.py 执行时,我正在执行一个模块,而不是一个包。因此 python 不知道 . 在这种情况下意味着什么
      • 修复:
        python3 -m secondary_karma.import
        
      • 现在 import.py 属于父包 second_karma,因此您的相对导入将起作用。

重要提示:

这些 __init__.py 是必需的,如果您没有它们,则必须先创建它们。

github 中的示例

Create a simple example

Assume we run ls -R in the current working directory and this is the result:

./second_karma:
enemy.py  import.py  __init__.py  math

./second_karma/math:
fibonacci.py  __init__.py

And we run this command $ python3 second-karma/import.py

init.py is an empty file but it should exists.

Now let's see what is inside the second-karma/import.py:

from .math.fibonacci import Fibonacci
fib = Fibonacci()
print(fib.get_fibonacci(15))

And what is inside the 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

Now the last file is 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

Now a simple answer why it was not working:

  • Python has a concept of packages, which is basically a folder containing one or more modules, and zero-or-more packages.
  • When we launch python, there are two ways of doing it:
    • Asking python to execute a specific module (python3 path/to/file.py).
    • Asking python to execute a package.
  • The issue is that import.py makes reference to importing .math
    • The .math in this context means "go find a module/package in the current package with the name math"
    • Trouble:
      • When I execute as $ python3 second-karma/import.py I am executing a module, not a package. thus python has no idea what . means in this context
      • Fix:
        python3 -m second_karma.import
        
      • Now import.py is of parent package second_karma, and thus your relative import will work.

Important note:

Those __init__.py are necessary and if you have not them you must create them first.

An example in github

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文