imp.reload可以重載模塊,但是關鍵問題是已經實例化過的類是不會變的
比如:
- class AA:
- def testaa():
- DEBUG_MSG("test")
- self.a=AA()
複製代碼
使用imp.reload熱更新後a還是不會變,需要重新把self.a.__class__=AA才能完成熱更新
這樣非常得不方便
一種可行的做法就是實例化類的時候把類都存到一個地方,然後熱更新的時候全部把它們的__class__修改一下就行了
一開始用的裝飾器的方式,但是有一些侷限性,還是用繼承的方式
- g_allReloadObjectList=[]
- class Reload:
- __reload__=True
- def __init__(self):
- g_allReloadObjectList.append(weakref.ref(self))
複製代碼
創建類的時候就像:
- class AA(Reload):
- def __init__(self):
- Reload.__init__(self)
複製代碼
就可以在實例化類的時候把實例存到g_allReloadObjectList裏面
下面的代碼寫得比較垃圾,但是簡單易懂:
reloadAllModule的功能是遍歷base cell common user_type幾個文件夾的所有文件,然後全部重載,感覺有點暴力,可以優化成只加載修改過的文件
同時把文件裏需要熱更新的類存到g_allClasses裏
然後把g_allReloadObjectList裏存的那些的實例的__class__全部改成g_allClasses裏的
reloadSystem.py
- import inspect
- import os
- import importlib
- import imp
- import copy
- import weakref
- import KBEngine
- from KBEDebug import *
- if 0:
- from baseapp import KBEngine
- if 0:
- from cellapp import KBEngine
- #需要把此文件加入熱更新黑名單
- _blackList=["reloadSystem"]
- g_allClasses={}
- g_allReloadObjectList=[]
- class Reload:
- __reload__=True
- def __init__(self):
- g_allReloadObjectList.append(weakref.ref(self))
- def reloadAllModule():
- global g_allClasses
- g_allClasses={}
- #base cell common user_type文件夾內的所有py全部重載
- if KBEngine.component=="baseapp":
- sb=KBEngine.getResFullPath("base/kbemain.py")
- sb=sb[:-10]
- ll=len(sb)
- for s in KBEngine.listPathRes("base","py"):
- s=s[ll:-3]
- s=s.replace('/','.')
- mo=importlib.import_module(s)
- _reloadModule(mo)
- elif KBEngine.component=="cellapp":
- sb=KBEngine.getResFullPath("cell/kbemain.py")
- sb=sb[:-10]
- ll=len(sb)
- for s in KBEngine.listPathRes("cell","py"):
- s=s[ll:-3]
- s=s.replace('/','.')
- mo=importlib.import_module(s)
- _reloadModule(mo)
- #reload common
- sb=KBEngine.getResFullPath("common/cfunc.py")
- sb=sb[:-8]
- ll=len(sb)
- for s in KBEngine.listPathRes("common","py"):
- s=s[ll:-3]
- s=s.replace('/','.')
- mo=importlib.import_module(s)
- _reloadModule(mo)
- #reload userType
- sb=KBEngine.getResFullPath("user_type/UserType.py")
- sb=sb[:-11]
- ll=len(sb)
- for s in KBEngine.listPathRes("user_type","py"):
- s=s[ll:-3]
- s=s.replace('/','.')
- mo=importlib.import_module(s)
- _reloadModule(mo)
- _reloadAllObjects()
- """
- 重載模塊,然後把模塊裏面的需要重載的類全部加
- """
- def _reloadModule(mo):
- if mo.__name__ in _blackList:
- return
- imp.reload(mo)
- for name,Cls in inspect.getmembers(mo):
- if getattr(Cls,'__reload__',False):
- path=inspect.getsourcefile(Cls)
- g_allClasses[path+Cls.__name__]=Cls
- def _reloadAllObjects():
- delList=[]
- for ref in g_allReloadObjectList:
- obj=ref()
- if obj:
- n=inspect.getsourcefile(obj.__class__)+obj.__class__.__name__
- if n in g_allClasses:
- obj.__class__=g_allClasses[n]
- else:
- WARNING_MSG("not find Class "+n)
- else:
- delList.append(ref)
- for ref in delList:
- g_allReloadObjectList.remove(ref)
複製代碼
這樣就實現了即時切換__class__
並且可以用Tornado做一個類來接受socket命令然後調用globalData通知全部進程熱更新
然後在ide裏的externalTools裏做個發送socket的小工具,並且設置快捷鍵
然後只要寫了點代碼後按一下快捷鍵,服務端所有進程瞬間更新到最新的代碼,生活質量提升了不止一個檔次
如果誰有更好的熱更新方案歡迎補充