Python騷操作:動態定義函式
Python騷操作:動態定義函式
標題:Python Tips: Dynamic function definition
作者:Philip Trauner
譯者:豌豆花下貓
連結:https://philip-trauner.me/blog/post/python-tips-dynamic-function-definition
基於 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 原始碼。
在本例中,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 的內部構件是一種深入學習這門語言的好方法。
- 如果需要,可以毫不費力地越過直譯器/語言的界線。
還是一如既往地: 不要濫用語言 (好吧,一點點也無妨,對吧?)
--------(譯文完)--------
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29829936/viewspace-2641364/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- python---函式定義Python函式
- python如何定義函式Python函式
- 什麼是Python函式?如何定義函式?Python函式
- .Net CLR GC動態獲取函式頭地址,C++的騷操作(慎入)GC函式C++
- Python如何定義一個函式Python函式
- 每日 30 秒 ⏱ 函式引數騷操作函式
- Python巢狀定義函式增強reduce()函式功能Python巢狀函式
- python學習總結之 函式定義defPython函式
- python函式的定義和呼叫是什麼?Python函式
- 02_函式定義及使用函式函式
- 如何在函式內部定義函式?函式
- Python動態變數名定義與呼叫Python變數
- Python 動態變數名定義與呼叫Python變數
- Python中定義(建立)、呼叫函式及返回值Python函式
- 兄弟連go教程(11)函式 - 函式定義Go函式
- 函式指標、回撥函式、動態記憶體分配、檔案操作函式指標記憶體
- python教程:自定義函式Python函式
- qt之函式重定義QT函式
- ts函式約束定義函式
- 在jQuery定義自己函式jQuery函式
- 函式引數 引數定義函式型別函式型別
- 第 8 節:函式-函式定義和引數函式
- Python基礎入門(5)- 函式的定義與使用Python函式
- makefile--函式定義與呼叫函式
- Mysql資料庫自定義函式的定義、使用方法及操作注意事項MySql資料庫函式
- Python 資料庫騷操作 — RedisPython資料庫Redis
- Python 資料庫騷操作 -- RedisPython資料庫Redis
- Python 資料庫騷操作 -- MongoDBPython資料庫MongoDB
- Python資料庫MongoDB騷操作Python資料庫MongoDB
- Python - 解包的各種騷操作Python
- Python函式/動態引數/關鍵字引數Python函式
- 動畫函式的繪製及自定義動畫函式動畫函式
- 方法(函式)的定義與引數函式
- Shell中函式的定義和使用函式
- TS定義陣列 ts宣告函式陣列函式
- Python學習-字串函式操作1Python字串函式
- Python學習-字串函式操作3Python字串函式
- python必會的函式或者操作Python函式