简体   繁体   English

Python 3:从父目录中的 python 文件导入函数

[英]Python 3: importing a function from a python file in a parent directory

I'm new to unit testing and I'm trying to create my first unit test file in python 3. So I have the following really rudimentary folder structure just from imitating an online course.我是单元测试的新手,我正在尝试在 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 is the file I'm using for unit testing, and I want to import the avg() function from first_project.py which exists in a parent directory above the it. test_first_project.py 是我用于单元测试的文件,我想从 first_project.py 导入 avg() 函数,它存在于它上面的父目录中。

I'm on windows 10, I have git bash open to the following path: '/d/Projects/Projects/unit_testing_course' (ie the parent directory containing first_project.py, the module/function I'm trying to import to the test_first_project.py file within the tests child directory).我在 Windows 10 上,我将 git bash 打开到以下路径:'/d/Projects/Projects/unit_testing_course'(即包含 first_project.py 的父目录,我试图导入到 test_first_project 的模块/函数.py 文件在测试子目录中)。 I keep running python tests/test_first_project.py我一直在运行python tests/test_first_project.py

I quickly found out I couldn't use something like 'from .. import first_project' or 'from .. import avg', which cause the 'ValueError: attempted relative import beyond top-level package' error message.我很快发现我不能使用诸如“from .. import first_project”或“from .. import avg”之类的东西,这会导致“ValueError:试图在顶级包之外进行相对导入”错误消息。

So from reading documentation I'm getting that both 'from' and 'import' are instructions that are meant to work with modules or packages.因此,通过阅读文档,我了解到“from”和“import”都是用于处理模块或包的指令。 https://docs.python.org/3/tutorial/modules.html https://docs.python.org/3/tutorial/modules.html

"Python has a way to put definitions in a file and use them in a script or in an interactive instance of the interpreter. Such a file is called a module; definitions from a module can be imported into other modules or into the main module (the collection of variables that you have access to in a script executed at the top level and in calculator mode). “Python 有一种方法可以将定义放在文件中,并在脚本或解释器的交互式实例中使用它们。这样的文件称为模块;来自模块的定义可以导入到其他模块或主模块中(您可以在顶层和计算器模式下执行的脚本中访问的变量集合)。

A module is a file containing Python definitions and statements.模块是包含 Python 定义和语句的文件。 The file name is the module name with the suffix .py appended.文件名是后缀 .py 的模块名称。 Within a module, the module's name (as a string) is available as the value of the global variable __name__."在模块内,模块的名称(作为字符串)可用作全局变量 __name__ 的值。”

So it sounds like as far as python 3 is concerned, every .py file is a module and module name is essentially the .py file name without the .py extension at the end.所以听起来就 python 3 而言,每个 .py 文件都是一个模块,模块名称本质上是 .py 文件名,末尾没有 .py 扩展名。 And it sounds like I'm trying to import a module from the parent directory of the test_first_project.py file.听起来我正在尝试从 test_first_project.py 文件的父目录中导入一个模块。

that documentation link seems to be helpful for explaining the scenario where you have a module within the current directory you're executing a program/python shell from and you're just trying to import a function from that module into that program.该文档链接似乎有助于解释在当前目录中有一个模块的场景,您正在从中执行程序/python shell,而您只是试图将该模块中的函数导入该程序。

But in this case it seems like we need to actually tell python to look for a module named 'first_project' within a specific directory, the parent directory of the test_first_project.py file.但在这种情况下,我们似乎需要实际告诉 python 在特定目录中查找名为“first_project”的模块,即 test_first_project.py 文件的父目录。 I looked at the section on module search paths, https://docs.python.org/3/tutorial/modules.html#the-module-search-path我查看了关于模块搜索路径的部分, https://docs.python.org/3/tutorial/modules.html#the-module-search-path

When a module named spam is imported, the interpreter first searches for a built-in module with that name.当导入名为 spam 的模块时,解释器首先搜索具有该名称的内置模块。 If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path.如果未找到,它将在变量 sys.path 给出的目录列表中搜索名为 spam.py 的文件。 After initialization, Python programs can modify sys.path.初始化后,Python 程序可以修改 sys.path。 The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path.包含正在运行的脚本的目录位于搜索路径的开头,在标准库路径之前。

Then I tried...然后我试了...

import sys
import os
p_dir_path = os.path.abspath('../')
sys.path.append(p_dir_path)
from  first_project import avg

Which still gets me the same error message of 'ValueError: attempted relative import beyond top-level package'.这仍然让我得到相同的错误消息“ValueError:试图在顶级包之外进行相对导入”。 I was hoping that modifying sys.path programatically could change things...我希望以编程方式修改 sys.path 可以改变事情......

So what do I actually need to do in order to import a module from a parent directory?那么我实际上需要做什么才能从父目录导入模块? Or... is it not possible to do that in python?或者......在python中不可能做到这一点? Do I need to be using a package instead of a module (ie do I need to create an init .py in my parent directory)?我是否需要使用包而不是模块(即我是否需要在我的父目录中创建一个init .py)?

I've seen other questions and posts on stackoverflow about trying to import a file in a different directory and other cases, but imitating the syntax on those questions hasn't helped me and I think I've spent way too much time on this.我在 stackoverflow 上看到了关于尝试在不同目录和其他情况下导入文件的其他问题和帖子,但是模仿这些问题的语法并没有帮助我,我想我在这上面花了太多时间。 I'm also sure I'm not the only person who has wanted to create unit tests and got sidetracked by issues with import statements, modules, and packages.我也确信我不是唯一一个想要创建单元测试并被导入语句、模块和包问题所困扰的人。

You should set your PYTHONPATH variable appropriately for your project.您应该为您的项目适当地设置PYTHONPATH变量。 In unit_testing_course , rununit_testing_course ,运行

export PYTHONPATH=$(pwd)

in your shell.在你的壳里。 And consider the following code:并考虑以下代码:

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 *

running python -m unittest tests will work as desired (provided python points to your desired python version).运行python -m unittest tests将按需要运行(前提是python指向您想要的 python 版本)。 You can also use a virtualenv and modify its venv/bin/activate to perform this path setting automatically.您还可以使用virtualenv并修改其venv/bin/activate以自动执行此路径设置。 When your project continues to grow, I recommend having two separate directories in the base - one for the project itself and one for the tests.当您的项目继续增长时,我建议在基本目录中有两个单独的目录 - 一个用于项目本身,另一个用于测试。 Then use relative imports in each respectively.然后分别在每个中使用相对导入 This will alow your project to be flexible should you choose to package it or use it as a submodule or something like this.如果您选择打包或将其用作子模块或类似的东西,这将使您的项目变得灵活。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM