【问题标题】:Importing modules from parent folder从父文件夹导入模块
【发布时间】:2019-09-16 22:26:12
【问题描述】:

我正在运行 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 中的父文件夹导入模块如此痛苦?这太荒谬了。
  • 为什么这么痛苦?看完了所有的讨论和答案,仍然没有合理的简单解决方案。

标签: python module path directory python-import


【解决方案1】:

您可以使用相对导入 (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 文件。
【解决方案2】:

相对导入(如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

编辑__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)) 也可以。
【解决方案3】:

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

没有sys.path hacks的解决方案

总结

  • 将代码打包到一个文件夹中(例如packaged_stuff
  • 在您使用setuptools.setup() 的地方创建一个setup.py 脚本。
  • 使用pip install -e <myproject_folder>将包安装为可编辑状态
  • 使用from packaged_stuff.modulename import function_name 导入

设置

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

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

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

步骤

  1. 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
  • 激活虚拟环境
    • . venv/bin/activate (Linux) 或 ./venv/Scripts/activate (Win)
  • 停用虚拟环境
    • deactivate (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>
  1. 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
  1. 通过在每次导入前添加 mainfolder 来导入

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


示例用法

nib.py

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

life.py

​​>
from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

运行 life.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 hacks 更好(并且您可以在该类别的路径 hacks 中使用 PYTHONPATH),因为这意味着开发中的代码对您的行为应该与对其他用户的行为相同。相反,当使用路径修改时,导入语句将以不同的方式解析。
  • 这是迄今为止,我读过的最好的解决方案。这会创建一个指向您当前目录的链接,因此对代码的所有更新都会直接反映到您的工作目录中。如果您需要删除此条目,请手动删除 egg 文件并从 dist-packages 中的 easy-install 中删除该条目(如果您使用 pip,则为 site-packages)。
  • 为什么让 python 导入头痛变得更加复杂?我们必须编写一个安装文件、一个虚拟环境、一个 pip 安装?天哪!
  • 2020 年在 python 3.8 上导入模块的工作量是否仍然需要?我不敢相信这是多么复杂。
【解决方案4】:

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

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

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

【讨论】:

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

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

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

如果要添加父父目录,

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

这适用于 python 2 和 3。

【讨论】:

  • 这是相对于当前目录的,甚至不一定是包含主脚本的目录。
  • 此方法在 PyCharm 中有效,但在 VS Code 中无效。
【解决方案6】:

对python 2了解不多。
在python 3中,可以按如下方式添加父文件夹:

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

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

【讨论】:

  • 只有当你当前的工作目录是'..'指向有问题模块的目录时才有效。
【解决方案7】:

如果将模块文件夹添加到 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/…
【解决方案8】:

这是一个简单的答案,因此您可以了解它的工作原理,小型且跨平台。
它只使用内置模块(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.pathpython 路径列表
因为这允许 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 将负责从给出父目录的完整路径(在本例中为文件名,然后是当前目录)中弹出两个目录条目。
【解决方案9】:

这是更通用的解决方案,将父目录包含在 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) 相同,但排序器 :)(cmets 中没有换行符)
  • @antiveeranna,如果你使用os.path.pardir,你将不会得到父级的真实路径,只是你调用sys.path.insert()的相对路径
  • 这个答案使用 __file__ 变量,它可能是不可靠(并不总是完整的文件路径,不适用于每个操作系统等)作为 StackOverflow用户经常提到。将答案更改为不包含它将导致更少的问题并且更具交叉兼容性。有关详细信息,请参阅stackoverflow.com/a/33532002/3787376
【解决方案10】:

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

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

【讨论】:

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

我发现以下方法适用于从脚本的父目录导入包。在示例中,我想从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 通常是个坏主意。您需要某种方式(例如PYTHONPATH)让其他代码可以访问您的库(否则它不是真正的库);一直使用它!
【解决方案12】:

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

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

%cd ..
import nib

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

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

【讨论】:

  • 在导入后加上%cd -不是很有意义,所以笔记本的当前目录保持不变。
  • 它有很大帮助,尤其是当您需要导入同时使用相对路径导入其他模块的模块时。
【解决方案13】:

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

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

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 测试)
【解决方案14】:

对我来说,访问父目录的最短且我最喜欢的 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 提到了必须重组项目的可能性(而不是对问题进行破解)
  • 这没有得到父,它得到当前
【解决方案15】:

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

【讨论】:

  • 这在从不同目录执行时将不起作用。
【解决方案16】:

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

cd ptdraft
python -m simulations.life.life

这样你可以从 nib.py 导入任何东西,因为 ptdraft 目录在路径中。

【讨论】:

  • 对于那些不想搞砸sys.pathPYTHONPATH 等环境变量的人来说,这是一个很好的方法,有关-m 的更多详细信息,您可以查看this stackoverflow thread
【解决方案17】:

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

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

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

【讨论】:

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

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

import nib

【讨论】:

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

我认为您可以在该特定示例中尝试此操作,但在 python 3.6.3 中

【讨论】:

  • ok,可以点击此链接下载「import_case」查看源码case_repo
【解决方案20】:

我们的文件夹结构:

/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 运行脚本没有问题。

有用的链接:

【讨论】:

    【解决方案21】:

    两行最简单的解决方案

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

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

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

    python child_module1/child_script.py
    

    【讨论】:

      【解决方案22】:

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

      【讨论】:

      • 您的想法不错,但有些人可能希望将他们的模块与他们的代码捆绑在一起——也许是为了使其可移植,并且不需要每次在不同的计算机上运行他们的模块时都将其放入 site-packages .
      【解决方案23】:

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

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

      然后在从app.py文件中导入app对象之前,我们将目录上移一级,所以当我们导入app(导入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'),这样您的工作目录就不会改变。

      【讨论】:

        【解决方案24】:

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

        nib.py

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

        life.py

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

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

        【讨论】:

          【解决方案25】:

          我创建了这个库来做到这一点。

          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
          

          【讨论】:

            【解决方案26】:

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

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

            例如在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 上以供参考可能是值得的。那么为什么不更新您的答案以反映您的推理,并提及一些随之而来的注意事项/陷阱?
            【解决方案27】:

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

            import os
            os.chdir('..')
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-12-13
              • 2017-06-07
              相关资源
              最近更新 更多