Python目录转包后导入RecipeManager类失败,求失效原因
我知道这个问题已有相关提问,试过现有解决方案但没效果。我想把目录转为Python包,将recipeProject.py里的RecipeManager类导入到testExportRecipes.py中,同时保持清晰的目录结构(测试文件单独放在专属文件夹)。用文件开头注释的sys.path方案能正常运行,但我更倾向于包化导入的方式,想搞清楚当前方案失效的原因。最后我试过按照Stack Overflow的方法从项目父目录运行文件,问题还是没解决。
当前代码片段
testExportRecipes.py
# import os, sys # CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) # sys.path.append(os.path.dirname(CURRENT_DIR)) import unittest from NewProjectJustDropped.recipePackage.recipeProject import RecipeManager class TestRecipeManagement(unittest.TestCase): def test_exported_JSON_file(self): rm = RecipeManager()
recipeProject.py(片段)
import json import os class RecipeManager: def __init__(self): self.data = [ { "id": 0, "recipeName": "McBurger", "recipeAuthor": "Sam", "prepTime": 10, "cookTime": 12, "servingSize": 1, "ingredients": [ {"ingredientName": "bun", "quantity": 1, "measurement": "unit"}, {"ingredientName": "secretPatty", "quantity": 1, "measurement": "unit"}, {"ingredientName": "specialMayo", "quantity": 10, "measurement": "grams"}, {"ingredientName": "specialSauce", "quantity": 20, "measurement": "grams"}, {"ingredientName": "lettuce", "quantity": 8, "measurement": "grams"}, {"ingredientName": "tomato", "quantity": 8, "measurement": "grams"} ], "instructions": { "1": "Assemble the bun and the secret patty.", "2": "Spread special mayo and special sauce on the bun.", "3": "Add lettuce and tomato on top.", "4": "Cook the assembled burger for 12 minutes." } } ] def viewRecipe(self): # this method should print all recipes to the screen. pass
- 缺少
__init__.py文件:Python要把目录识别为合法包,必须在每个包级目录下放置空的__init__.py文件。如果你的NewProjectJustDropped、recipePackage目录下没有这个文件,Python不会把它们当作可导入的包。 - 导入路径与实际目录结构不匹配:如果你的
testExportRecipes.py是放在NewProjectJustDropped内部的tests文件夹里,那用from NewProjectJustDropped.recipePackage...这种绝对路径就会出错——因为此时测试文件已经在NewProjectJustDropped包内部,应该用相对路径或者直接从recipePackage开始导入。 - Python路径未包含项目根目录:即使你从父目录运行文件,如果项目根目录没被加入Python的
sys.path列表,Python依然找不到NewProjectJustDropped这个顶级包。
假设你想要的规范目录结构是这样:
你的项目根目录/ ├─ NewProjectJustDropped/ │ ├─ __init__.py │ ├─ recipePackage/ │ │ ├─ __init__.py │ │ └─ recipeProject.py │ └─ tests/ │ ├─ __init__.py │ └─ testExportRecipes.py
添加
__init__.py文件
在NewProjectJustDropped、recipePackage、tests这三个目录下各创建一个空的__init__.py文件,让Python把它们识别为包。调整导入语句
因为testExportRecipes.py在NewProjectJustDropped/tests目录下,属于NewProjectJustDropped包的子目录,所以导入语句应该改成:from recipePackage.recipeProject import RecipeManager正确运行测试
从项目根目录(也就是包含NewProjectJustDropped的那个文件夹)运行测试命令:# 使用unittest运行 python -m unittest NewProjectJustDropped.tests.testExportRecipes # 或者如果用pytest python -m pytest NewProjectJustDropped/tests/testExportRecipes.py -v这种方式会自动把项目根目录加入Python路径,确保包能被正确找到。
可选:更规范的项目配置
如果你想让包在任何环境下都能被导入,可以在项目根目录创建pyproject.toml文件,内容如下:[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "NewProjectJustDropped" version = "0.1.0" packages = ["NewProjectJustDropped"]然后在项目根目录运行
pip install -e .,把包以可编辑模式安装,之后不管在哪个位置都能直接导入recipePackage里的模块。
内容的提问来源于stack exchange,提问作者Samson

