python 定义函数方法_Python动态定义函数的方法介绍
本篇文章給大家帶來的內容是關于Python動態定義函數的方法介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
基于 MIT 許可協議
在 Python 中,沒有可以在運行時簡化函數定義的語法糖。然而,這并不意味著它就不可能,或者是難以實現。from types import FunctionType
foo_code = compile('def foo(): return "bar"', "", "exec")
foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")
print(foo_func())
輸出:bar
剖析
逐行檢視代碼,你會發現語言/解釋器的屏障是多么脆弱。>>> from types import FunctionType
Python 文檔通常不會列出那些非用于手動創建的類的特征(這是完全合理的)。有三種方法可以解決這個問題:help()、inspect(無法查看內置方法)、以及最后的解決方案,即查看 CPython 源代碼。(推薦:python教程)
在本例中,help() 與 inspect 都可以完成工作,但是查看實際的源代碼,則會揭示出關于數據類型的更多細節。>>> from inspect import signature
>>> signature(FunctionType)
1. code
內部是一個PyCodeobject ,作為types.CodeType 對外開放。非內置方法擁有一個__code__ 屬性,該屬性保存了相應的代碼對象。利用內置的 compile() 方法,可以在運行期創建types.CodeType 對象。
2. globals
如果一個函數引用的變量不是在局部定義的,而是作為參數轉入、由默認參數值提供、或者通過閉包上下文提供,則它會在 globals 字典中查找。
內置的 globals() 方法會返回一個對當前模塊的全局符號表(global symbol table)的引用 ,因此能被用來提供一個總是與當前表的狀態相一致的字典。傳入任意其它的字典也是可以的(FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz")。
3. name(可選)
控制所返回的函數的__name__ 屬性。只真正對 lambdas 有用(由于匿名性,它們通常沒有名稱),并且重命名函數。
4. argdefs(可選)
通過傳入一個包含任意類型的對象的元組,提供了一個方式來供應默認參數值(def foo(bar="baz"))。(FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10)。
5. closure(可選)
(如果需要在 CPython(PyPy,Jython,...)以外的其它 Python VM 中執行,可能不應該觸及,因為它嚴重地依賴于實現細節)。
一個cell 對象的元組。創建 cell 對象并非完全是直截了當的,因為需要調用 CPython 的內部組件,但有一個庫可以令它更加方便:exalt (無恥的廣告)。(譯注:這個庫是作者開發的。)>>> foo_code = compile('def foo(): return "bar"', "", "exec")
compile() 是一個內置方法,因此同時也是文檔豐富的。
exec 模式被用到,因為定義函數需要用多個語句。>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")
聚合全部內容,并將動態創建的函數指定給一個變量。
那個被前一句代碼編譯成的函數,成為了生成的代碼對象的第一個常量,因此僅僅指向 foo_code 是不充分的。這是 exec 模式的直接后果,因為生成的代碼對象可以包含多個常量。>>> print(foo_func())
動態生成的函數可以像其它函數一樣被調用。
最后
除了做實驗,需要用到動態創建函數的場景很少。
玩耍(Toying around) Python 的內部構件是一種深入學習這門語言的好方法。
如果需要,可以毫不費力地越過解釋器/語言的界線。
總結
以上是生活随笔為你收集整理的python 定义函数方法_Python动态定义函数的方法介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python爬虫与数据分析实战27_Py
- 下一篇: 构造函数必须是public吗_c++ 构