我們在編寫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
"""