偶然碰到一個問題,初想是通過動態創建Python函數的方式來解決,於是調研了動態創建Python函數的方法。
定義lambda函數
在Python中定義lambda函數的寫法很簡單,
func = lambda: "foobar"
可以認為lambda函數是最常用的一種方式。
定義局部函數
Python中函數可以在代碼塊中進行定義,比如decorator就是通過這種方式實現的,
def decorator(func): def _(*args, **kwargs): return func(*args, **kwargs) return _
通過types.FunctionType創建函數
Python標准庫中的types.FunctionType也可以用於創建函數,常見有如下兩種使用方式,
- 從已有函數構建心函數
def foobar(): return "foobar" dynamic = types.FunctionType(foobar.__code__, {})
- 配合compile函數構建
module_code = compile('def foobar(): return "foobar"', '', 'exec') function_code = [c for c in module_code.co_consts if isinstance(c, types.CodeType)][0] foobar = types.FunctionType(function_code, {}) print foobar()
通過ast創建函數
除了通過compile()直接編譯字符串代碼之外,Python中也可以直接創建ast相關對象,最終再通過compile(), types.FunctionType進行構建,
from ast import * import types function_ast = FunctionDef( name='foobar', args=arguments(args=[], vararg=None, kwarg=None, defaults=[]), body=[Return(value=Num(n=42, lineno=1, col_offset=0), lineno=1, col_offset=0)], decorator_list=[], lineno=1, col_offset=0 ) module_ast = Module(body=[function_ast]) module_code = compile(module_ast, "<>", "exec") function_code = [c for c in module_code.co_consts if isinstance(c, types.CodeType)][0] foobar = types.FunctionType(function_code, {}) print foobar()
通過eval創建函數
最后還有一個eval函數,
foobar = eval('lambda: "foobar"')
在eval函數中不能直接通過def定義函數,所以嘗試定義lambda函數進行替代。
其它方法
除了上面羅列的還有些旁的方法,比如,
將函數定義寫入到單獨的py文件中,而后通過 __import__ 操作導入模塊來獲取定義的函數。
總結
絕大部分應用場景下通過lambda或decorator就足以應付需求了,不過動態語言的函數就是真的想動態的搞,也是能找到方法的。
原文:http://soliloquize.org/2015/07/02/Python動態創建函數的幾種方法/
