[英]Python 3: importing a function from a python file in a parent directory
我是單元測試的新手,我正在嘗試在 python 3 中創建我的第一個單元測試文件。所以我只是通過模仿在線課程獲得了以下非常基本的文件夾結構。
D:\Projects\Projects\unit_testing_course # parent dir absolute path
unit_testing_course/ # root/parent folder
first_project.py # has a function called avg()
tests/
test_first_project.py # I want to import avg() into this file
test_first_project.py 是我用於單元測試的文件,我想從 first_project.py 導入 avg() 函數,它存在於它上面的父目錄中。
我在 Windows 10 上,我將 git bash 打開到以下路徑:'/d/Projects/Projects/unit_testing_course'(即包含 first_project.py 的父目錄,我試圖導入到 test_first_project 的模塊/函數.py 文件在測試子目錄中)。 我一直在運行python tests/test_first_project.py
我很快發現我不能使用諸如“from .. import first_project”或“from .. import avg”之類的東西,這會導致“ValueError:試圖在頂級包之外進行相對導入”錯誤消息。
因此,通過閱讀文檔,我了解到“from”和“import”都是用於處理模塊或包的指令。 https://docs.python.org/3/tutorial/modules.html
“Python 有一種方法可以將定義放在文件中,並在腳本或解釋器的交互式實例中使用它們。這樣的文件稱為模塊;來自模塊的定義可以導入到其他模塊或主模塊中(您可以在頂層和計算器模式下執行的腳本中訪問的變量集合)。
模塊是包含 Python 定義和語句的文件。 文件名是后綴 .py 的模塊名稱。 在模塊內,模塊的名稱(作為字符串)可用作全局變量 __name__ 的值。”
所以聽起來就 python 3 而言,每個 .py 文件都是一個模塊,模塊名稱本質上是 .py 文件名,末尾沒有 .py 擴展名。 聽起來我正在嘗試從 test_first_project.py 文件的父目錄中導入一個模塊。
該文檔鏈接似乎有助於解釋在當前目錄中有一個模塊的場景,您正在從中執行程序/python shell,而您只是試圖將該模塊中的函數導入該程序。
但在這種情況下,我們似乎需要實際告訴 python 在特定目錄中查找名為“first_project”的模塊,即 test_first_project.py 文件的父目錄。 我查看了關於模塊搜索路徑的部分, https://docs.python.org/3/tutorial/modules.html#the-module-search-path
當導入名為 spam 的模塊時,解釋器首先搜索具有該名稱的內置模塊。 如果未找到,它將在變量 sys.path 給出的目錄列表中搜索名為 spam.py 的文件。 初始化后,Python 程序可以修改 sys.path。 包含正在運行的腳本的目錄位於搜索路徑的開頭,在標准庫路徑之前。
然后我試了...
import sys
import os
p_dir_path = os.path.abspath('../')
sys.path.append(p_dir_path)
from first_project import avg
這仍然讓我得到相同的錯誤消息“ValueError:試圖在頂級包之外進行相對導入”。 我希望以編程方式修改 sys.path 可以改變事情......
那么我實際上需要做什么才能從父目錄導入模塊? 或者......在python中不可能做到這一點? 我是否需要使用包而不是模塊(即我是否需要在我的父目錄中創建一個init .py)?
我在 stackoverflow 上看到了關於嘗試在不同目錄和其他情況下導入文件的其他問題和帖子,但是模仿這些問題的語法並沒有幫助我,我想我在這上面花了太多時間。 我也確信我不是唯一一個想要創建單元測試並被導入語句、模塊和包問題所困擾的人。
您應該為您的項目適當地設置PYTHONPATH
變量。 在unit_testing_course
,運行
export PYTHONPATH=$(pwd)
在你的殼里。 並考慮以下代碼:
first_project.py
def avg(l):
return sum(l)/len(l) if len(l) > 0 else 0
tests/test_first_project.py
import unittest
from first_project import avg
class Test(unittest.TestCase):
...
tests/__init__.py
from .test_first_project import *
運行python -m unittest tests
將按需要運行(前提是python
指向您想要的 python 版本)。 您還可以使用virtualenv
並修改其venv/bin/activate
以自動執行此路徑設置。 當您的項目繼續增長時,我建議在基本目錄中有兩個單獨的目錄 - 一個用於項目本身,另一個用於測試。 然后分別在每個中使用相對導入。 如果您選擇打包或將其用作子模塊或類似的東西,這將使您的項目變得靈活。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.