簡體   English   中英

從 Python 中的相對路徑導入

[英]Importing from a relative path in Python

我有一個用於存放客戶端代碼的文件夾、一個存放服務器代碼的文件夾以及一個存放它們之間共享的代碼的文件夾

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

如何從 Server.py 和 Client.py 導入 Common.py?

編輯 2014 年 11 月(3 年后):

Python 2.6 和 3.x 支持適當的相對導入,您可以避免做任何 hacky。 使用這種方法,您知道您獲得的是相對導入而不是絕對導入。 '..' 的意思是,轉到我上面的目錄:

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'模塊。

有趣的是,我剛剛遇到了同樣的問題,我通過以下方式完成了這項工作:

結合 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進程, 這里討論的同樣的問題,希望它有所幫助!

不要進行相對導入。

PEP8

非常不鼓勵用於包內導入的相對導入。

將所有代碼放入一個超級包(即“myapp”),並為客戶端、服務器和公共代碼使用子包。

更新:Python 2.6 和 3.x 支持正確的相對導入 (...) ”。 有關更多詳細信息,請參閱Dave 的答案

做相對導入是絕對OK的! 這是 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

默認導入方法已經是“相對”的,來自 PYTHONPATH。 默認情況下,PYTHONPATH 與原始源文件的文件夾一起指向某些系統庫。 如果使用 -m 運行模塊,則當前目錄將添加到 PYTHONPATH。 因此,如果您的程序的入口點在 Proj 內部,那么使用import Common.Common應該可以在 Server.py 和 Client.py 中工作。

不要進行相對導入。 它不會按照你想要的方式工作。

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

Python世界新手的簡單答案

創建一個簡單的例子

假設我們在當前工作目錄中運行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中的一個例子

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM