类导入其他类错误
问题描述
我有三个脚本:
C:codevoiceTermmaster.py:
from voice_terminal_module.voice_terminal import VoiceTerminal
vterm = VoiceTerminal()
C:codevoiceTermvoice_terminal_modulevoice_terminal.py:
from chatbot_module.chatbot_module import Chatbot
class VoiceTerminal:
print("INITIALIZING VOICE TERMINAL")
cb = Chatbot()
C:codevoiceTermvoice_terminal_modulechatbot_modulechatbot_module.py:
class Chatbot:
print("CHATBOT INITIALIZED")
奇怪的是:当我运行chat bot_mode.py时,它会工作,如果我运行VOICE_Terminal.py,它会工作。但是,由于某些原因,master.py会出错,并显示以下消息:
Traceback (most recent call last):
File "c:codevoiceTermmaster.py", line 1, in <module>
from voice_terminal_module.voice_terminal import VoiceTerminal
File "c:codevoiceTermvoice_terminal_modulevoice_terminal.py", line 1, in <module>
from chatbot_module.chatbot_module import Chatbot
ModuleNotFoundError: No module named 'chatbot_module'
为什么它有时起作用,但有时不起作用?
解决方案
一般导入指南(供您自己编写)
我确定现在应该有一个副本,但我找不到,所以我正在写一篇完整的文章。
要正确解决问题,您必须注意两件事:
确保
sys.path
--Python搜索模块的路径--包括项目根目录的路径。确保代码中的
import
语句编写为使用该路径。
搜索路径
对于第一部分,您必须了解sys.path
是如何工作的。这是一个文件夹列表,将在启动时自动设置(即使您不是import sys
,就像sys.argv
一样)。
正常情况下,它将是一个包含以下内容的列表:
要执行的入口点的路径(该路径的详细信息将取决于如何启动Python;当直接从同一目录运行
.py
文件时,通常为''
,如果您这样做,则为另一个目录的路径,例如python somewhere/else/file.py
,使用-m
开关时为显式路径)系统库路径
虚拟环境库的路径(如果虚拟环境处于活动状态)
用户显式安装的内容的路径
您可以修改此列表,这将对以后的import
语句产生预期影响;但您通常不应。
为确保项目根目录位于路径上,通常只需安装项目--理想情况下应安装到虚拟环境中。详情请参考Python packaging guide。如果做不到这一点,请确保仅从包含顶级代码的文件夹外部启动项目。在OP的例子中,这意味着C:code
。这将确保C:code
(或等效项)处于sys.path
,然后我们可以依赖它进行第二步。
导入
我们基本上可以通过两种方式做到这一点:通过绝对导入指定根目录的路径,或者通过相对导入指定当前源文件的路径。阅读有关相对导入here和here的堆栈溢出的详细信息。
绝对导入
在任何一种情况下,我们都希望将项目的根文件夹(此处为<2-13]>)视为包。对于绝对导入,这意味着我们将始终在导入路径中提及根文件夹名称。
因此:
在C:codevoiceTermmaster.py
中:from voiceTerm.voice_terminal_module.voice_terminal import VoiceTerminal
在C:codevoiceTermvoice_terminal_modulevoice_terminal.py
中:from voiceTerm.voice_terminal_module.chatbot_module.chatbot_module import Chatbot
_module
。它并没有真正增加信息,使输入变得相当困难,而且实际上有点误导。)
我们还可以import
整个模块:import voiceTerm.master
,import voiceTerm.voice_terminal_module.voice_terminal
;import voiceTerm.voice_terminal_module.chatbot_module.chatbot_module
。此外,通过将文件命名为__init__.py
,我们可以将该文件夹作为包导入:import voiceTerm
;import voiceTerm.voice_terminal_module
;import voiceTerm.voice_terminal_module.chatbot_module
。我们还可以从以下包之一导入模块:from voiceTerm import master
;from voiceTerm.voice_terminal_module import voice_terminal
;from voiceTerm.voice_terminal_module.chatbot_module import chatbot_module
。相对进口量
对于相对导入,我们必须使用from
语法,并且我们只能从我们自己的包层次结构中导入内容。然而,我们的优势在于,我们不必指定完整路径,而且我们可以重命名包,而不必编辑代码。我个人的建议是在可能的情况下使用相对导入;这也与从系统库或其他第三方程序包导入有很强的视觉区别。
对于相对导入,首先使用相对导入路径指定要从中导入的包或子包。从单个.
开始,我们从当前目录开始,在同一文件夹中查找另一个模块或包。
因此:
inC:codevoiceTermmaster.py
:from .voice_terminal_module.voice_terminal import VoiceTerminal
导入类;from .voice_terminal_module import voice_terminal
导入模块。
inC:codevoiceTermvoice_terminal_modulevoice_terminal.py
:from .chatbot_module.chatbot_module import Chatbot
导入类;from .chatbot_module import chatbot_module
导入模块。
.
在包层次结构中向上导航(但我们不能以这种方式超出根目录)。例如,from ... import master
从下层chatbot_module.py
导入顶层master.py
。(当然,这在本例中实际上不起作用,因为它将是循环导入。)要从同一目录导入另一个源文件(作为模块),只需from . import other_file
。你明白了。
相关文章