Python 動態創建函數【轉】


知乎上也有相似的問題

偶然碰到一個問題,初想是通過動態創建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動態創建函數的幾種方法/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM