我们在编写pthon代码时,模块间的数据通信主要采用以下几种方法:
1、采用全局变量。所有模块都通过引用全局变量,通过本模块对此全局变量数据的修改值,其他模块也能访问并得到此全局变量的当前值,由于全局变量的不可控性(经常出现访问的并不是要访问的变量值),不建议大家编码时过多使用全局变量。
2、通过定义的类实例化对象。通过对象调用本类对象的当前属性、方法、函数来得到本类相关数据。此方法限定了只能在定义有类对象的模块中来使用,有时要时实撑握类对象中的变化数据也较麻烦,需要通计时器或管理线程来定时刷对象属性数据得到其当前值。对没有定义类对象的其他模块要想访问此类对象的数据,需要通过定义类对象所在的模块作为中转站来传递数据,可能也很麻烦。
3、采用回调函数来实时得到类对象中的数据,方法是模块A中定义类B对象时,同时传入B对象一个A模块的函数作为B向A实时传递数据的回调函数。使用时,代码运行到B对象模块某一位置,调用此回调函数,即可实时的将B模块中的计算数据回传给了A,让A模块再进一步去处理。如B一直在计算数据,并不断的将计算情况回调给A,A接收到数据后,根据数据不断的对UI界面进行更新。但同B和A模块无直接关联的C模块想要再得到B模块的当前数据就处理起来就很复杂。
4、采用pyside或QT模块定义的类时,可以通过信号槽实时反馈类对象中的数据变化给类对象定义的模块中。信号槽的使用相对抽象,这里不作举例。
5、本文根据python的特性,结合以上方式,偿试采用一个全局字典变量,此字典变量专门存储所有可对外公开调用的模块中的函数方法,对软件中任意一模块,不论是否同其他模块有关联(如无需定义或引用类对象),均可以通过字典存储的其他模块函数来调用此函数。这只是对模块间调用函数的一个测试,可能不符合标准的程序设计思维,仅供大家参考。
测试代码分成以下几个模块:
main.py:主模块,用于测试调用各模块使用全局字典中存储的类对象函数。
testClass.py: 同main模块有关联,在main.py模块实例化此模块类对象,以便进行测试
此模块中也演示了main模块传入的回调函数的示例。
otherClass.py:同main.py和testClass.py模块无任何关联的模块,用于调用全局字典中的testClass类对象函数
gdic.py:定义全局字典变量的模块:
此模块中有定义有全局字典g_dicFuntion,字典数据格式定义如下:
key为整数ID号,每项字典元素格式为:{ID:[要调用的函数名称(实际就是地址),[函数参数列表],['所属模块文件名','所属类名','函数功能说明','函数返回值']}
main.py模块代码如下:
"""
main.py: python中偿试用全局字典调用各类中的函数:用字典存储函数地址,实现在任意可调用处调用
"""
import time,sys,io,randomfrom gdic import g_dicFuntion,gf_addFunToDic #从gdic.py中导入公用全局变量和全局函数
from testClass import * #有加入字典存储函数的类
from otherClass import * #测试调用加入字典存储的函数类#本模块中的用于测试的外部函数
#【字典key=0=>mani.py中的全局函数test1(id)】
def test1(id):return f'test1({id})'#当作回调函数用于测试:参数采用*,表示参数数量不限
def test2(*args):print(f'得到其他模块传回的值数量={len(args)},参数值={args}') #本示例回调的两个数据:x+y+z=24,[1, 3.14, True, 'abc', [4, 5, 6]]for i in range(len(args)):print(args[i])############################################################################
if __name__ == '__main__':"""函数主入口"""global g_dicFuntion #声明全局变量#g_dicFuntion[0]=[test1,[1234],['pyTextFun.py','test1(id)','参数:id=整型','返回值:字符串']] #方法一:向字典中加入函数信息gf_addFunToDic(keyID=0,funName=test1,lstArgc=[1234],lstInfo=['pyTextFun.py','test1(id)','参数:id=整型','返回值:字符串']) #推荐:向字典中加入函数信息【ID=0,即字典的key=0】print(g_dicFuntion)curFuntion=g_dicFuntion.get(0,None)print(curFuntion[0](curFuntion[1][0]))#定义CTest类对象1时,同时传入要回调本模块用的回调函数名test2cTest_obj1=CTest(9,8,7,test2) #类对象中的函数self.ctest()保存到全局字典变量中,供其他模块无差别调用,建议实例化对象的同时,就对此对象要对外公开的函数分配ID并加入到全局字典中gf_addFunToDic(keyID=1,funName=cTest_obj1.ctest,lstArgc=[9,8,7],lstInfo=['classTest.py','ctest(self,x,y,z)','x=整型,y=整型,z=整型','返回值:字符串']) #向字典中加入函数信息【ID=1】cTest_obj2=CTest(4,5,6) #CTest第二个实例化对象,方法同上gf_addFunToDic(keyID=2,funName=cTest_obj2.ctest,lstArgc=[4,5,6],lstInfo=['classTest.py','ctest(self,x,y,z)','x=整型,y=整型,z=整型','返回值:字符串']) #向字典中加入函数信息【ID=2】cTest_obj1.ctest(1,2,3) #调用对象方法,此方法有回调函数的示例 cOtherObj=otherClass() #定义第三方类对象,用来调用类CTest的对象ctestObj1等中的函数及方法(注意此方法是针对实例化对象ctestObj1的,不同的类实例化对象的同一方法可以在字典中分别保存(key不同)cOtherObj.use_classTest() #调用类CTest的实例化对象cTestObj1等的函数ctest(self,x,y,z)del cTest_obj1 #删除对象cTest_obj1,删除后,此实例化对象不可用,但对象原占用的内存段可能可执行代码段可能还存在CTest.isEnabled[0]=False #不准再使用cTest_obj1对象在字典中key=1的函数了cOtherObj.use_classTest() #再测试下结果:仍不会报错,估计此cTest_obj1对象对应的内存段的可执行代码没有被更新覆盖仍可以使用,但不保证代码运行久了不会出错,故应在相关代码中作处理,略
testClass.py模块代码如下:
"""
testClass.py:外部类模块,供pyClassFun.py模块测试全局字典调用类中函数
"""
from gdic import g_dicFuntion,gf_addFunToDic #从gdic.py中导入公用全局变量和全局函数#本模块中的用于测试的外部函数
def test3(id):return 'test3'
def test4(x,y):return 'test4'#本模块中的类
class CTest():"""用于测试的类"""objCount=0 #所有CTest类实例化对象共用的全局变量,使用方法CTest.objCountisEnabled=[] #本类当前可使用的类对象序号,如类对象被释放或锁定,不准再用字典中存储的类函数地址来调用时,对应下标元素改为Falseglobal g_dicFuntion #声明为全局变量def __init__(self,x,y,z,callback=None): self.x,self.y,self.z=x,y,zself.callback=callback #类对象定义处同时传入回调函数#也可以在初始化时就对类中的可供外部调用的函数分配ID,如下行代码,只适用于实例化一个对象,如实例化多个对象时,ID号的控制将很麻烦#gf_addFunToDic(ID=1,funName=self.ctest,lstArgc=[x,y,z],lstInfo=['classTest.py','ctest(self,x,y,z)','x=整型,y=整型,z=整型','返回值:字符串']) #向字典中加入函数信息【ID=1】CTest.objCount+=1 #在其他模块中每初始化一个新类对象,此数自+1CTest.isEnabled.append(True) #同时增加一可用状态开关#【字典key=1=>mani.py中的类实例化对象cTest_obj1】#【字典key=2=>mani.py中的类实例化对象cTest_obj2】def ctest(self,x,y,z):"""类实例化对象的此函数要被外被其他模块调用,初始化时,已将此函数加入到全局字典中,"""if(self.callback is not None): #模块向另一模块实时传递数据方法一:函数回调,前提:定义对象时要传入回调函数名称(实际是地址)lstValues=[1,3.14,True,'abc',[4,5,6]]self.callback(x+y+z,lstValues) #通过回调函数传回本模块生成的数据值return f'CTest->ctest(x={x},y={y},z={z}),CTest.isEnabled={CTest.isEnabled},类对象被实例化数量CTest.ID={CTest.objCount},'
otherClass.py模块代码如下:
"""
otherClass.py:同main.py和testClass.py无任何关联的模块,用于调用全局字典中的testClass类对象函数
"""
from gdic import g_dicFuntion,gf_addFunToDic #从gdic.py中导入公用全局变量和全局函数class otherClass():"""测试用其他类任意调用全局字典中已保存的类函数的第三方类"""global g_dicFuntion #声明为全局变量def __init__(self):passdef use_classTest(self):"""跨模块用全局字典中保存的函数地址调用函数,不必使用信号槽或逐级调用"""print('\n===模块otherClass.py中的self.use_classTest函数通过全局字典记录的函数地址调用其他模块函数:本例调用classText.ctest(x,y,z)===')curFuntion_1=g_dicFuntion.get(1,None) #得到classTest模块中的类CTest实例化对象cTest_obj1的函数ctest(x,y,z)地址,【在字典中:key=1】if(curFuntion_1 is not None):reFun=curFuntion_1[0](curFuntion_1[1][0],curFuntion_1[1][1],curFuntion_1[1][2])print(f'调用字典中保存的KEY={1}的类函数的传入参数值 = {reFun}\n') else:print(f'调用字典中保存的KEY={1}的类函数为空,没有调用成功\n')curFuntion_2=g_dicFuntion.get(2,None) #得到classTest模块中的类CTest实例化对象cTest_obj2的函数ctest(x,y,z)地址,【在字典中:key=2】if(curFuntion_2 is not None):reFun=curFuntion_2[0](curFuntion_2[1][0],curFuntion_2[1][1],curFuntion_2[1][2])print(f'调用字典中保存的KEY={2}的类函数的传入参数值 = {reFun}\n') else:print(f'调用字典中保存的KEY={2}的类函数为空,没有调用成功\n')
全局字典变量模块gdic.py代码如下:
"""
gdic.py:定义全局变量的模块
"""
#定义全局变量
g_dicFuntion={} #全局字典,保存要调用的函数信息{ID:[要调用的函数名称(实际就是地址),[函数参数列表],['所属模块文件名','所属类名','函数功能说明','函数返回值']}def gf_addFunToDic(keyID,funName,lstArgc,lstInfo):"""向记录全局函数全局字典变量中加入一项函数记录"""print(type(keyID).__name__)c=g_dicFuntion.get(keyID,None)if(type(keyID).__name__=='int' and (g_dicFuntion.get(keyID,None) is None)):g_dicFuntion[keyID]=[funName,lstArgc,lstInfo]return Trueelse:print('\n!!!!要加入字典的函数keyID不为整数,或字典key(ID)号已存在,需重新指定key(ID)号!!!!\n')raise ValueError('!!!!要加入字典的函数keyID不为整数,或字典key(ID)号已存在,需重新指定key(ID)号!!!!') #抛出异常"""
全局字典中可对外使用的函数、方法明细表
keyID号 模块 实例化对象 函数 参数 返回值 使用时效 调用模块
0 main.py 无 test1 id=整数 字符串 长期 main.py
1 classTest.py main.py->cTest_obj1 self.use_classTest x=9,y=8,z=7 字符串 有限 otherClass.py->use_classTest
2 classTest.py main.py->cTest_obj2 self.use_classTest x=4,y=5,z=6 字符串 长期 otherClass.py->use_classTest
3
4
5
6
7
8
9
"""