0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python動(dòng)態(tài)定義函數(shù)實(shí)現(xiàn)

454398 ? 來(lái)源:Python貓 ? 作者:Philip Trauner ? 2020-11-19 15:42 ? 次閱讀

作者:Philip Trauner 譯者:豌豆花下貓”

Python 中,沒(méi)有可以在運(yùn)行時(shí)簡(jiǎn)化函數(shù)定義的語(yǔ)法糖。然而,這并不意味著它就不可能,或者是難以實(shí)現(xiàn)。

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

剖析

逐行檢視代碼,你會(huì)發(fā)現(xiàn)語(yǔ)言/解釋器的屏障是多么脆弱。

>>> from types import FunctionType

Python 文檔通常不會(huì)列出那些非用于手動(dòng)創(chuàng)建的類(lèi)的特征(這是完全合理的)。有三種方法可以解決這個(gè)問(wèn)題:help()、inspect(無(wú)法查看內(nèi)置方法)、以及最后的解決方案,即查看 CPython 源代碼。

在本例中,help() 與 inspect 都可以完成工作,但是查看實(shí)際的源代碼,則會(huì)揭示出關(guān)于數(shù)據(jù)類(lèi)型的更多細(xì)節(jié)。

>>> from inspect import signature
>>> signature(FunctionType)

1. code

內(nèi)部是一個(gè)PyCodeobject,作為types.CodeType對(duì)外開(kāi)放。非內(nèi)置方法擁有一個(gè)__code__屬性,該屬性保存了相應(yīng)的代碼對(duì)象。利用內(nèi)置 compile() 方法,可以在運(yùn)行期創(chuàng)建types.CodeType對(duì)象。

2. globals

如果一個(gè)函數(shù)引用的變量不是在局部定義的,而是作為參數(shù)轉(zhuǎn)入、由默認(rèn)參數(shù)值提供、或者通過(guò)閉包上下文提供,則它會(huì)在 globals 字典中查找。

內(nèi)置的 globals() 方法會(huì)返回一個(gè)對(duì)當(dāng)前模塊的全局符號(hào)表(global symbol table)的引用 ,因此能被用來(lái)提供一個(gè)總是與當(dāng)前表的狀態(tài)相一致的字典。傳入任意其它的字典也是可以的(FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz")。

3. name(可選)

控制所返回的函數(shù)的__name__ 屬性。只真正對(duì) lambdas 有用(由于匿名性,它們通常沒(méi)有名稱(chēng)),并且重命名函數(shù)。

4. argdefs(可選)

通過(guò)傳入一個(gè)包含任意類(lèi)型的對(duì)象的元組,提供一個(gè)方式來(lái)供應(yīng)默認(rèn)參數(shù)值(def foo(bar="baz"))。(FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10)。

5. closure(可選)

(如果需要在 CPython(PyPy,Jython,…)以外的其它 Python VM 中執(zhí)行,可能不應(yīng)該觸及,因?yàn)樗鼑?yán)重地依賴(lài)于實(shí)現(xiàn)細(xì)節(jié))。

一個(gè)cell 對(duì)象的元組。創(chuàng)建 cell 對(duì)象并非完全是直截了當(dāng)?shù)?,因?yàn)樾枰{(diào)用 CPython 的內(nèi)部組件,但有一個(gè)庫(kù)可以令它更加方便:exalt(無(wú)恥的廣告)。(譯注:這個(gè)庫(kù)是作者開(kāi)發(fā)的。)

>>> foo_code = compile('def foo(): return "bar"', "", "exec")

compile() 是一個(gè)內(nèi)置方法,因此同時(shí)也是文檔豐富的。

exec 模式被用到,因?yàn)槎x函數(shù)需用多個(gè)語(yǔ)句。

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

聚合全部?jī)?nèi)容,并將動(dòng)態(tài)創(chuàng)建的函數(shù)指定給一個(gè)變量。

那個(gè)被前一句代碼編譯成的函數(shù),成為了生成的代碼對(duì)象的第一個(gè)常量,因此僅僅指向 foo_code 是不充分的。這是 exec 模式的直接后果,因?yàn)樯傻拇a對(duì)象可以包含多個(gè)常量。

>>> print(foo_func())

動(dòng)態(tài)生成的函數(shù)可以像其它函數(shù)一樣被調(diào)用。

結(jié)尾

除了做實(shí)驗(yàn),需要用到動(dòng)態(tài)創(chuàng)建函數(shù)的場(chǎng)景很少。

玩耍(Toying around) Python 的內(nèi)部構(gòu)件是一種深入學(xué)習(xí)這門(mén)語(yǔ)言的好方法。

如果需要,可以毫不費(fèi)力地越過(guò)解釋器/語(yǔ)言的界線(xiàn)。

還是一如既往地:不要濫用語(yǔ)言 (好吧,一點(diǎn)點(diǎn)也無(wú)妨,對(duì)吧?)

譯者簡(jiǎn)介: 豌豆花下貓,生于廣東畢業(yè)于武大,現(xiàn)為蘇漂程序員,有一些極客思維,也有一些人文情懷,有一些溫度,還有一些態(tài)度。

編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • python
    +關(guān)注

    關(guān)注

    53

    文章

    4753

    瀏覽量

    84077
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    不屬于python的內(nèi)置函數(shù)

    Python是一種高級(jí)編程語(yǔ)言,它提供了許多內(nèi)置函數(shù),可以幫助開(kāi)發(fā)人員更輕松地處理各種任務(wù)。但是,在Python中并非所有的函數(shù)都是內(nèi)置函數(shù)
    的頭像 發(fā)表于 11-29 14:27 ?1147次閱讀

    python中各種函數(shù)的用法

    Python中有很多種不同類(lèi)型的函數(shù),它們?cè)诮鉀Q各種問(wèn)題和完成不同任務(wù)時(shí)起著重要的作用。下面我將詳細(xì)介紹幾種常用的函數(shù),包括內(nèi)置函數(shù)、自定義
    的頭像 發(fā)表于 11-23 15:48 ?619次閱讀

    python調(diào)用math函數(shù)的方法

    Python編程中,數(shù)學(xué)函數(shù)是非常重要的工具,我們可以使用它們進(jìn)行各種數(shù)值計(jì)算、幾何運(yùn)算和統(tǒng)計(jì)分析等操作。Python的標(biāo)準(zhǔn)庫(kù)中內(nèi)置了很多數(shù)學(xué)函數(shù),而其中最基本和常用的數(shù)學(xué)
    的頭像 發(fā)表于 11-22 11:01 ?2100次閱讀

    python的format函數(shù)怎么用

    Python中的format()函數(shù)是用于格式化字符串的內(nèi)置函數(shù)。它允許我們將變量的值插入到字符串中,并對(duì)字符串進(jìn)行格式化以滿(mǎn)足特定的需求。format()函數(shù)使用大括號(hào){}作為占位符
    的頭像 發(fā)表于 11-22 09:44 ?1828次閱讀

    復(fù)數(shù)中i在Python中如何定義

    復(fù)數(shù)中的虛數(shù)單位'i'在Python中可以通過(guò)使用cmath模塊來(lái)定義和使用。cmath模塊提供了處理復(fù)數(shù)的函數(shù)和常量。 在Python中,虛數(shù)單位'i'表示為1j。它是一個(gè)特殊的數(shù)值
    的頭像 發(fā)表于 11-22 09:40 ?2114次閱讀

    python函數(shù)返回多個(gè)參數(shù)

    。 在Python中,可以使用關(guān)鍵字 return 來(lái)返回一個(gè)或多個(gè)值。在函數(shù)定義的末尾,可以使用 return 語(yǔ)句來(lái)指定函數(shù)要返回的值。這些返回的值可以是一個(gè)變量、一個(gè)常量、一個(gè)列
    的頭像 發(fā)表于 11-21 16:37 ?930次閱讀

    sort函數(shù)python用法

    sort()函數(shù)Python中的內(nèi)置函數(shù)之一,用于對(duì)可迭代對(duì)象進(jìn)行排序??傻鷮?duì)象包括列表、元組和字符串等。sort()函數(shù)是一個(gè)靈活而強(qiáng)大的函數(shù)
    的頭像 發(fā)表于 11-21 15:15 ?1046次閱讀

    python定義函數(shù)和返回多個(gè)值方法

    函數(shù) 如果想定義一個(gè)什么事也不做的空函數(shù),可以用pass語(yǔ)句 def nop (): pass pass可用來(lái)作為占位符,比如現(xiàn)在還沒(méi)想好怎么寫(xiě)函數(shù)的代碼,就可以先放一個(gè)pass,讓
    的頭像 發(fā)表于 11-14 11:33 ?460次閱讀

    python如何定義一個(gè)函數(shù)

    一、Python3 函數(shù) 函數(shù)是組織好的,可重復(fù)使用的,用來(lái)實(shí)現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段。 函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率。你
    的頭像 發(fā)表于 11-14 11:26 ?597次閱讀

    在單片機(jī)上實(shí)現(xiàn)動(dòng)態(tài)加載功能的函數(shù)庫(kù)介紹

    本項(xiàng)目是一個(gè)在單片機(jī)(如:STM32)上實(shí)現(xiàn)動(dòng)態(tài)加載功能的函數(shù)庫(kù),與Windows中的dll,Linux中的so類(lèi)似,可以將代碼動(dòng)態(tài)地從其他的存儲(chǔ)介質(zhì),
    的頭像 發(fā)表于 11-09 10:55 ?1221次閱讀

    Python 函數(shù)參數(shù)分類(lèi)

    文章應(yīng)該對(duì)你會(huì)有不小的幫助。 接下來(lái)是正文。 1. 參數(shù)分類(lèi) 函數(shù),在定義的時(shí)候,可以有參數(shù)的,也可以沒(méi)有參數(shù)。 從函數(shù)定義的角度來(lái)看,參數(shù)可以分為兩種: 必選參數(shù) :調(diào)用
    的頭像 發(fā)表于 10-21 10:45 ?515次閱讀

    C語(yǔ)言中宏函數(shù)定義和用法

    函數(shù)是一種特殊的函數(shù)宏,與普通函數(shù)宏不同的是,它可以擁有多條語(yǔ)句和局部變量,從而實(shí)現(xiàn)更復(fù)雜的功能。它的定義類(lèi)似于普通
    發(fā)表于 10-11 11:32 ?2775次閱讀
    C語(yǔ)言中宏<b class='flag-5'>函數(shù)</b>的<b class='flag-5'>定義</b>和用法

    python定義函數(shù)與調(diào)用函數(shù)的順序

    定義函數(shù)與調(diào)用函數(shù)的順序 函數(shù)定義后,本身是不會(huì)自動(dòng)執(zhí)行的,只有在被調(diào)用后,函數(shù)才會(huì)被執(zhí)行,得
    的頭像 發(fā)表于 10-04 17:17 ?1036次閱讀

    一文詳解python調(diào)用函數(shù)

    函數(shù)定義后,本身是不會(huì)自動(dòng)執(zhí)行的,只有在被調(diào)用后,函數(shù)才會(huì)被執(zhí)行,得到相應(yīng)的結(jié)果。但是在 Python 中我們要注意一個(gè)關(guān)鍵點(diǎn),就是Python
    發(fā)表于 10-01 10:45 ?512次閱讀

    python中eval的用法和作用

    `eval()`函數(shù)的作用是將字符串作為Python表達(dá)式進(jìn)行求值。它可以執(zhí)行包括算術(shù)運(yùn)算、邏輯運(yùn)算、函數(shù)調(diào)用以及定義在當(dāng)前命名空間中的變量等在內(nèi)的各種表達(dá)式。使用`eval()`可以
    的頭像 發(fā)表于 09-28 16:26 ?3544次閱讀