Python相互导入的问题解决
作者:__程序喵__ 发布时间:2022-12-04 16:59:56
前言
Hi! 这是随笔专栏的第一篇文章。好的开始等于成功了一半。在之后的日子里,除了不定期分享实战中可总结出的小项目外,还会经常与大分享开发时遇到的问题。今天,是一个曾困扰了我许久的关于 Python 两个文件间互相 import 的问题。
问题→解决
问题描述
两个文件间相互导入时产生了一系列错误,比如 ImportError, NameError 等等。这次,我用简单的代码示例复现一下这些问题,并一步一步解决。
问题复现
这里,我创建两个同目录下的 Python 文件:mutualImportA 和 mutualImportB 并输入代码。
# mutualImportA.py
from mutualImportB import b
a = 1
def pA():
print(b)
pA()
# mutualImportB.py
from mutualImportA import a
b = 1
def pB():
print(a)
pB()
创建完毕后,任意运行 A 或 B 都会报错:ImportError: cannot import name 'b' from partially initialized module 'mutualImportB' (most likely due to a circular import)
当然有些人习惯于用 import 的导入而非 from import 的导入方式,这时候的报错就会变成:AttributeError: partially initialized module 'mutualImportB' has no attribute 'b' (most likely due to a circular import)
好的,这两个报错还算友好。这种导入的方式都在程序出指明了导入的内容,所以解释器可以发现这里是循环导入(most likely due to a circular import)。但有时出现的 NameError 才真正让人头疼。
我们将代码改一下,保留 from import 语句,但将其 import 后面的变量名改为通配符 * 。这次的报错:NameError: name 'b' is not defined
这就很奇怪了。我们在使用 IDE 时, IDE 不会检出相互导入时引发的循环导入问题。不过前两种在报错中即可看出,而这时,从报错中很难发现为何 b 没有声明。这种专为复现而出现的小文件中问题可以捋清思路、找到问题,在较大的项目中就往往无从下手了。
那么为什么会出现这样的情况呢?我们想一下整个程序的运行流程。
问题复现完毕,下面探讨如何解决问题。
解决问题
此前,我曾在许多平台看到过文章,但其中绝大部分都是完全重复的(尤其在 CSDN 上),明显互相“转载”来“转载”去。可惜,转载的文章并不能真正解决问题。在这篇原创的文章中,我将自己摸索的经验分享了出来。下面转入正题。
循环导入的根本原因是什么?为什么会循环导入?
其实由循环导入,我们可以想到递归而引发的栈溢出。
def a(b):
return a(b)
这,是一个明显错误的函数。一旦我们调用了函数,函数内部就会不加判断地再次调用此函数。而当我们加入了判断时:
def a(b):
if b == 1:
return 1
else:
return a(b - 1)
这样的话,该函数就转变为一个健康的函数了。
将同样的思路运用到相互导入的方式上。我们必须在整个文件初就要导入某个模块吗?一般来说不是的。我们应当将导入放在它真正被需要的函数里。比如,问题复现中的 a、b 改一下:
# mutualImportA.py
a = 1
def pA():
from mutualImportB import b
print(b)
pA()
# mutualImportB.py
b = 1
def pB():
from mutualImportA import a
print(a)
pB()
这样的话,就没有上面的循环导入的问题了。这次再划分下流程:
OK,那么问题到此为止就解决完毕了。
当然,据此问题也衍生出了一些代码的规范问题:
开发中,若文件较小,还是最好不要将需要相互使用的两个函数或类分到两个文件中。这样,可以避免不少的问题。
来源:https://blog.csdn.net/meituwo/article/details/122322043


猜你喜欢
- 1、安装flask_sqlalchemy和pymysql包pip install flask-sqlalchemypip install p
- 本文实例讲述了Sanic框架应用部署方法。分享给大家供大家参考,具体如下:简介Sanic是一个类似Flask的Python 3.5+ Web
- 后台线程•Master Thread核心后台线程,主要负责将缓冲池的数据异步刷新到磁盘。例如脏页的刷新,插入缓冲的合并,undo 页的回收等
- 一. 分析需求1. 需求说明在项目开发过程中,我们有时会频繁的更新代码, 流程大概为:(1) 本地git push提交代码至git托管平台(
- msgpackMessagePack是一种高效的二进制序列化格式。它允许你在多种语言(如JSON)之间交换数据。但它更快更小。golang
- 现在只要是有关头像的框基本都是圆形的了,C#提供的PictureBox控键默认情况下是方形的非常大的影响美观PictureBox默认情况下比
- 使用smtplib模块发送邮件,供大家参考,具体内容如下1)使用smtplib模块发送简单邮件步骤:1.连接SMTP服务器,并使用用户名、密
- 研究编码,得知GB2312编码与区位码的关系,尝试之后,得此程序。搜索,似乎没人写,故发此地。1.简述(1)GB2312标准的定义,其实就是
- 1.前言这段时间,金三银四,很多人面试,很多人分享面试题。在前段时间,我也临时担任面试官,为了大概了解面试者的水平,我也写了一份题目,面试了
- 如下所示:#python解决字符串倒序输出def string_reverse(m): num=len(m) a=[] for i in r
- 一个Javascript 的类库,用于table内容排序。使用很方便,不用每次都去调用数据库了。特别适合多表查询的排序。加上<tbod
- 代码如下:<?php$a;$b = false;$c = '';$d = 0;$e = null;$f = array
- 用过Qt的朋友 特别是QtCreator的习惯在界面UI上面对应的CPP中写代码。但是在PyQt中不是这样的。pyQt只是个界面,只会生成界
- 本文实例讲述了Python爬虫之pandas基本安装与使用方法。分享给大家供大家参考,具体如下:一、简介:Python Data Analy
- 工作中需要从一个数据库中的表GIS_WEICHAI_DATA_1S中的数据导入到另个一数据库的表GIS_WEICHAI_DATA_1S中,数
- 1.将字符的数字转成数字,比如'0'转成0可以直接用加法来实现例如:将pony表中的d 进行排序,可d的定义为varchar
- 在Qtdesigner中新建一个主界面如下所示:ctrl+R 预览从预览图中可以看出这时的界面不支持伸缩,拖动过小的话会导致部分界面遮住不可
- magpierss中就用到了snoopy,这让我有点兴趣去研究下这个咚咚。再SF上,找到了这个源代码。居然就是一个类,但不要笑看哦,功能可是
- ARIMA模型预测餐厅销量import numpy as npimport pandas as pdimport matplotlib.py
- os.systemsystem方法会创建子进程运行外部程序,方法只返回外部程序的运行结果。这个方法比较适用于外部程序没有输出结果的情况。im