Python編程:遞歸與匿名函數(shù)及函數(shù)屬性與文檔字符串(函數(shù)補(bǔ)充)
本文簡(jiǎn)單扼要地說,輔以代碼進(jìn)一步地加深理解。
遞歸函數(shù)
當(dāng)函數(shù)調(diào)用自身而生成最終結(jié)果時(shí),這樣的函數(shù)稱為遞歸。有時(shí)遞歸函數(shù)非常有用,因?yàn)樗鼈兪咕帉懘a變得更容易——使用遞歸范式編寫一些算法非常容易,而其他算法則不是這樣。沒有不能以迭代方式重寫的遞歸函數(shù),換句話說,所有遞歸函數(shù)都可以通過循環(huán)迭代的方式實(shí)現(xiàn),因此通常由程序員根據(jù)手頭的情況選擇最佳方法。
遞歸函數(shù)主體通常有兩個(gè)部分:一部分的返回值依賴于對(duì)自身的后續(xù)調(diào)用,另一部分的返回值不依賴于對(duì)自身的后續(xù)調(diào)用(稱基本情況,或遞歸邊界)。
作為理解的參考示例,我們看一個(gè)階乘函數(shù)N!作為遞歸的兩部分分別是:基本情況(邊界,用來結(jié)束遞歸)是當(dāng)N為0或1時(shí),函數(shù)返回1,不需要進(jìn)一步計(jì)算。另一方面,在一般情況下的自我調(diào)用,即N!返回的生成結(jié)果:
如果你仔細(xì)想想,N!可以寫成這樣:N!= (N - 1) !*N。作為一個(gè)實(shí)際的例子,請(qǐng)看如下的階乘表示:
我們來轉(zhuǎn)化成函數(shù)實(shí)現(xiàn):
高手大俠們?cè)诰帉懰惴〞r(shí)經(jīng)常使用遞歸函數(shù),編寫遞歸函數(shù)非常有趣。作為練習(xí),嘗試使用遞歸和迭代方法解決幾個(gè)簡(jiǎn)單的問題。很好的練習(xí)對(duì)象可能是計(jì)算斐波那契數(shù)列,或其它諸如此類的東西。自己動(dòng)手去試試吧。
提示: 在編寫遞歸函數(shù)時(shí),總是考慮要進(jìn)行多少個(gè)嵌套調(diào)用,因?yàn)檫@是有限制的。有關(guān)這方面的更多信息,請(qǐng)查看sys.getrecursionlimit()和sys.setrecursionlimit()。 |
匿名函數(shù)
還有一種函數(shù)是匿名函數(shù)(Anonymous functions)。這些函數(shù)在Python中稱為lambda(蘭姆達(dá)),其通常在使用具有自己完整定義名稱的函數(shù)有些多余時(shí)而使用,此時(shí)所需要的只是一個(gè)快速、簡(jiǎn)單的一行程序來完成這項(xiàng)工作。
假設(shè)我們想要一個(gè)列表,所有N的某個(gè)值,是5的倍數(shù)的數(shù)字。為此,我們可以使用filter()函數(shù),它需要一個(gè)函數(shù)和一個(gè)可迭代對(duì)象作為輸入。返回值是一個(gè)過濾器對(duì)象,當(dāng)你遍歷它時(shí),會(huì)從輸入可迭代對(duì)象中生成元素,所需的參數(shù)函數(shù)會(huì)為其返回True。如果不使用匿名函數(shù),我們可能會(huì)這樣做:
注意我們?nèi)绾问褂胕sMultipleOfFive()來過濾前n個(gè)自然數(shù)。這似乎有點(diǎn)過分——任務(wù)及其很簡(jiǎn)單,我們不需要為其他任何事情保留isMultipleOfFive()函數(shù)。此時(shí),我們就可用lambda函數(shù)來重寫它:
邏輯是完全相同的,但是過濾函數(shù)現(xiàn)在是個(gè)lambda函數(shù),顯然,Lambda更簡(jiǎn)單。
定義Lambda函數(shù)非常簡(jiǎn)單,它遵循以下形式:
funcName = lambda [parameter_list]: expression
其返回的是一個(gè)函數(shù)對(duì)象,相當(dāng)于:
def func_ name([parameter_list]):return expression
參數(shù)列表以逗號(hào)分隔。
注意,可選參數(shù)是方括號(hào)括起來的部分,是通用語(yǔ)法的表示形式,即文中的方括號(hào)部分是可選的,根據(jù)實(shí)際需要提供,
我們?cè)賮砜戳硗鈨蓚€(gè)等價(jià)函數(shù)的例子,以兩種形式定義:
前面的例子非常簡(jiǎn)單。第一個(gè)函數(shù)將兩個(gè)數(shù)字相加,第二個(gè)函數(shù)生成字符串的大寫版本。注意,我們將lambda表達(dá)式返回的內(nèi)容賦值給一個(gè)名稱(adder_lambda, to_upper_lambda),但是當(dāng)按照filter()示例中的方式使用lambda時(shí),就不需要這樣做了——不需要把匿名函數(shù)賦給變量。
函數(shù)屬性
Python中每個(gè)函數(shù)都是一個(gè)完整的對(duì)。因此,它有許多屬性。其中一些是特殊的,可以以內(nèi)省的方式在運(yùn)行時(shí)檢查函數(shù)對(duì)象。下面的示例,展示了它們的一部分以及如何為示例函數(shù)顯示它們的值:
我們使用內(nèi)置的getattr()函數(shù)來獲取這些屬性的值。getattr(obj, attribute)等價(jià)于obj.attribute,當(dāng)我們需要在運(yùn)行時(shí)動(dòng)態(tài)地獲取屬性時(shí),就從變量中獲取屬性的名稱(如本例中所示),此時(shí)它就會(huì)派上用場(chǎng)。
運(yùn)行這個(gè)腳本會(huì)得到類似如下輸出:
__doc__ -> 返回a乘以b的結(jié)果. __name__ -> multiplication __qualname__ -> multiplication __module__ -> __main__ __defaults__ -> (1,) __code__ -> <……> __globals__ -> {…略…} __dict__ -> {} __closure__ -> None __annotations__ -> {} __kwdefaults__ -> None |
這里省略了__globals__屬性的值,內(nèi)容太多。這個(gè)屬性的含義可以在Python數(shù)據(jù)模型文檔頁(yè)面(或自帶幫助文檔中)的可調(diào)用類型部分找到:
??https://docs.python.org/3/reference/datamodel.html#the-standard-typehierarchy??
再次提醒:如果你想查看對(duì)象的所有屬性,只需調(diào)用dir(object_name),將得到其所有屬性的列表。
內(nèi)置函數(shù)
Python自帶很多內(nèi)置函數(shù)。它們可以在任何地方使用,你可以通過dir(__builtins__)來查看builtins模塊,或通過訪問官方Python文檔來獲得它們的列表。這里就不一一介紹了。在前面的學(xué)習(xí)過程中,我們已經(jīng)見過其中的一些,如any、bin、bool、divmod、filter、float、getattr、id、int、len、list、min、print、set、tuple、type和zip等,但還有更多,建議你至少應(yīng)該閱讀一次。熟悉它們,嘗試它們,為它們每個(gè)編寫一小段代碼,并確保您隨時(shí)可以使用它們,以便在需要時(shí)使用它們。
可在官方文檔中找到這個(gè)內(nèi)置函數(shù)列表:https://docs.python.org/3/library/functions.html 。
文檔化代碼
我們非常喜歡不需要文檔的代碼。當(dāng)我們正確地編程、選擇正確的名稱、并注意細(xì)節(jié)時(shí),代碼應(yīng)該是不言自明的,幾乎不需要文檔。不過,有時(shí)注釋非常有用,添加一些文檔化描述也是如此。你可以在Python的PEP 257規(guī)范——文檔字符串約定中找到Python的文檔指南:
??https://www.python.org/dev/peps/pep-0257/,??
但在這里還是會(huì)向你展示基本原理。Python的文檔中包含字符串,這些字符串被恰當(dāng)?shù)胤Q為文檔字符串(docstrings)。任何對(duì)象都可以被文檔化來加以描述記錄,可以使用單行或多行文檔字符串。單行程序非常簡(jiǎn)單。不是為函數(shù)提供另外的簽名,而應(yīng)該聲明或描述函數(shù)的目的。請(qǐng)看下面的示例:
使用三重雙引號(hào)字符串可以在以后輕松展開或擴(kuò)展文檔內(nèi)容。
使用以句號(hào)結(jié)尾的句子,不要在前后留下空行。
多行注釋的結(jié)構(gòu)與此類似。應(yīng)該用一行代碼簡(jiǎn)單地說明對(duì)象的主旨,然后是更詳細(xì)的描述。
作為多行文檔化的一個(gè)例子,我們?cè)谙旅娴睦又惺褂肧phinx表示法記錄了一個(gè)虛構(gòu)的connect()函數(shù)及文檔化描述:
提示:
Sphinx是用于創(chuàng)建Python文檔的最廣泛使用的工具之一——事實(shí)上,官方Python文檔就是用它編寫的。絕對(duì)值得花點(diǎn)時(shí)間去看看。
內(nèi)置函數(shù)help()用于即時(shí)交互使用的,它就使用對(duì)象的文檔字符串為對(duì)象創(chuàng)建文檔頁(yè)面來展示對(duì)象的用法。基本用法如下:
首先明確或定義一個(gè)對(duì)象或函數(shù)(包括已有的對(duì)象或函數(shù)),然后使用內(nèi)置help函數(shù),并把對(duì)象或函數(shù)做help的參數(shù),該函數(shù)就會(huì)返回相應(yīng)對(duì)象的說明文檔了。就這么簡(jiǎn)單。
本文小結(jié)
本文主要基于Python語(yǔ)言的一大特色——函數(shù)來拓展的一些相關(guān)編程知識(shí),包括遞歸函數(shù)(重點(diǎn)是有限性和邊界性)、lambda函數(shù)(簡(jiǎn)潔性和臨時(shí)性)以及函數(shù)的屬性以及如何實(shí)現(xiàn)函數(shù)的文檔化描述等。