繁体   English   中英

为什么从同一个 *sub* 目录导入时会发生错误?

[英]Why does error occurs when importing from same *sub*directory?

考虑这个文件夹结构:

main.py
module_a/
    aa.py
    bb.py
    __init__.py

main.py中,我将 aa 导入为:

from module_a import aa
aa.yyy()

然后在aa.py中,我导入 bb 并将其函数包含为:

import bb
bb.xxx()

但是,当我运行main.py时,python 显示“没有名为‘bb’的模块”。

我可以知道为什么会这样吗? 导入 bb 的正确方法是什么?

谢谢!!!

我尝试将aa.py写为:

import .bb
bb.xxx()

但它仍然不起作用。

为什么会这样

因为aa文件夹不是Python搜索模块的地方。

Python 的import s 默认是绝对的。 它们只查看由sys.path确定的特定位置。 main.py中, import module_a.aa起作用是因为项目的根文件夹恰好在sys.path上; 该文件夹包含一个module_a文件夹; 该文件夹包含aa.py

导入 bb 的正确方法是什么?

请在您的 package 中的文件之间使用相对导入。在这种情况下, aa.py中的必要导入如下所示:

from . import bb

绝对导入容易出错; 使用两个内容具有重叠名称的包的项目将遇到名称空间冲突。 (遗憾的是,标准库在大多数地方都使用绝对导入,这样项目需要为了安全而禁止某些模块名称。)如果您稍后重命名子包,相对导入也需要更少的维护。

相对导入唯一需要的是加载 package,这通常会在首次(是的,绝对)导入任何 package 内容时自动发生。 当加载 package 时,它会自动在该 package 中的模块上设置一个__package__属性,Python 可以使用它来解析相关导入。 重要的是要注意,相对导入是相对于package 层次结构,而不是目录结构,这就是为什么这是必要的; from.. import example这样的导入无法通过找出当前文件位置然后在目录层次结构中上升一个级别来工作。 相反,他们检查__package__以确定包含的 package 是什么,然后检查它的文件/文件夹位置并从那里开始工作。

如果“驱动程序”脚本在 package 内,则将其作为模块运行,使用 Python 的-m开关。例如,从根文件夹,如果module_a/aa.py是驱动程序,请使用python -m module_a.aa . 这指示 Python module_a是包含 package 的aa.py ,并确保它被加载,即使代码中没有import加载它。

与许多人会错误地告诉您的相反,几乎不需要操纵sys.path GitHub 上有流行的 Python 项目,运行了数十万行代码,要么根本不使用它,要么只作为辅助角色使用一次(可能是因为对文档工具的特殊要求)。 只是不要这样做。

与许多人错误地告诉你的相反, __init__.py文件不需要在 Python 中创建包。它们只是一个可以放置额外代码以进行 package 初始化的地方 - 例如,为子包内容创建别名,或者限制将使用* -import 导入的内容(通过设置__all__ )。

import.bb

这只是无效的。 相对导入使用from语法。 请参阅上面的正确语法。

假设文件结构与 OP 中所述相同,并且:

main.py

import module_a.aa

module_a.aa.thisFile()
module_a.aa.module_a.bb.thisFile()

aa.py :

import module_a.bb

def thisFile():
    print("aa")

bb.py :

def thisFile():
    print("bb")

然后,这将打印

aa
bb

就像你期望的那样。 这里的主要区别是bb.py是通过module_a.bb导入aa.py的。 运行main.py没有问题,但是,运行aa.py不能以这种方式工作。 这就是为什么您可能想要将文件夹添加到您的路径,这样您就可以从不同的文件调用 function 而不会遇到这个问题。 这是通过以下方式完成的:

import os, inspect, sys 

current_folder = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_folder = os.path.dirname(current_folder)
sys.path.insert(0,parent_folder)

然后你可以导入你的文件,比如import file 如果您考虑这个选项,我建议您阅读一下它的工作原理。 提示:确保避免循环导入问题。

暂无
暂无

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

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