导读:前段时间想用c++写有限元程序,最终由于我个人在c++上的造诣比较差,又希望有灵活的表现形式,只能转向了python。
末尾有彩蛋,敬请关注
问题:花了三天的时间重新构建了我的有限元程序,在写测试案例的时候,发现一个Python导入模块的顺序引发的一个错误。
我在__init__.py 文件中,import包时,没有注意顺序,结果在后面文件中使用from XX import * 时,会出现找不到相应库的错误。
1、DinoFem 包2020年初我在家的时候,想给儿子写一个游戏,于是为了学习pygame,就写了一个教程,也就是我的专栏里的那个《Pygame视频教程》。里面封装了pygame,起了个新的名字叫Dino。因为儿子喜欢恐龙。
这次,我自己开始开发Fem通用框架,也使用了这个名字,叫DinoFem。
这个问题就是在开发DinoFem包的过程中发现的。
2、在python包中使用__all__ 变量一个包,比如就叫DinoFem,是一个文件夹,里面有一个__init__.py文件。这个__init__.py文件可以为空。也可以增加一些代码,用以进行在加载包时所做的操作。例如,我们的__init__.py文件是这样的内容。
也就是,我们先import一些类和函数,然后将这些函数名放在__all__这个列表里。在其他地方调用的时候,我们可以使用
from DinoFem import *
这样,我就可以导入__all__列表里的所有的函数和类或者变量了。
3、加载顺序的坑#python#
我加载了类,为什么调用的时候还是找不到呢?
在有些地方我发现,即使我使用了这个
from DinoFem import *
并且在__all__列表里已经加入了要加载的类,但是还是会出现
NameError: name 'Mesh‘ is not defined
因为我是DinoFem包的第一次迭代,所以其实有很多错误,而这个错误是藏的很深的。当我一个一个的排除之后,还是出现了这个错误。经过了1个小时的排查,终于发现了这个隐藏的问题。最终,还是我学艺不精啊。
果真应了那句名言啊:
任何人,都只能赚到自己认知范围内的钱
不然就要付出生命的代价。
__all__列表里顺序是有讲究的,必须是包的子模块中使用的元素已经被定义过。否则,就会出现"not defined"错误
4、测试案例我们设计了一个简单的案例,如图,定义了一个包DPG,里面有四个文件
# a.pydef func_a(): print("file a have a function func_a")
# b.pyfrom DPG import *def func_b(): func_a() print("file b have a function func_b")
# c.pyfrom DPG import *if __name__ == '__main__': func_b()
# __init__.pyfrom DPG.b import func_bfrom DPG.a import func_a__all__=[ 'func_b', 'func_a']
我们运行c.py文件后,就出现了错误提示
这个错误就是我们所说的import顺序引发的错误。
我们是不是只需要把__all__里的顺序调整了就可以了呢?
我们把__init__.py文件的__all__列表中加载顺序调整了之后,运行,依然出现找不到定义的错误。
我们需要把import顺序和__all__的顺序都要调整过来,才能保证程序正常调用
正确的方式应该是
# __init__.pyfrom DPG.a import func_afrom DPG.b import func_b__all__=[ 'func_a', 'func_b',]
c.py的运行结果为:
file a have a function func_a
file b have a function func_b
结论对于没有系统学习过python的朋友来说,会遇到非常多的坑。这也是在2020年初,疫情在家的时候,写了很多微头条来说明python的技巧和一些坑的原因。大概也是为了完善我自己的python编程知识吧。
彩蛋我的DinoFem程序的整体框架已经有了初步的雏形了,现在只能计算1D的问题。希望有兴趣的朋友,可以参与进来。
以下是整体的框架
代码的文档使用pydoc生成:
目前完成的部分,做了一个测试,使用了我师兄在《有限元编程课程》里使用的1D的案例。误差估计和阶的估计如下图:
这个结果,显示了非常好的2阶精度的效果。当然这个太过简单。
后续我将持续的推进这个开发,从1D慢慢写到2D、3D。
欢迎圈内的朋友加入进来。
我是张麟博士,谢谢大家的关注和支持。