问题描述
存在这样的两个类,都在同一个模块a.py内
class YamlGlobal:
with open(get_project_path() + "/cfg/global.yaml", 'r', encoding='utf-8') as f:
glVar = yaml.load(f, Loader=yaml.SafeLoader)
......
class DatabaseGlobal:
itd = InstanceDao(SQLAlchemyConnect())
......
# 原文链接:https://blog.csdn.net/qq_33562122/article/details/135380208
# 作者:秋不溜啾
# 未经许可,不得转载
同时存在一个b.py
from dao.get_global import YamlGlobal
if __name__ == "__main__":
YamlGlobal()
当MySQL服务正常时,b.py是正常的,但当MySQL服务终止后,b.py执行时会出现“[WinError 10061] 由于目标计算机积极拒绝,无法连接。”的错误,但是b.py是没有导入DatabaseGlobal类
原因分析
Python 中的模块在被导入时会执行整个模块的代码。所以当导入一个模块时,其中的所有全局代码(在类定义之外的代码)都会被执行。即使导入的是 YamlGlobal
模块,但由于 DatabaseGlobal
类的实例化是在模块层级上进行的(不在任何函数内部),所以导入 YamlGlobal
模块时会执行 DatabaseGlobal
类的实例化代码。
这可能导致问题,因为 InstanceDao
和 SQLAlchemyConnect
的实例化需要数据库服务可用。如果没有数据库服务,这些实例化会导致错误。解决这个问题的一种方式是将需要数据库服务的实例化放在需要使用这些对象的函数内部,而不是在模块的顶层。
改造
原文链接:python类的初始化-CSDN博客
作者:秋不溜啾
未经许可,不得转载
将itd = InstanceDao(SQLAlchemyConnect())移动到DatabaseGlobal的__init__(self)里面
'''a.py'''
class YamlGlobal:
with open(get_project_path() + "/cfg/global.yaml", 'r', encoding='utf-8') as f:
glVar = yaml.load(f, Loader=yaml.SafeLoader)
......
class DatabaseGlobal:
def __init__(self):
self.itd = InstanceDao(SQLAlchemyConnect())
......
# 原文链接:https://blog.csdn.net/qq_33562122/article/details/135380208
# 作者:秋不溜啾
# 未经许可,不得转载
由于YamlGlobal的glVar变量也是在类的顶层,尝试不通过实例化YamlGlobal类,在b.py中通过类变量去get这个变量
'''b.py'''
from dao.get_global import YamlGlobal
if __name__ == "__main__":
print(YamlGlobal.glVar)
不再报数据库错误,并能直接通过类变量获取glVar的结果
而现在DatabaseGlobal的itd变量,则需要实例化后才能获取,即
DatabaseGlobal().itd
小结
在类中,如果代码直接放在类下面,则视为全局代码和类变量,在第三方模块导包时,即使没有导入该类,也会执行这些全局代码,如果想推迟到类实例化再执行这些代码或者不想成为类变量而是实例变量,则需要放到__init__或类的其他函数包裹中。