导入位于当前文件夹同级中的库

Posted

技术标签:

【中文标题】导入位于当前文件夹同级中的库【英文标题】:Import a library which is in a sibling of the current folder 【发布时间】:2019-07-04 10:38:50 【问题描述】:

文件夹结构

lib/
    abcd/
        __init.py__
        lib.py
app.py

代码

from lib.abcd import lib

有效。但是有了这个文件结构:

bin/
    app.py
lib/
    abcd/
        __init.py__
        lib.py

代码

from ..lib.abcd import lib     

出现导入错误。

当库位于当前文件夹的同级文件夹中时如何正确执行import(或同级文件夹的子文件夹)

我知道可能会有一些涉及将 lib/ 添加到 PATH 的技巧,但是有没有优雅的 Pythonic 解决方案?

如果没有,是否有真正的内部原因阻止用户以简单的方式进行这种简单的导入?

【问题讨论】:

通常你不能。因为您的***目录是bin。要实现它,您需要将父目录添加到sys.path。然后将其导入为from lib.abcd import lib 感谢您的评论@Sraw。没有更简单的解决方案吗? 肯定有...将lib 移至bin。我了解您的项目结构。如果你想坚持,我建议你添加一个 bash 脚本来启动。在该脚本中,您可以使用 PYTHONPATH=your_parent_directory python app.py 启动您的应用程序。 只是为了澄清,基于代码和这些 cmets:这里没有父文件夹吗?这是您项目的完整文件夹结构吗? 恕我直言,您做错了。您应该区分源代码的布局和已安装软件的布局。当您安装软件时,lib 将安装在 python 解释器的站点包中,您可以将app.py 放在标准的bin 目录中,它将始终独立于它所在的位置工作。在开发过程中,您只需将根目录标记为源根目录即可完成,或者您使用 virtualenv 在其中执行 pip install -e 【参考方案1】:

执行此操作的方法


方法#1:使用 sys 模块:您可以使用sys 模块轻松完成您想要做的事情。要导入lib 包,您可以使用下面列出的两个代码之一:

import sys
sys.path.append('<PATH_TO_LIB_FOLDER>')

from lib.abcd import lib

import sys
sys.path.insert(0, '<PATH_TO_LIB_FOLDER>')

方法二:使用 os 模块: 另一种方法是使用os 模块。下面是通过调用os.path.join 方法使用os 模块导入lib 模块的示例代码:

import os

path = os.path.join("<PATH>/lib/abcd", "lib")
from lib.abcd import lib

方法 #3:将模块添加到您的 PYTHONPATH: 这在大多数情况下不是最好的方法,但如果您不想继续使用 sysos 模块导入lib,这是理想的。你所要做的就是在你的 bash 终端中输入这个:

export PYTHONPATH=<PATH_TO_LIB> python lib.py

然后在你的 python shell 中你可以像这样导入它:

from lib.abcd import lib

方法#4:结合sys和os模块(推荐):这是最有效的方法,可以为你节省很多时间。这段代码结合了ossys 模块,如下所示:

import sys, os
sys.path.append(os.path.abspath(os.path.join('..', 'lib')))

然后你可以像这样轻松地导入你的模块:

from lib.abcd import lib

所有代码的工作原理:

上面所有的代码都很简单。除了“方法#3”之外的所有例子,暂时将你的模块添加到PYTHONPATH“方法#3”另一方面,将模块永久添加到您的PYTHONPATH

【讨论】:

你添加了什么新信息?这些都是路径操作,我已经提到过,并不是 OP 所要求的。 方法 #2 不会向您的 PYTHONPATH 添加任何内容。所做的就是创建字符串path,例如在 *nix 上,"&lt;PATH&gt;/lib/abcd/lib"。对于方法#3,您可能不应该覆盖PYTHONPATH,而应该在它前面添加。 方法2与问题完全无关(至少os部分)。 @CristiFati -- 方法 2 只是让它发挥作用的一种方法 也许,但os.path.join 在那里完全没用,因此 os 然后是方法本身..【参考方案2】:

表面水平的外观

通常情况下,你不能。导入文件时,Python 只搜索当前目录、入口点脚本运行所在的目录以及包含包安装目录等位置的sys.path(实际上比这复杂一点,但这涵盖了大多数情况下)。

您在导入已安装模块时看不到此问题的原因是因为它们安装在您的路径中已经存在的位置,或者该位置已被安装实用程序添加到路径中(例如pip) .

您可以在运行时添加到 Python 路径:

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

    import file  

您也可以使用sys.path.append('../lib'),但它会在您的路径中被搜索到最后,并且可能会被之前的路径条目覆盖。

我已经广泛阅读了import documentation,据我所知,您的问题的答案是否定的,没有办法以纯粹的“Pythonic”方式做到这一点。

更深入的了解:

深入了解import documentation 解释了这一点:

import 语句结合了两个操作;它搜索命名模块,然后将搜索结果绑定到本地范围内的名称。导入语句的搜索操作被定义为对 __import__() 函数的调用,并带有适当的参数。 __import__()的返回值用于执行import语句的名称绑定操作。

仔细看__import__:

__import__(name, globals=None, locals=None, fromlist=(), level=0)

注意:与importlib.import_module() 不同,这是日常 Python 编程中不需要的高级功能。

此函数由 import 语句调用。它可以被替换(通过导入 builtins 模块并分配给 builtins.__import__ )以更改 import 语句的语义,但强烈建议不要这样做,因为使用导入钩子(参见 PEP 302)通常更容易获得相同的目标,并且不会导致假设默认导入实现正在使用的代码出现问题。也不鼓励直接使用 __import__() 以支持 importlib.import_module()。

level 指定是使用绝对导入还是相对导入。 0(默认值)表示只执行绝对导入。 level 的正值表示要搜索的父目录相对于调用 __import__() 的模块的目录的数量(有关详细信息,请参阅 PEP 328)。

这让我觉得您可以通过某种方式指定level,这可能会使导入自动在父路径上查找。我猜当import 从不在它自己的目录中的app.py 中调用时,level 被设置为0 并且它搜索相同级别和更深。

当您从子文件夹中调用app.py 中的import 时,level 仍设置为0,因此无法找到它上面的其他目录。我正在研究一种在运行脚本时将此级别设置为1 的“Pythonic”方式,这似乎可以解决此问题。

【讨论】:

以上是关于导入位于当前文件夹同级中的库的主要内容,如果未能解决你的问题,请参考以下文章

vs2010 相对路径中附加包含目录 不好用,请帮忙看看

树莓派 Arduino 库文件夹

Python基础-----模块导入注意事项

无法从同级目录导入图像 - React Native

模拟CMD操作文件(夹)

垂直对齐位于浮动同级旁边的 Div 中的多行文本