最近寫公司 項目的時候碰到一個問題,公司使用flask,在自測單個模塊下的函數會用到flask自帶的shell調試,但是這個shell有一個問題就是無發熱加載,每次修改了文件,就要退出重新進入,然後在輸入from ..... import .... 然後開始執行函數,效率極其低下,還讓人有點惱火,所以我就想寫一個可以熱加載的shell,提高一下效率,因爲時間比較短,所以比較簡陋,不過目前能滿足我的需求
import sys, os, importlib, readline, traceback
"""
importlib.reload 重載模塊
readline 這個模塊必須有,因爲接收輸入並保存在內存
"""
def iteration_module_files():
# 獲取環境
# 篩選內置模塊和一些項目外的模塊
for module in sys.modules.values():
filename = getattr(module, '__file__', None)
if filename:
# 減少判斷只檢測本目錄下的模塊
if not os.getcwd() in filename:
continue
if filename[-4:] in ('.pyo', '.pyc'):
filename = filename[:-1]
# 將模塊也帶過去,因爲後面需要重載被修改文件的模塊
yield (filename, module)
def is_files_modify(mtimes, module_list):
# 檢測模塊文件是否修改
for filename, module in iteration_module_files():
try:
# 文件修改時間
mtime = os.stat(filename).st_mtime
except IOError:
continue
# 從dict中根據文件名取出上一次文件修改時間
old_time = mtimes.get(filename, None)
# 如果沒有上一次的修改時間,加入dict
if old_time is None:
mtimes[filename] = mtime
# 對比修改時間
elif mtime > old_time:
# 將修改了時間的模塊加入列表
module_list.add(module)
# 如果不把新的時間賦值給文件,那麼會一直進入重載
mtimes[filename] = mtime
return module_list
def file_detector():
# 添加文件修改時間
mtimes = {}
# 添加模塊
module_list = set()
# 輸出信息
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
sys.stderr.write("* Python * %s on %s\n%s\n" %
(sys.version, sys.platform, cprt))
# 死循環檢測文件是否修改
while 1:
is_files_modify(mtimes, module_list)
# 如果有文件修改,就重載修改過的模塊
if module_list:
for module in module_list:
importlib.reload(module)
# 記得清空模塊列表
module_list = set()
# 執行語句
try:
exec(input('=>'))
except KeyboardInterrupt as k:
print(' Ctrl+C')
return
except Exception as e:
print(traceback.print_exc())
def runs():
file_detector()
if __name__ == '__main__':
# 導入項目的入口模塊
__import__('test')
# print(sys.modules.keys())
runs()
"""
思路:不停檢測模塊文件的修改時間,如果文件修改就重新加載該模塊
用法:
文件 test.py
這個程序中導入test
__import__('test')
終端中:
import test
test.demo()
結果:
1111
修改文件,終端:
import test
test.demo()
結果:
1111222
退出:
輸入 exit()
或者
Ctrl+C
缺點:
只支持單行python語句,需要print打印信息
這裏還有一個缺點就是,如果通過from... import ...的形式調用摸一個函數或者類,
修改了該文件以後必須用import...形式導入修改過的文件模塊,重新加載,
因爲直接用from... import ...形式沒有重載這個模塊文件的話調用的是緩存中的模塊數據,
不過因爲這裏有輸入緩存區,所以可以每次開始先用import...再用from...import...,
每次直接上下鍵選擇即可,不需要太多額外輸入
目前在公司項目中使用還可以,但是有時候會碰到一些服務項目中用到os.path.abspath(".")當路徑,
所以要這個程序與入口程序在同級目錄下
"""