簡體   English   中英

我是否需要將項目目錄添加到每個腳本中的系統路徑以從另一個目錄導入函數?

[英]Do I need to add my project directory to the system path in every script to import a function from another directory?

我正在努力保持數據科學項目組織良好,所以我在我的src目錄中創建了一個名為utils目錄,其中包含一個名為helpers.py的文件,其中包含一些將在許多腳本中使用的輔助函數。 如何將func_namesrc/utils/helpers.py導入到完全不同的目錄(例如src/processing/clean_data.py的文件的最佳實踐是什么?

我看到了這個問題的答案 ,我已經實現了一個有效的解決方案,但這感覺很難看:

 sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))

我這樣做了嗎? 我是否需要將此添加到每個要導入func_name腳本中,例如train_model.py

我當前的項目文件夾結構:

myproject
    /notebooks
        notebook.ipynb
    /src
        /processing
            clean_data.py
        /utils
            helpers.py
        /models
            train_model.py
        __init__.py

示例文件:

# clean_data.py

import os
import sys

sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))
from src.utils.helpers import func_name

func_name()


# helpers.py

def func_name():
    print('I'm a helper function.')

正確的方法是使用__init__.py . setuptoolssetup.pysetuptools Python包:

myPackage/
    myPackage/
        __init__.py
    setup.py

鏈接包含所有步驟。

首先,讓我描述一下Python模塊Python包之間的區別,以便我們兩個人都在同一頁面上。


模塊是在一個導入下導入並使用的單個.py文件(或多個文件)

import aModuleName # Here 'aModuleName' is just a regular .py file.

然而,包是給出包層次結構的目錄中的模塊集合 包中包含不同的__init__.py文件。

from aPackageName import aModuleName # Here 'aPackageName` is a folder with a `__init__.py` file # and 'aModuleName', which is just a regular .py file.


因此,當我們有一個名為proj-dir的項目目錄時,結構如下⤵

proj-dir --|--__init__.py --package1 --|--__init__.py --|--module1.py --package2 --|--__init__.py --|--module2.py

🔎請注意,我還在proj-dir本身添加了一個空的__init__.py ,這也使它成為一個包。

👍現在,如果你想從包2模塊2導入任何Python對象到包1模塊1,然后在文件module1.py import語句會

from package2.module2 import object2 # if you were to import the entire module2 then, from package2 import module2

我希望這個簡單的解釋能夠澄清你對Python導入機制的疑慮並解決問題。 如果沒有,那么在這里做評論。 😊

首先讓我澄清一下,如果要使用其中的一部分,導入整個模塊,則不是一個好主意。 而不是你可以使用from來導入庫/包下的特定功能。 通過這樣做,您可以使您的程序在內存和性能方面更高效。

要了解更多信息,請參考以

  1. '導入模塊'或'從模塊導入'
  2. 導入和導入之間的差異

網讓我們看看解決方案。

在開始使用解決方案之前,讓我向您闡明__init__.py文件的用法。 它告訴python解釋器,存在的* .py文件是可導入的,這意味着它們是模塊, 並且/可能是包的一部分。

因此,如果您沒有N個子目錄,則必須將__init__.py文件放在所有這些子目錄中,以便它們也可以導入。 __init__.py文件中,您還可以添加一些其他信息,例如應包含哪些路徑,默認函數,變量,范圍等等。 要了解這些只是谷歌關於__init__.py文件或采取一些python庫並通過相同的__init__.py文件來了解它。 (這就是解決方案)

更多信息:

  1. 模塊
  2. 是pythonic

正如@Sushant Chaudhary所說,你的項目結構應該是這樣的

proj-dir
 --|--__init__.py
   --package1
     --|--__init__.py
     --|--module1.py
   --package2
     --|--__init__.py
     --|--module2.py

那么現在,如果我把__init__.py文件放在我上面的目錄下,它是否可以導入並且工作正常?

是的,不

是的:

如果要導入該項目/包目錄中的模塊。 例如在你的情況下
您正在from package1 import module1 module1導入pakage2.module2中from package1 import module1

在這里你必須導入子模塊內的基礎目錄為什么? 如果從同一個地方運行模塊,項目將運行正常。 ie:在package2中作為python module2.py但是會拋出ModuleNotFoundError如果從其他目錄運行模塊。 ie:除了package2之外的任何其他路徑 ,例如在proj-dir下作為python package2/module2.py 這就是你的情況。 您正在從project-dir運行該模塊。

那么如何解決這個問題呢?

1-您必須在module2.py中將基於路徑的路徑附加到系統路徑

from sys import path
dir_path = "/absolute/path/to/proj-dir"
sys.path.insert(0, dir_path)

因此module2將能夠找到package1(以及其中的module1)。

2-您必須在proj-dir下的__init__.py文件中添加所有子模塊路徑。

例如:

#__init__.py under lxml
# this is a package

def get_include():
    """
    Returns a list of header include paths (for lxml itself, libxml2
    and libxslt) needed to compile C code against lxml if it was built
    with statically linked libraries.
    """
    import os
    lxml_path = __path__[0]
    include_path = os.path.join(lxml_path, 'includes')
    includes = [include_path, lxml_path]

    for name in os.listdir(include_path):
        path = os.path.join(include_path, name)
        if os.path.isdir(path):
            includes.append(path)

    return includes

這是lxml__init__.py文件(用於解析html,xml數據的python庫)。 您可以在具有子模塊的任何python庫下引用任何__init__.py文件。 ex(os,sys) 在這里我提到了lxml,因為我覺得你很容易理解。 您甚至可以檢查其他庫/包下的__init__.py文件。 每個人都有自己的方式來定義子模塊的路徑。

沒有

如果您嘗試導入目錄外的模塊。 然后,您必須導出模塊路徑,以便其他模塊可以將它們找到環境變量中。 這可以通過將基礎目錄的絕對路徑附加到PYTHONPATHPATH來直接完成。

要了解更多:

  1. OS中的PATH變量
  2. PYTHONPATH變量

因此,要解決您的問題,請在proj-dir下的__init__.py文件中包含所有子模塊的路徑,並將/ absolute / path /添加到/ proj-dir或者添加到PYTHONPATHPATH

希望答案能解釋您對__init__.py使用並解決您的問題。

在Linux上,您只需將src目錄的父文件夾的路徑添加到~/.local/lib/python3.6/site-packages/my_modules.pth 請參閱使用.pth文件 然后,您可以從系統中的任何位置導入src模塊。

NB1:用你想要使用的任何Python版本替換python3.6

NB2:如果你使用Python2.7(不知道其他版本),你需要在src/src/utils創建__init__.py (空)文件。

NB3:任何名稱.pth文件都可以用於my_modules.pth

是的,您只能從已安裝的軟件包或工作目錄或子目錄中的文件導入代碼。

我看到它的方式,你的問題將得到解決,如果你將安裝你的模塊或包,如安裝和安裝,然后導入(numpy,xml,json等)

我還有一個我經常在我的所有項目中使用的軟件包, ulitilies ,我知道這對導入很痛苦。

這里有一個關於如何打包python應用程序以使其可以進行pip安裝的描述: https//marthall.github.io/blog/how-to-package-a-python-app/

  • 導航到python安裝文件夾

  • 導航到lib

  • 導航到站點包

  • 創建一個名為any_thing_you_want.pth的新文件

  • 使用您喜歡的文本編輯器在該文件中鍵入.../src/utils/helpers.py

注意: scr/utils/helpers.py之前的省略號看起來像: C:/Users/blahblahblah/python_folders/scr... < - 你需要這個!

這是一種廉價的出路,但它保持代碼清潔,並且是最不復雜的。 缺點是,對於您的模塊所在的每個文件夾,example.pth都需要它們。 好處:與Windows一起使用Windows 10

暫無
暫無

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

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