首頁  >  文章  >  後端開發  >  Python動態定義函數的方法介紹

Python動態定義函數的方法介紹

不言
不言轉載
2019-03-19 09:19:092756瀏覽

這篇文章帶給大家的內容是關於Python動態定義函數的方法介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

基於 MIT 授權協定

在 Python 中,沒有可以在執行時間簡化函數定義的語法糖。然而,這並不意味著它就不可能,或難以實現。

from types import FunctionType

foo_code = compile('def foo(): return "bar"', "<string>", "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)
<Signature (code, globals, name=None, argdefs=None, closure=None)>

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"', "<string>", "exec")

compile() 是內建方法,因此同時也是文件豐富的。

exec 模式被用到,因為定義函數需要用多個語句。

>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")

聚合全部內容,並將動態建立的函數指定給一個變數。

那個被前一句程式碼編譯成的函數,成為了產生的程式碼物件的第一個常數,因此僅僅指向 foo_code 是不充分的。這是 exec 模式的直接後果,因為產生的程式碼物件可以包含多個常數。

>>> print(foo_func())

動態產生的函數可以像其它函數一樣被呼叫。

最後

除了做實驗,需要用到動態建立函數的場景很少。
玩(Toying around) Python 的內部構件是深入學習這門語言的好方法。
如果需要,可以毫不費力地越過解釋器/語言的界線。


以上是Python動態定義函數的方法介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除