【问题标题】:Python 3: importing a function from a python file in a parent directoryPython 3:从父目录中的 python 文件导入函数
【发布时间】:2019-04-14 19:58:40
【问题描述】:

我是单元测试的新手,我正在尝试在 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:尝试相对导入超出顶级包' 错误消息。

因此,通过阅读文档,我了解到“来自”和“导入”都是用于处理模块或包的指令。 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 上看到了关于尝试在不同目录和其他情况下导入文件的其他问题和帖子,但在这些问题上模仿语法并没有帮助我,我认为我花了太多时间对此。我也确信我不是唯一一个想要创建单元测试并被导入语句、模块和包问题所牵制的人。

【问题讨论】:

  • 从父目录运行它:python tests/test_first_project.py 或简单地python -m unittest。可能需要tests/__init__.py
  • 有趣的是,我已经在这样做了。我有 git bash 打开到 /d/Projects/Projects/unit_testing_course,继续使用 'python tests/test_first_project.py' 但我收到这些错误。
  • 好吧,你写了很多文字,而显示的代码却很少。
  • 我在父目录 (unit_testing_course) 和子目录 (unit_testing_course/tests/) 中都有 init.py。 from first_project import avg 仍然失败并显示消息 ModuleNotFoundError: No module named 'first_project'。是的,我知道这里有很多文字,我可能使这个问题过于复杂。在这一点上,我真的对 python 包和模块感到困惑,即使是这个相对简单的任务,只是试图从不同的目录中获取一个函数。对于这个问题,我没有超过我真正包含的 5 行代码。

标签: python python-3.x


【解决方案1】:

您应该为您的项目适当地设置您的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 以自动执行此路径设置。当您的项目继续增长时,我建议在基础中有两个单独的目录 - 一个用于项目本身,一个用于测试。然后分别在每个中使用 relative imports。如果您选择package 或将其用作submodule 或类似的东西,这将使您的项目更加灵活。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-09
    • 2013-11-09
    • 2016-12-27
    • 2012-07-08
    • 2020-03-21
    • 1970-01-01
    • 2013-07-17
    • 2012-04-22
    相关资源
    最近更新 更多