Python 函數熱更(開發時)

來源:互聯網
上載者:User
Python 函數熱更(運行時更新)

特性

  1. 實現函數運行時修改(開發環境!!!, 非線上熱更!!!)
  2. 支援協程函數(tornado)

用法

from /path/to/realtimefunc import realtimefunc@coroutine@realtimefuncdef test():    # function body

引言
說到熱更, 很容易就會聯想到線上產品的熱更。 有前端, 也有後台。不過在這裡提及到的是 python 後台開發時候的熱更。

開發也需要熱更 ??
開發也有人權的啊, 什麼! 沒有? 那就自己折騰個。

後端服務的啟動一般需要做相當多的準備工作, 導致啟動的速度比較慢。開發時用的伺服器一般比不上線上的,啟動速度就更引入注目了。

當你作為一個小白剛接觸到一個 python 後端項目, 需要在上面做開發時, 你可能會遇到兩個情況。

1. 去理解一個功能, 資料存放區的結構在理解占很大一部分,對 python 這種動態資料結構, 通過代碼, 很難清晰看到一個功能(相關dict,list, set等)定義的資料結構, 或者一些全域變數的具體結構以及內容。一些固定的也許可以直接通過 db 查看資料結構, 但一些記憶體的中的資料,就難以顧及了。2. 實現一個功能寫了一大段代碼, 這大段代碼中隱藏 bug 團夥,python 是運行時檢測,也就是代碼運行到具體語句才會報錯, 這樣報錯之後的 bug 君依然得以隱藏,如果服務啟動需要5分鐘,bug 團夥規模達到 6 個以上,小半個小時就沒了。而這些 bug 可能只是簡單 key error, 真是想想都要崩潰。

備忘:

很多web架構有自啟動, 是通過檢測專案檔的 mtime , 然後替換掉當前的服務進程,比如 tornado 就是用一個定時器定時檢測專案檔, 實現 autostart。但這種重啟的是整個服務,所以費時並不會減少。

這樣很自然的就會想到, 如果可以隨時改動開發的代碼, 而不需要重啟整個服務,豈不是很爽。

實現目標:
實現一個裝飾器, 被裝飾的函數任意修改,無需重啟服務,新請求立即生效。

實現思路:
在被裝飾函數調用時, 利用 inspect.getsource 從 .py 檔案擷取該函數具體代碼, 通過 exec 重新定義和命名該函數, 使得函數代碼的修改能在下次調用中生效。最新代碼地址 realtimefunc

# -*- coding: iso-8859-1 -*-import sysimport linecacheimport refrom inspect import getsource, getfile# A decorator is used to update a function at runtime.DecoratorName = 'realtimefunc'suffix = '_runtime'PY3 = sys.version_info >= (3,)if PY3:    basestring_type = strelse:    basestring_type = basestring  # noqadef _exec_in(code, glob, loc=None):    # type: (Any, Dict[str, Any], Optional[Mapping[str, Any]]) -> Any    if isinstance(code, basestring_type):        # exec(string) inherits the caller's future imports; compile        # the string first to prevent that.        code = compile(code, '<string>', 'exec', dont_inherit=True)    exec(code, glob, loc)def _handle_real_time_func_code(func, split='\n'):    code = getsource(func)    i_indent = 0    i_decorator = 0    code_lines = code.split(split)    func_pat = re.compile(r'^\s*def\s+'+func.__name__)    for i, line in enumerate(code_lines):        if "@"+DecoratorName in line:            i_decorator = i        if  func_pat.match(line):            i_indent = line.index("def")            code_lines[i] = code_lines[i].replace(func.func_name, func.func_name+suffix, 1)            break    # rm realtimefunc decorator    code_lines.pop(i_decorator)    # code indentation    code_lines = [line[i_indent:] for line in code_lines]    code = split.join(code_lines)    return codedef realtimefunc(func):    def wrapper(*args, **kwargs):        filename = getfile(func)        # inspect use linecache to do file cache, so do checkcache first        linecache.checkcache(filename)        code_str = _handle_real_time_func_code(func)        _exec_in(code_str,func.__globals__, func.__globals__)        # A return expected when is work, if not yield instead.        return func.__globals__[func.__name__+suffix](*args, **kwargs)    return wrapper

效果
實現開發運行時修改函數, 可以很方便的查看和修改被裝飾函數相關的資料,以及構造簡單測試資料和進行簡單的分支測試。
注意
對於協成函數, 比如如果使用低版本的 tornado (比如 4.1) 請將 return 改為 yield, 位置在代碼中有注釋
inspect 中有用到 linecache 做緩衝, 在擷取函數源碼的時候需要檢查緩衝

本文適用小白, 大神繞道, 小白自娛!!!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.