ChatGPT解决这个技术问题 Extra ChatGPT

从父文件夹导入模块

我正在运行 Python 2.5。

这是我的文件夹树:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(我在每个文件夹中也有 __init__.py,为了便于阅读,此处省略)

如何从 life 模块中导入 nib 模块?我希望无需修改 sys.path 就可以做到。

注意:正在运行的主模块位于 ptdraft 文件夹中。

罗斯:我看过那里。我该怎么办?我已经有一个 __init__.py。 S.Lott:我不知道如何检查......
从 shell 回显 $PYTHONPATH;导入系统;从 Python 中打印 sys.path。 docs.python.org/tutorial/…
我强烈建议跳过所有 sys.pathPYTHONPATH 答案并查看 np8's excellent answer。是的,读起来很长。是的,看起来工作量很大。但这是唯一能正确、干净地真正解决问题的答案。
可执行伪代码发生了什么?为什么从 Python 中的父文件夹导入模块如此痛苦?这是荒谬的。
为什么会如此痛苦?在阅读了所有的讨论和答案后,仍然没有合理的简单解决方案。

D
Dennis

您可以使用相对导入(python >= 2.5):

from ... import nib

(What’s New in Python 2.5) PEP 328: Absolute and Relative Imports

编辑:添加了另一个点“。”上两包


ValueError: Attempted relative import in non-package
@endolith:你必须在一个包中,即你必须有一个 init.py 文件。
尝试相对导入超出顶级包
另请参阅以下答案,因为添加 __init__.py 不是您唯一需要做的事情:stackoverflow.com/questions/11536764/…
更准确地说,甚至,您需要一个 __init__.py 文件。
K
KetZoomer

相对导入(如 from .. import mymodule)仅在包中有效。要导入当前模块的父目录中的“mymodule”:

import os
import sys
import inspect

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) 

import mymodule

edit:并不总是给出 __file__ 属性。我现在建议使用检查模块来检索当前文件的文件名(和路径)而不是使用 os.path.abspath(__file__)


稍微短一点的东西:sys.path.insert(1, os.path.join(sys.path[0], '..'))
有什么理由避免使用 sys.path.append() 而不是插入?
@Tyler - 如果在 parentdir 之外的其他地方可能很重要,但在 sys.path 中指定的路径之一中,还有另一个名为“mymodule”的模块。插入 parentdir 作为 sys.path 列表的第一个元素可确保将导入来自 parentdir 的模块。
@JHolta 如果您不处理包裹,那么您的包裹是最好的解决方案。
@JHolta 好主意。 sys.path.insert(1, os.path.realpath(os.path.pardir)) 也可以。
n
np8

关于从同级包导入的问题,我也发布了类似的答案。你可以看到它here

没有 sys.path hacks 的解决方案

概括

将代码打包到一个文件夹中(例如 packaged_stuff)

在您使用 setuptools.setup() 的地方创建一个 setup.py 脚本。

使用 pip install -e 将包安装为可编辑状态

使用 from packaged_stuff.modulename import function_name 导入

设置

我假设与问题中的文件夹结构相同

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

我将 . 称为根文件夹,就我而言,它位于 C:\tmp\test_imports

脚步

在根文件夹中添加一个 setup.py -- setup.py 的内容可以很简单

    from setuptools import setup, find_packages

    setup(name='myproject', version='1.0', packages=find_packages())

基本上“任何”setup.py 都可以。这只是一个最小的工作示例。

使用虚拟环境

如果您熟悉虚拟环境,请激活一个,然后跳到下一步。虚拟环境的使用不是绝对必要的,但从长远来看,它们确实会帮助你(当你有超过 1 个正在进行的项目时......)。最基本的步骤是(在根文件夹中运行)

创建虚拟环境 python -m venv venv

python -m venv venv

激活虚拟环境。 venv/bin/activate (Linux) 或 ./venv/Scripts/activate (Win)

. venv/bin/activate (Linux) 或 ./venv/Scripts/activate (Win)

停用虚拟环境停用 (Linux)

停用 (Linux)

要了解更多信息,只需谷歌搜索“python virtualenv 教程”或类似内容。除了创建、激活和停用之外,您可能永远不需要任何其他命令。

一旦你创建并激活了一个虚拟环境,你的控制台应该在括号中给出虚拟环境的名称

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

pip 以可编辑状态安装您的项目

使用 pip 安装您的顶级软件包 myproject。诀窍是在安装时使用 -e 标志。这样它以可编辑状态安装,对 .py 文件所做的所有编辑都将自动包含在安装的包中。

在根目录下,运行

pip install -e .(注意点,它代表“当前目录”)

您还可以看到它是使用 pip freeze 安装的

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

通过在每次导入前添加主文件夹来导入

在此示例中,mainfolder 将是 ptdraft。这样做的好处是您不会遇到与其他模块名称(来自 python 标准库或 3rd 方模块)的名称冲突。

示例用法

笔尖

def function_from_nib():
    print('I am the return value from function_from_nib!')

生活.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

运行生活.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

另外,为什么这比使用 sys.path 方法更好或更优雅?
@HomeroBarrocasSEsmeraldo 好问题。 PYTHONPATH 环境变量保持不变。这将安装到 site-packages,它已经在 sys.path 上,并且代码通常由最终用户安装。这比 sys.path hack(并且您可以在该类别的路径 hack 中包括使用 PYTHONPATH)更好,因为这意味着开发中的代码对您的行为方式应该与对其他用户的行为方式相同。相反,当使用路径修改时,导入语句将以不同的方式解析。
这是迄今为止,我读过的最好的解决方案。这会创建一个指向您当前目录的链接,因此对代码的所有更新都会直接反映到您的工作目录中。如果您需要删除此条目,请手动删除 egg 文件并从 dist-packages 中的 easy-install 中删除该条目(如果您使用 pip,则为 site-packages)。
为什么让 python 导入头痛更加复杂?我们必须编写一个安装文件、一个虚拟环境、一个 pip 安装?我的天啊!
2020 年在 python 3.8 上导入模块的工作量是否仍然需要?我无法相信这是多么复杂。
M
MERose

似乎问题与位于父目录或类似目录中的模块无关。

您需要将包含 ptdraft 的目录添加到 PYTHONPATH

您说 import nib 与您合作,这可能意味着您将 ptdraft 本身(而不是其父级)添加到 PYTHONPATH。


如果您正在使用许多永远不会被重用的包,那么必须将所有内容添加到 pythonpath 不是一个好的解决方案。
@JasonCheng:那为什么要打包?
对我来说,这个答案已经解决了。但是,为了更明确,该过程是先 import sys,然后是 sys.path.append("..\<parent_folder>")
@JasonCheng,您不必导出修改后的 PYTHONPATH 或您的 shell 配置文件,您也可以选择仅将其设置为对 python 的一次调用(因此它仅在每次执行的基础上进行修改)或者您可以将其放入某种 .env 文件(基于每个文件夹)。
S
Shinbero

您可以在 sys.path 中列出的“模块搜索路径”中使用取决于操作系统的路径。因此,您可以轻松添加父目录,如下所示

import sys
sys.path.insert(0,'..')

如果要添加父父目录,

sys.path.insert(0,'../..')

这适用于 python 2 和 3。


这是相对于当前目录的,甚至不一定是包含主脚本的目录。
此方法在 PyCharm 中有效,但在 VS Code 中无效。
对我来说很棒!谢谢! ...但我需要兄弟目录,所以我的解决方案是 sys.path.insert(0,'../sibling_dir')
@DavisHerring 要修复它,请使用绝对路径。
@Jeyekomon:这只是用另一种方法替换了这种方法中几种脆弱性形式中的一种。
S
Serg Chernata

对python 2不太了解,在python 3中可以添加父文件夹如下:

import sys 
sys.path.append('..')

...然后可以从中导入模块


这仅在您当前的工作目录使得 '..' 指向包含相关模块的目录时才有效。
J
Joe Reynolds

如果将模块文件夹添加到 PYTHONPATH 不起作用,您可以在 Python 解释器搜索要导入的模块的程序中修改 sys.path 列表,python documentation 表示:

当导入名为 spam 的模块时,解释器首先搜索具有该名称的内置模块。如果没有找到,它会在变量 sys.path 给出的目录列表中搜索名为 spam.py 的文件。 sys.path 从以下位置初始化:包含输入脚本的目录(或当前目录)。 PYTHONPATH(目录名称列表,与 shell 变量 PATH 具有相同的语法)。安装相关的默认值。初始化后,Python 程序可以修改 sys.path。包含正在运行的脚本的目录位于搜索路径的开头,位于标准库路径之前。这意味着将加载该目录中的脚本,而不是库目录中的同名模块。除非打算更换,否则这是一个错误。

知道了这一点,您可以在程序中执行以下操作:

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft

您的答案很好,但可能并不总是有效并且不是很便携。如果程序被移动到新位置,则必须编辑 /path/to/ptdraft。有一些解决方案可以计算出文件的当前目录并以这种方式从父文件夹中导入它。
@Edward 这些技术是什么?
例如@Shuklaswag,答案是 stackoverflow.com/questions/714063/…
E
Edward

这是一个简单的答案,因此您可以了解它是如何工作的,小型且跨平台。
它只使用内置模块(ossysinspect),因此应该可以在
任何操作系统 (OS),因为 Python 就是为此而设计的。

更短的答案代码 - 更少的行和变量

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

如果行数少于此值,请将第二行替换为 import os.path as path, sys, inspect
getsourcefile(第 3 行)的开头添加 inspect. 并删除第一行。
- 但是这会导入所有模块所以可能需要更多的时间、内存和资源。

我的答案的代码(更长的版本)

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

它使用 Stack Overflow 答案中的示例How do I get the path of the current
executed file in Python?
来使用内置工具查找运行代码的源(文件名)。

from inspect import getsourcefile from os.path import abspath 接下来,无论您想从哪里找到源文件,只需使用: abspath(getsourcefile(lambda:0))

我的代码将文件路径添加到 sys.path,即 python 路径列表
,因为这允许 Python 从该文件夹导入模块。

在代码中导入模块后,如果添加的文件夹具有与稍后在程序中导入的另一个模块同名的模块
,最好在新行上运行 sys.path.pop(0)。您需要删除导入之前添加的列表项,而不是其他路径。
如果您的程序没有导入其他模块,则不删除文件路径是安全的,因为
在程序结束(或重新启动 Python shell),对 sys.path 所做的任何编辑都会消失。

关于文件名变量的注释

我的回答没有使用 __file__ 变量来获取运行
代码的文件路径/文件名,因为这里的用户经常将其描述为不可靠。您不应该在其他人使用的程序中使用它
从父文件夹导入模块

一些不起作用的例子(引自 this Stack Overflow 问题):

• 它can't be在某些平台上发现 • 它有时isn't the full file path

py2exe 没有 __file__ 属性,但是有一种解决方法当您使用 execute() 从 IDLE 运行时,没有 __file__ 属性 OS X 10.6 出现 NameError: global name '__file__' is not defined


我这样做并在导入所需模块后立即使用 sys.path.pop(0) 删除了新路径条目。然而,随后的进口仍然去了那个位置。例如,我有 app/configapp/toolsapp/submodule/config。从 submodule,我插入 app/ 以导入 tools,然后删除 app/ 并尝试导入 config,但我得到的是 app/config 而不是 app/submodule/config
我发现 tools 的其中一个导入也是从父目录导入 config。因此,当我后来尝试在 submodule 中执行 sys.path.pop(0); import config 并期望得到 app/submodule/config 时,我实际上得到了 app/config。显然,Python 返回同名模块的缓存版本,而不是实际检查 sys.path 中是否有匹配该名称的模块。 sys.path 在这种情况下被正确更改,Python 只是没有检查它,因为已经加载了同名模块。
我认为这是对我遇到的问题的确切引用:docs.python.org/3/reference/import.html#the-module-cache
5.3.1 中的一些有用信息。 documentation page 上的模块缓存:在导入期间,在 sys.modules 中查找模块名称 ... sys.modules 是可写的。删除键将使命名模块的缓存条目无效,导致 Python 在下一次导入时重新搜索。 ... 但请注意,如果您保留对模块对象的引用,使其缓存无效然后重新导入,这两个对象将是不同的。相比之下,importlib.reload() 将重用并重新初始化模块内容 ...
更短:os.path.realpath(getsourcefile(lambda:0) + "/../..")。将获取附加两个父目录符号的当前源文件。我没有使用 os.path.sep,因为 getsourcefile 即使在 Windows 上也使用 / 返回字符串。 realpath 将负责从提供父目录的完整路径(在本例中为文件名,然后是当前目录)中弹出两个目录条目。
i
itmatters

pathlib 库(包含在 >= Python 3.4 中)使得将父目录的路径附加到 PYTHONPATH 变得非常简洁和直观:

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))

是否可以使用 init.py 来规避这个问题?
谢谢埃里克,我刚刚删除了令人困惑的部分。
从 pathlib 导入 sys 导入路径 sys.path.append(str(Path('.').absolute().parent))
仅供参考,这在调试模式下运行 Visual Studio 代码时不起作用。全局导入/导出的能力在我对 python4 的愿望清单上
它适用于 VS 代码调试模式 + 适用于 jupyter notebok 而不是 Path(file)
M
Mike

这是更通用的解决方案,将父目录包含在 sys.path 中(对我有用):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

import os, sys\n sys.path.insert(0,os.path.pardir) 相同,但排序器 :)(评论中没有换行符)
@antiveeranna,如果您使用 os.path.pardir,您将不会获得父级的真实路径,只是您调用 sys.path.insert() 的相对路径
正如 StackOverflow 用户经常提到的那样,此答案使用可能 不可靠__file__ 变量(并不总是完整的文件路径,不适用于每个操作系统等)。将答案更改为不包括它将导致更少的问题并且更具交叉兼容性。有关详细信息,请参阅 stackoverflow.com/a/33532002/3787376
T
Thomas R

在 Jupyter Notebook 中(使用 Jupyter LAB 或 Jupyter Notebook 打开)

只要您在 Jupyter Notebook 中工作,这个简短的解决方案可能会很有用:

%cd ..
import nib

即使没有 __init__.py 文件,它也可以工作。

我在 Linux 和 Windows 7 上使用 Anaconda3 对其进行了测试。


在导入后添加 %cd - 是否有意义,因此笔记本的当前目录保持不变。
它有很大帮助,特别是当您需要导入同时使用相对路径导入其他模块的模块时。
Y
Yu N.

我发现以下方法适用于从脚本的父目录导入包。在示例中,我想从 app.db 包中导入 env.py 中的函数。

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)

所以,一个不错的单行:sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
完全修改 sys.path 通常是个坏主意。您需要某种方式(egPYTHONPATH)让other 代码可以访问您的库(否则它不是真正的库);一直使用它!
R
Ravin Gupta

上面提到的解决方案也很好。这个问题的另一个解决方案是

如果您想从顶级目录导入任何内容。然后,

from ...module_name import *

此外,如果您想从父目录导入任何模块。然后,

from ..module_name import *

此外,如果您想从父目录导入任何模块。然后,

from ...module_name.another_module import *

这样,您可以根据需要导入任何特定方法。


这似乎应该是这样,但由于某种原因,这与上面的 sys.path.append hacks 不同,我无法像这样导入我的库。这是我在开始 google 之前第一次尝试做的事情 :) 好的,就是这个 ValueError: attempted relative import beyond top-level package
我做了一些测试,似乎 from ... import name 并不意味着“从顶级导入名称”,而是“从父级的父级导入名称”。我创建了一个包含九个目录的嵌套目录结构 a1/.../a9,其中每个目录都包含一个 __init__.py,并使用 from . import next_dir 导入下一个目录。最后一个目录有一个带有 from ....... import b 的文件,然后导入了 a1/a2/a3/b。 (使用 Python 3.8.2 测试)
将此解决方案用于我们的库测试。接受的答案确实是一种正确的做事方式,但如果我理解正确,这将需要公开我们不想要的模块
@juzzlin 这是一个单独的问题。请参阅stackoverflow.com/questions/30669474/…
A
Andong Zhan

import sys sys.path.append('../')


当从不同的目录执行时,这将不起作用。
z
zviad

对我来说,访问父目录的最短且我最喜欢的 oneliner 是:

sys.path.append(os.path.dirname(os.getcwd()))

或者:

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd() 返回当前工作目录的名称,os.path.dirname(directory_name) 返回传递的目录名称。

实际上,在我看来,Python 项目架构应该按照子目录中的任何模块都不会使用父目录中的任何模块的方式来完成。如果发生这样的事情,值得重新考虑项目树。

另一种方法是将父目录添加到 PYTHONPATH 系统环境变量。


+1 提到必须重组项目的可能性(而不是解决问题)
这没有得到父母,它得到了当前
这是一个坏主意,因为它取决于当前目录而不是文件的位置,因此它会根据您运行脚本的位置执行不同的操作。
t
tjk

虽然原作者可能不再寻找解决方案,但为了完整性,有一个简单的解决方案。将 life.py 作为一个模块运行,如下所示:

cd ptdraft
python -m simulations.life.life

这样,您可以从 nib.py 导入任何内容,因为 ptdraft 目录位于路径中。


对于那些不想弄乱 sys.pathPYTHONPATH 等环境变量的人来说,这是一个很好的方法,有关 -m 的更多详细信息,您可以查看 this stackoverflow thread
如果您使用的是 vscode,您可以使用 stackoverflow.com/questions/57455652/… 中的配置自动执行此操作。
V
Vinoj John Hosan

两行最简单的解决方案

import os, sys
sys.path.insert(0, os.getcwd()) 

如果 parent 是您的工作目录,并且您想从子脚本中调用另一个子模块。

您可以在任何脚本中从父目录导入所有子模块并将其执行为

python child_module1/child_script.py

这是唯一对我有用并且最适合我的用例的方法:从测试文件夹中导入主要方法
G
Gin

https://i.stack.imgur.com/2S8pY.png


好的,您可以点击此链接下载「import_case」查看源代码case_repo
j
jheyse

与过去的答案相同的风格 - 但行数更少:P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

文件返回您正在工作的位置


对我来说,文件是不包含路径的文件名。我使用“ipy filename.py”运行它。
嗨@CurtisYallop 在上面的示例中,我们正在添加包含 python 文件所在的文件 [我们当前所在的] 的目录。带有文件名的 os.path.dirname 调用应该返回文件的路径,我们正在将其添加到路径而不是显式文件中-HTH :-)
您假设 __file__ 始终包含路径和文件。有时它只包含文件名而不包含路径。
@CurtisYallop - 完全不是先生,我假设文件是文件名,我正在使用 os.path.dirname() 来获取文件的路径。你有这个不起作用的例子吗?我喜欢重现的步骤
@CurtisYallop - 不,我不是!我是说: print /_/file/_/ 会给你上面“file.py”示例中的文件名 - 然后我说你可以使用 os.path.dirname() 从中提取完整路径.如果您从某个奇怪的位置调用并且您想要这种关系,那么您可以通过 os 模块轻松找到您的工作目录 - 天哪!
E
Erel Segal-Halevi

在 Linux 系统中,您可以创建从“life”文件夹到 nib.py 文件的软链接。然后,您可以像这样简单地导入它:

import nib

这个答案值得更多关注。符号链接方法比该线程上的大多数答案要干净几个数量级。然而,这是我第一次看到有人建议它。
我不同意。这是一个不可移植的解决方案,它还将文件系统层与 python 源代码混合在一起。
T
Thomas R

我有一个专门针对 git-repositories 的解决方案。

首先,我使用了 sys.path.append('..') 和类似的解决方案。如果您正在导入本身使用 sys.path.append('..') 导入文件的文件,这会导致特别问题。

然后我决定总是附加 git 存储库的根目录。在一行中,它看起来像这样:

sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)

或者像这样的更多细节:

import os
import sys
import git
def get_main_git_root(path):
    main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
    return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)

对于原始问题:根据存储库的根目录,导入将是

import ptdraft.nib

或者

import nib

顺便说一句:这是安装 git 库的方法: pip install GitPython
S
Sida Zhou

我们的文件夹结构:

/myproject
  project_using_ptdraft/
    main.py
  ptdraft/
    __init__.py
    nib.py
    simulations/
      __init__.py
      life/
        __init__.py
        life.py

我理解这一点的方式是有一个以包为中心的视图。包根是 ptdraft,因为它是包含 __init__.py 的最顶层

包中的所有文件都可以使用绝对路径(相对于包根目录)进行导入,例如在 life.py 中,我们只需:

import ptdraft.nib

但是,要为包开发/测试目的运行 life.py,而不是 python life.py,我们需要使用:

cd /myproject
python -m ptdraft.simulations.life.life

请注意,此时我们根本不需要摆弄任何路径。

更令人困惑的是,当我们完成 ptdraft 包时,我们想在驱动程序脚本中使用它,该脚本必须位于 ptdraft 包文件夹(又名 project_using_ptdraft/main.py)之外,我们需要修改路径:

import sys
sys.path.append("/myproject")  # folder that contains ptdraft
import ptdraft
import ptdraft.simulations

并使用 python main.py 运行脚本没有问题。

有用的网址:

https://tenthousandmeters.com/blog/python-behind-the-scenes-11-how-the-python-import-system-works/(查看如何使用 __init__.py)

https://chrisyeh96.github.io/2017/08/08/definitive-guide-python-imports.html#running-package-initialization-code

https://stackoverflow.com/a/50392363/2202107

https://stackoverflow.com/a/27876800/2202107


u
user3181121

与图书馆合作。创建一个名为 nib 的库,使用 setup.py 安装它,让它驻留在站点包中,您的问题就解决了。你不必把你做的所有东西都塞进一个包里。把它分解成碎片。


您的想法很好,但有些人可能希望将他们的模块与他们的代码捆绑在一起——也许是为了使其可移植,并且不需要每次在不同的计算机上运行他们的模块时都将其放入 site-packages
C
Casper Hansen

我遇到了一个问题,我必须导入一个 Flask 应用程序,该应用程序的导入还需要在单独的文件夹中导入文件。这部分使用了 Remi's answer,但假设我们有一个如下所示的存储库:

.
└── service
    └── misc
        └── categories.csv
    └── test
        └── app_test.py
    app.py
    pipeline.py

然后在从 app.py 文件导入应用程序对象之前,我们将目录更改为上一级,因此当我们导入应用程序(导入 pipeline.py)时,我们还可以读取其他文件,如 csv 文件。

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)

os.chdir('../')
from app import app

导入 Flask 应用程序后,您可以使用 os.chdir('./test'),这样您的工作目录就不会更改。


M
Miroslav Hinkov

在我看来,您实际上并不需要导入父模块。假设在 nib.py 中有 func1() 和 data1,需要在 life.py 中使用

笔尖

import simulations.life.life as life
def func1():
   pass
data1 = {}
life.share(func1, data1)

生活.py

func1 = data1 = None

def share(*args):
   global func1, data1
   func1, data1 = args

现在您可以访问 life.py 中的 func1 和数据了。当然,在尝试使用它们之前,你必须小心在 life.py 中填充它们,


f
fx-kirin

我制作了这个库来做到这一点。

https://github.com/fx-kirin/add_parent_path

# Just add parent path
add_parent_path(1)

# Append to syspath and delete when the exist of with statement.
with add_parent_path(1):
   # Import modules in the parent path
   pass

m
mj_whales

这是对我有用的最简单的解决方案:

from ptdraft import nib

J
JLT

虽然违反了所有规则,但我还是要提一下这种可能性:

您可以先将文件从父目录复制到子目录。接下来导入它并随后删除复制的文件:

例如在 life.py 中:

import os
import shutil

shutil.copy('../nib.py', '.')
import nib
os.remove('nib.py')

# now you can use it just fine:
nib.foo()

当然,当 nibs 尝试使用相对导入/路径导入/读取其他文件时,可能会出现一些问题。


这是一个创造性的解决方案!我可能不会使用它。
我强烈建议不要使用此解决方案,而是将父目录也设为一个包,或者只是将父目录附加到您的 sys.path(如其他答案中所建议的那样)。复制/删除文件会引入对文件位置的非常紧密的依赖,这在将来更改项目时可能会被忽视(从而使脚本的健壮性降低)。它还可以防止文件被缓存,当然也会为所需的 IO 产生轻微的开销。
我知道人们确实对这篇文章投了反对票,因为这确实是一种不好的做法,而且我在编写包或可重用脚本时永远不会使用它,但在某些情况下它可能仍然值得。例如,当您运行交互式会话并且只想使用在另一个位置的脚本中定义的某些功能时。我认为在 stackoverflow 上仍然提到这些解决方案是一种很好的做法。
我理解你的评论,@JLT 并同意将其包含在 StackOverflow 上以供参考可能是值得的。那么,为什么不更新您的答案以反映您的推理,并提及一些随之而来的注意事项/陷阱呢?
R
Ricardo D. Quiroga

这对我来说可以从更高的文件夹中导入东西。

import os
os.chdir('..')