一虐译、函數(shù)的定義
在 Python 中為了將代碼的流程進(jìn)行分解,可以通過函數(shù)對程序代碼的邏輯進(jìn)行過程化(函數(shù)是面向過程的)和結(jié)構(gòu)化(一個函數(shù)是一個獨(dú)立的處理結(jié)構(gòu))的封裝鞋囊,將整塊具有獨(dú)立功能的代碼隔離并打包到一個單獨(dú)的函數(shù)中宴偿,從而將一個系統(tǒng)分割為不同的部分。
我們可以把具有一定功能性(可以完成某項(xiàng)任務(wù))的代碼放到函數(shù)中钟沛,這樣在程序中需要此函數(shù)的功能時(shí)就可以直接調(diào)用函數(shù),而不必進(jìn)行重復(fù)的代碼拷貝 —— 這樣既能節(jié)省空間局扶,也有助于保持程序的一致性恨统,因?yàn)楫?dāng)后期有修改需要時(shí)你只需改變此函數(shù)的代碼而無須去尋找修改大量代碼的拷貝。
函數(shù)是Python為了最大化的代碼重用和最小化的代碼冗余而提供的最基本的程序結(jié)構(gòu)三妈。
1畜埋、函數(shù)的定義
在某些編程語言(比如C/C++)里,函數(shù)的聲明和定義是區(qū)分開的畴蒲。一個函數(shù)聲明包括函數(shù)名和參數(shù)的名字(傳統(tǒng)上還有參數(shù)的類型和函數(shù)的類型也就是返回值的類型)悠鞍, 但不必給出函數(shù)的任何代碼, 具體的代碼通常屬于函數(shù)定義的范疇模燥。這樣的設(shè)計(jì)往往是為了將函數(shù)的定義和聲明放在不同的文件中咖祭。 Python將這兩者視為一體,函數(shù)語句由聲明的標(biāo)題行以及隨后的定義體組成蔫骂。
我們使用 def 關(guān)鍵字來自定義函數(shù)么翰。自定義的函數(shù)主要由函數(shù)頭和可執(zhí)行的函數(shù)體兩部分組成。
函數(shù)定義可以由一個或多個裝飾器表達(dá)式包裝糖儡。裝飾器表達(dá)式是在函數(shù)定義時(shí)伐坏,在包含函數(shù)定義的作用域中的計(jì)算。結(jié)果必須是可調(diào)用的握联,它以函數(shù)對象作為唯一的參數(shù)來調(diào)用桦沉。返回的值綁定到函數(shù)名稱而不是函數(shù)對象。多個裝飾器以嵌套方式應(yīng)用金闽,關(guān)于裝飾器的原理和應(yīng)用我們會在下面的章節(jié)詳細(xì)介紹纯露。
下面的代碼:2、函數(shù)的返回值
Python 里的函數(shù)使用 return 語句返回一個對象挤庇,返回的對象可以是一個容器類型钞速,比如序列和字典。如果函數(shù)中沒有 return 語句嫡秕, 就會自動返回 None 對象渴语。如果函數(shù)返回多個對象,python 會自動把他們包裝在一個元組中來返回昆咽。
許多靜態(tài)類型的語言主張一個函數(shù)的類型就是其返回值的類型掷酗。但是在 python 中调违, 由于 python 是動態(tài)地確定類型而且函數(shù)能返回不同類型的對象,所以沒有將函數(shù)和類型進(jìn)行直接的的關(guān)聯(lián)汇在。
3翰萨、函數(shù)對象
def 是一個可執(zhí)行語句。當(dāng) Python 解釋器運(yùn)行了 def 語句后糕殉,便創(chuàng)建了一個函數(shù)對象(函數(shù)的可執(zhí)行代碼的包裝器)并將其賦值給了 def 關(guān)鍵字后面緊跟的變量名亩鬼。就像所有的賦值一樣,函數(shù)名變成了這個函數(shù)對象的引用阿蝶。函數(shù)對象可以賦值給其他的變量名雳锋,甚至可以保存在列表之中。函數(shù)定義時(shí)不執(zhí)行函數(shù)體只是生成函數(shù)對象并對其進(jìn)行賦值,只有當(dāng)函數(shù)被調(diào)用時(shí)函數(shù)對象(函數(shù)體)才被執(zhí)行辛蚊。
在典型的操作中粤蝎,def 語句一般在模塊文件中編寫,并自然而然的在模塊文件第一次被導(dǎo)入的時(shí)候生成定義的函數(shù)對象袋马。
4初澎、函數(shù)屬性
可以向函數(shù)附加任意的用戶定義的屬性。這樣的屬性可以用來直接把狀態(tài)信息附加到函數(shù)對象虑凛,而不必使用全局碑宴、非本地和類等其他技術(shù)。和非本地不同桑谍,這樣的屬性可以在函數(shù)自身的任何地方訪問延柠。這種變量的名稱對于一個函數(shù)來說是本地的,但是锣披,其值在函數(shù)退出后仍然保留贞间。屬性與對象相關(guān)而不是與作用域相關(guān),但直接效果是類似的盈罐。
5榜跌、函數(shù)注解
在 Python 3 中可以給函數(shù)對象附加注解信息 —— 與函數(shù)的參數(shù)和結(jié)果相關(guān)的任意的用戶自定義的數(shù)據(jù)。Python為聲明注解提供了特殊的語法盅粪,但是钓葫,它自身不做任何事情。注解完全是可選的票顾,并且础浮,出現(xiàn)的時(shí)候只是直接附加到函數(shù)對象的 __annotations__ 屬性以供其他用戶使用。
參數(shù)可以在參數(shù)名稱后面帶有 “: expression” 形式的注解奠骄。任何參數(shù)都可以具有注解豆同,即使是 *args 或 \kwargs 形式。函數(shù)可以在參數(shù)列表的后面帶有 “ -> expression ” 形式的 “返回值” 注解含鳞。這些注解可以是任何有效的 Python 表達(dá)式影锈,并且在執(zhí)行函數(shù)定義時(shí)計(jì)算。注解可能以不同于它們在源代碼中出現(xiàn)的順序計(jì)算蝉绷。注解的存在不改變函數(shù)的語義鸭廷。注解的值可以通過函數(shù)對象的 __annotations__ 字典屬性訪問,以參數(shù)的名稱作為鍵熔吗。
你可以在函數(shù)頭部的各部分之間使用空格豆混,也可以不用,但省略他們對某些讀者來說可能會提高代碼的可讀性触徐。
注解可以用作參數(shù)類型或值的特定限制,并且較大的API中你可以使用這一功能作為標(biāo)識函數(shù)接口信息的方式狐赡。
6撞鹉、匿名函數(shù):lambda
除了 def 語句之外,Python 還提供了一種生成函數(shù)對象的表達(dá)式形式:lambda 颖侄。
這個表達(dá)式創(chuàng)建了一個能夠調(diào)用的函數(shù)鸟雏,但是它返回了一個函數(shù)對象而不是將這個函數(shù)對象賦值給一個變量名。這也就是 lambda 有時(shí)叫做匿名(也就是沒有函數(shù)名)函數(shù)的原因览祖。
lambda的一般形式是:關(guān)鍵字 lambda孝鹊,之后是一個或多個參數(shù)(相當(dāng)于 def 語句頭部內(nèi)用括號括起來的參數(shù)列表),緊跟著的是一個冒號展蒂,之后是一個表達(dá)式又活,這個表達(dá)式的定義體必須和聲明放在同一行。參數(shù)是可選的锰悼,如果使用的參數(shù)話柳骄,參數(shù)通常也是表達(dá)式的一部分。
lambda [argument1, argument2, .... argumentn]: expression
由 lambda 表達(dá)式所返回的函數(shù)對象與由 def 創(chuàng)建并賦值后的函數(shù)對象工作起來是完全一樣的箕般,但是 lambda 有一些不同之處讓其在扮演特定的角色時(shí)很有用:
lambda 是一個表達(dá)式耐薯,而不是一個語句
lambda 表達(dá)式能夠出現(xiàn)在 Python 語句語法上不允許 def 出現(xiàn)的地方。例如:在一個列表常量中或者函數(shù)調(diào)用的參數(shù)中丝里。此外作為一個表達(dá)式曲初,lambda 返回了一個值(一個新的函數(shù)對象),可以選擇性地賦值給一個變量名丙者。相反复斥,def 語句總是得在頭部將一個新的函數(shù)賦值給一個變量名,而不是將這個函數(shù)作為結(jié)果返回械媒。
lambda 的主體是一個單個的表達(dá)式或語句目锭,而不是一個代碼塊
lambda 通常要比 def 功能要衅捞:你僅能夠在 lambda 主體中封裝有限的邏輯進(jìn)去,連 if 這樣的語句都不能夠使用痢虹。這是有意設(shè)計(jì)的——它限制了程序的嵌套:lambda 是一個為編寫簡單的函數(shù)而設(shè)計(jì)的被去,而 def 用來處理更大的任務(wù)。
為什么使用 lambda
通常來說,lambda 起到了一種函數(shù)速寫的作用丰捷,允許在使用的代碼內(nèi)嵌入一個函數(shù)的定義坯墨。它們完全是可選的(你總是能夠使用 def 來替代它們),但是在你僅需要嵌入小段可執(zhí)行代碼的情況下它們會帶來一個更簡潔的代碼結(jié)構(gòu)病往。
lambda 通常用來編寫跳轉(zhuǎn)表捣染,也就是行為的列表或字典,能夠按照需要執(zhí)行相應(yīng)的動作停巷。我們可以用 Python 中的字典或者其他的數(shù)據(jù)結(jié)構(gòu)來構(gòu)建更多種類的行為表庆揪,從而做同樣的事情式曲。
7、內(nèi)部/內(nèi)嵌函數(shù)
在函數(shù)體內(nèi)創(chuàng)建另外一個函數(shù)(對象)是完全合法的嚷硫。這種函數(shù)叫做內(nèi)部/內(nèi)嵌函數(shù)检访。因?yàn)楝F(xiàn)在 python 支持靜態(tài)地嵌套域,內(nèi)部函數(shù)實(shí)際上很有用的仔掸。
最明顯的創(chuàng)造內(nèi)部函數(shù)的方法是在外部函數(shù)的定義體內(nèi)定義函數(shù)脆贵。8、遞歸函數(shù)
Python 支持遞歸函數(shù) —— 即直接或間接的調(diào)用自身以進(jìn)行循環(huán)的函數(shù)起暮。它允許程序遍歷擁有任意的卖氨、不可預(yù)知的形狀的結(jié)構(gòu)。遞歸甚至是簡單循環(huán)和迭代的替換负懦,盡管它不一定是最簡單的或最高效的一種筒捺。循環(huán) VS 遞歸
遞歸在 Python 中并不像 Prolog 或 Lisp 這樣更加深奧的語言中那樣常用,因?yàn)镻ython 強(qiáng)調(diào)像循環(huán)這樣的簡單的過程式語句纸厉,循環(huán)語句通常更為自然系吭。處理任意結(jié)構(gòu)
遞歸可以要求遍歷任意形狀的結(jié)構(gòu)。簡單的循環(huán)語句在這里不起作用则吟,因?yàn)檫@不是一個線性迭代槐臀。嵌套的循環(huán)語句也不夠用,因?yàn)樽恿斜砜赡芮短椎饺我獾纳疃炔⑶乙匀我獾男问角短酌ブ佟O喾此旅娴拇a使用遞歸來對應(yīng)這種一般性的嵌套,以便順序訪問子列表敬扛。9晰洒、函數(shù)的設(shè)計(jì)理念
耦合性:只有在真正必要的情況下使用全局變量。
全局變量通常是一種蹩腳的函數(shù)間進(jìn)行通信的辦法舔哪。它們引發(fā)了依賴關(guān)系和計(jì)時(shí)的問題欢顷,會導(dǎo)致程序調(diào)試和修改的困難。
耦合性:不要改變可改變類型的參數(shù)捉蚤,除非調(diào)用者希望這樣做。
函數(shù)可以改變傳入的可變類型對象炼七,但是就像全局變量一樣缆巧,這回導(dǎo)致很多調(diào)用者和被調(diào)用者之間的耦合性,這種耦合性會導(dǎo)致一個函數(shù)過于特殊和不友好豌拙。
耦合性:避免直接改變在另一個模塊文件中的變量陕悬。
改變引入模塊中的變量會導(dǎo)致模塊文件間的耦合性,就像全局變量產(chǎn)生了函數(shù)間的耦合一樣:模塊難于理解和重用按傅。
聚合性:每一個函數(shù)都應(yīng)該有一個單一的捉超、統(tǒng)一的目標(biāo)。
在設(shè)計(jì)完美的情況下唯绍,每一個函數(shù)中都應(yīng)該做一件事:這件事可以用一個簡單說明句來總結(jié)拼岳。
簡潔:每一個函數(shù)都應(yīng)該盡可能的簡潔。
Python 代碼是以簡單明了而著稱的 况芒,一個過長或者有著深層嵌套的函數(shù)往往就成為設(shè)計(jì)缺陷的征兆惜纸。保持簡單,保持簡短绝骚。
通常來講耐版,我們應(yīng)該竭力使函數(shù)和其他編程組件中的外部依賴性最小化。函數(shù)的自包含性越好压汪,它越容易被理解粪牲、復(fù)用和修改。
10止剖、和函數(shù)相關(guān)的內(nèi)建函數(shù)
filter()
函數(shù)式編程的意思就是對序列應(yīng)用一些函數(shù)的工具腺阳。例如落君,基于某一測試函數(shù)過濾出一些元素(filter),以及對每隊(duì)元素都應(yīng)用函數(shù)并運(yùn)行到最后結(jié)果(reduce)舌狗。map()
程序?qū)α斜砗推渌蛄谐3R龅囊患虑榫褪菍γ恳粋€元素進(jìn)行一個操作并把其結(jié)果集合起來叽奥。因?yàn)?map() 是內(nèi)置函數(shù)朝氓,它總是可用的,并總是以同樣的方式工作主届,還有一些性能方面的優(yōu)勢(它要比自己編寫的 for 循環(huán)更快)赵哲。
reduce()
reduce() 位于 functools 模塊中,要更復(fù)雜一些君丁。它接收一個迭代器來處理枫夺,但是,它自身不是一個迭代器绘闷,它返回一個單個的結(jié)果橡庞。《Python基礎(chǔ)手冊》系列:
Python基礎(chǔ)手冊 1 —— Python語言介紹
Python基礎(chǔ)手冊 2 —— Python 環(huán)境搭建(Linux)
Python基礎(chǔ)手冊 3 —— Python解釋器
Python基礎(chǔ)手冊 4 —— 文本結(jié)構(gòu)
Python基礎(chǔ)手冊 5 —— 標(biāo)識符和關(guān)鍵字
Python基礎(chǔ)手冊 6 —— 操作符
Python基礎(chǔ)手冊 7 —— 內(nèi)建函數(shù)
Python基礎(chǔ)手冊 8 —— Python對象
Python基礎(chǔ)手冊 9 —— 數(shù)字類型
Python基礎(chǔ)手冊10 —— 序列(字符串)
Python基礎(chǔ)手冊11 —— 序列(元組&列表)
Python基礎(chǔ)手冊12 —— 序列(類型操作)
Python基礎(chǔ)手冊13 —— 映射(字典)
Python基礎(chǔ)手冊14 —— 集合
Python基礎(chǔ)手冊15 —— 解析
Python基礎(chǔ)手冊16 —— 文件
Python基礎(chǔ)手冊17 —— 簡單語句
Python基礎(chǔ)手冊18 —— 復(fù)合語句(流程控制語句)
Python基礎(chǔ)手冊19 —— 迭代器
Python基礎(chǔ)手冊20 —— 生成器
Python基礎(chǔ)手冊21 —— 函數(shù)的定義
Python基礎(chǔ)手冊22 —— 函數(shù)的參數(shù)
Python基礎(chǔ)手冊23 —— 函數(shù)的調(diào)用
Python基礎(chǔ)手冊24 —— 函數(shù)中變量的作用域
Python基礎(chǔ)手冊25 —— 裝飾器
Python基礎(chǔ)手冊26 —— 錯誤 & 異常
Python基礎(chǔ)手冊27 —— 模塊
Python基礎(chǔ)手冊28 —— 模塊的高級概念
Python基礎(chǔ)手冊29 —— 包