Python入門 - 第 3 節(jié)課:函數(shù)

目錄


1. 函數(shù)定義

定義函數(shù)

函數(shù)定義示例:

def cylinder_volume(height, radius):
    pi = 3.14159
    return height * pi * radius ** 2

定義 cylinder_volume 函數(shù)后,我們可以如下所示地調(diào)用該函數(shù)。

cylinder_volume(10, 3)

函數(shù)定義包含幾個(gè)重要部分。

  • 函數(shù)頭部

我們從函數(shù)頭部開始举畸,即函數(shù)定義的第一行。

  1. 函數(shù)頭部始終以關(guān)鍵字 def 開始郑诺,表示這是函數(shù)定義羡鸥。
  2. 然后是函數(shù)名稱(在此例中是 cylinder_volume想括,因?yàn)楹瘮?shù)名是要一個(gè)單詞曾沈,所以需要用_進(jìn)行連接)尘颓,遵循的是和變量一樣的命名規(guī)范。你可以在本頁(yè)面下方回顧下命名規(guī)范晦譬。
  3. 名稱之后是括號(hào),其中可能包括用英文逗號(hào)分隔的參數(shù)(在此例中是 heightradius)互广。形參(或?qū)崊ⅲ?/a>是當(dāng)函數(shù)被調(diào)用時(shí)作為輸入傳入的值敛腌,用在函數(shù)主體中卧土。如果函數(shù)沒(méi)有參數(shù),這些括號(hào)留空像樊。
  4. 頭部始終以英文冒號(hào) : 結(jié)束尤莺。
    ?
  • 函數(shù)主體

函數(shù)的剩余部分包含在主題中,也就是函數(shù)完成操作的部分生棍。

  1. 函數(shù)主體是在頭部行之后縮進(jìn)的代碼颤霎。在此例中是定義 π 和返回體積的兩行代碼。
  2. 在此主體中涂滴,我們可以引用參數(shù)并定義新的變量友酱,這些變量只能在這些縮進(jìn)代碼行內(nèi)使用。
  3. 主體將經(jīng)常包括 return 語(yǔ)句柔纵,用于當(dāng)函數(shù)被調(diào)用時(shí)返回輸出值缔杉。return 語(yǔ)句包括關(guān)鍵字 return,然后是經(jīng)過(guò)評(píng)估以獲得函數(shù)輸出值的表達(dá)式搁料。如果沒(méi)有 return 語(yǔ)句或详,函數(shù)直接返回 None(例如內(nèi)置 print() 函數(shù))。
    ?
  • 函數(shù)的命名規(guī)范

函數(shù)名稱遵守和變量一樣的命名規(guī)范郭计。

  1. 僅在函數(shù)名稱中使用普通字母霸琴、數(shù)字和下劃線。不能有空格昭伸,需要以字母或下劃線開頭梧乘。
  2. 不能使用在 Python 中具有重要作用的保留字或內(nèi)置標(biāo)識(shí)符,我們將在這門課程中學(xué)習(xí)這方面的知識(shí)勋乾。要了解 python 保留字列表宋下,請(qǐng)參閱此處
  3. 嘗試使用可以幫助讀者了解函數(shù)作用的描述性名稱辑莫。

?

默認(rèn)參數(shù)

我們可以向函數(shù)中添加默認(rèn)參數(shù)学歧,以便為在函數(shù)調(diào)用中未指定的參數(shù)提供默認(rèn)值。

def cylinder_volume(height, radius=5):
    pi = 3.14159
    return height * pi * radius ** 2

在上述示例中各吨,如果在函數(shù)調(diào)用中忽略了 radius枝笨,則將該參數(shù)設(shè)為 5。如果我們調(diào)用 cylinder_volume(10)揭蜒,該函數(shù)將使用 10 作為高度横浑,使用 5 作為半徑。但是屉更,如果調(diào)用 cylinder_volume(10, 7)徙融,7 將覆蓋默認(rèn)的值 5。

此外注意瑰谜,我們按照位置向參數(shù)傳遞值欺冀∈骷ǎ可以通過(guò)兩種方式傳遞值:按照位置和按照名稱。下面兩個(gè)函數(shù)的效果是一樣的隐轩。

cylinder_volume(10, 7)  # pass in arguments by position
cylinder_volume(height=10, radius=7)  # pass in arguments by name

?
?

2. 變量作用域

變量作用域是指可以在程序的哪個(gè)部分引用或使用某個(gè)變量饺饭。

在函數(shù)中使用變量時(shí),務(wù)必要考慮作用域职车。如果變量是在函數(shù)內(nèi)創(chuàng)建的瘫俊,則只能在該函數(shù)內(nèi)使用該變量。你無(wú)法從該函數(shù)外面訪問(wèn)該變量悴灵。

# This will result in an error
def some_function():
    word = "hello"

print(word)

這意味著你可以為在不同函數(shù)內(nèi)使用的不同變量使用相同的名稱扛芽。

# This works fine
def some_function():
    word = "hello"

def another_function():
    word = "goodbye"

像這樣在函數(shù)之外定義的變量依然可以在函數(shù)內(nèi)訪問(wèn)。

# This works fine
word = "hello"

def some_function():
    print(word)

print(word)

注意称勋,我們可以在此函數(shù)內(nèi)以及函數(shù)外輸出 word胸哥。作用域?qū)斫庑畔⒃谟?Python 和任何編程語(yǔ)言編寫的程序中的傳遞方式來(lái)說(shuō)很關(guān)鍵。

?
?

3. 文檔

文檔使代碼更容易理解和使用赡鲜。函數(shù)尤其容易理解空厌,因?yàn)樗鼈兺ǔJ褂梦臋n字符串,簡(jiǎn)稱 docstrings银酬。文檔字符串是一種注釋嘲更,用于解釋函數(shù)的作用以及使用方式。下面是一個(gè)包含文檔字符串的人口密度函數(shù)揩瞪。

def population_density(population, land_area):
    """Calculate the population density of an area. """
    return population / land_area

文檔字符串用三個(gè)引號(hào)引起來(lái)赋朦,第一行簡(jiǎn)要解釋了函數(shù)的作用。如果你覺得信息已經(jīng)足夠了李破,可以在文檔字符串中只提供這么多的信息宠哄;一行文檔字符串完全可接受,如上述示例所示嗤攻。

def population_density(population, land_area):
    """Calculate the population density of an area.

    INPUT:
    population: int. The population of that area
    land_area: int or float. This function is unit-agnostic, if you pass in values in terms
    of square km or square miles the function will return a density in those units.

    OUTPUT: 
    population_density: population / land_area. The population density of a particular area.
    """
    return population / land_area

如果你覺得需要更長(zhǎng)的句子來(lái)解釋函數(shù)毛嫉,可以在一行摘要后面添加更多信息。在上述示例中妇菱,可以看出我們對(duì)函數(shù)的參數(shù)進(jìn)行了解釋承粤,描述了每個(gè)參數(shù)的作用和類型。我們經(jīng)常還會(huì)對(duì)函數(shù)輸出進(jìn)行說(shuō)明闯团。

文檔字符串的每個(gè)部分都是可選的辛臊。但是,提供文檔字符串是一個(gè)良好的編程習(xí)慣房交。你可以在此處詳細(xì)了解文檔字符串慣例彻舰。

?
?

4. Lambda 表達(dá)式

使用Lambda表達(dá)式創(chuàng)建匿名函數(shù),即沒(méi)有名稱的函數(shù)候味。lambda 表達(dá)式非常適合快速創(chuàng)建在代碼中以后不會(huì)用到的函數(shù)刃唤。尤其對(duì)高階函數(shù)或?qū)⑵渌瘮?shù)作為參數(shù)的函數(shù)來(lái)說(shuō)口猜,非常實(shí)用。

我們可以使用lambda 表達(dá)式將以下函數(shù)

def multiply(x, y):
    return x * y

簡(jiǎn)寫為:

double = lambda x, y: x * y

?

Lambda 函數(shù)的組成部分

  1. 關(guān)鍵字lambda 表示這是一個(gè)lambda 表達(dá)式透揣。
  2. lambda 之后是該匿名函數(shù)的一個(gè)或多個(gè)參數(shù)(用英文逗號(hào)分隔),然后是一個(gè)英文冒號(hào) :川抡。和函數(shù)相似辐真,lambda 表達(dá)式中的參數(shù)名稱是隨意的。
  3. 最后一部分是被評(píng)估并在該函數(shù)中返回的表達(dá)式崖堤,和你可能會(huì)在函數(shù)中看到的 return語(yǔ)句很像侍咱。

鑒于這種結(jié)構(gòu),lambda 表達(dá)式不太適合復(fù)雜的函數(shù)密幔,但是非常適合簡(jiǎn)短的函數(shù)楔脯。
?

Lambda 與 Map

map()是一個(gè)高階內(nèi)置函數(shù),接受函數(shù)可迭代對(duì)象作為輸入胯甩,并返回一個(gè)將該函數(shù)應(yīng)用到可迭代對(duì)象的每個(gè)元素的迭代器昧廷。下面的代碼使用 map() 計(jì)算 numbers 中每個(gè)列表的均值,并創(chuàng)建列表 averages偎箫。

通過(guò)將 mean 函數(shù)替換為在 map() 的調(diào)用中定義的 lambda表達(dá)式木柬,重寫這段代碼,使代碼更簡(jiǎn)練淹办。


numbers = [
              [34, 63, 88, 71, 29],
              [90, 78, 51, 27, 45],
              [63, 37, 85, 46, 22],
              [51, 22, 34, 11, 18]
           ]

def mean(num_list):
    return sum(num_list) / len(num_list)

# before
averages = list(map(mean, numbers))
print(averages)
 # after
averages_2 = list(map((lambda x: sum(x) / len(x)), numbers))
print(averages_2)

?

Lambda 與 Filter

filter() 是一個(gè)高階內(nèi)置函數(shù)眉枕,接受函數(shù)可迭代對(duì)象作為輸入,并返回一個(gè)由可迭代對(duì)象中的特定元素(該函數(shù)針對(duì)該元素會(huì)返回 True)組成的迭代器怜森。下面的代碼使用filter()cities中獲取長(zhǎng)度少于 10 個(gè)字符的名稱以創(chuàng)建列表 short_cities速挑。

通過(guò)將is_short 函數(shù)替換為在filter() 的調(diào)用中定義的lambda 表達(dá)式,重寫這段代碼副硅,使代碼更簡(jiǎn)練驹愚。

cities = ["New York City", "Los Angeles", "Chicago", "Mountain View", "Denver", "Boston"]

def is_short(name):
    return len(name) < 10
# before
short_cities = list(filter(is_short, cities))
print(short_cities)

 # after
short_cities = list(filter((lambda s: len(s) < 10), cities))
print(short_cities)

?
?

5. 迭代器和生成器

迭代器是每次可以返回一個(gè)對(duì)象元素的對(duì)象诚撵,例如返回一個(gè)列表。我們到目前為止使用的很多內(nèi)置函數(shù)(例如 enumerate)都會(huì)返回一個(gè)迭代器。

迭代器是一種表示數(shù)據(jù)流的對(duì)象免姿。這與列表不同,列表是可迭代對(duì)象畔师,但不是迭代器薄霜,因?yàn)樗皇菙?shù)據(jù)流。

生成器是使用函數(shù)創(chuàng)建迭代器的簡(jiǎn)單方式漱凝。也可以使用定義迭代器疮蹦,更多詳情請(qǐng)參閱此處

下面是一個(gè)叫做 my_range 的生成器函數(shù)茸炒,它會(huì)生成一個(gè)從 0 到 (x - 1) 的數(shù)字流愕乎。

def my_range(x):
    i = 0
    while i < x:
        yield i
        i += 1

注意阵苇,該函數(shù)使用了 yield 而不是關(guān)鍵字 return。這樣使函數(shù)能夠一次返回一個(gè)值感论,并且每次被調(diào)用時(shí)都從停下的位置繼續(xù)绅项。關(guān)鍵字 yield 是將生成器與普通函數(shù)區(qū)分開來(lái)的依據(jù)。

注意比肄,因?yàn)檫@段代碼會(huì)返回一個(gè)迭代器快耿,因此我們可以將其轉(zhuǎn)換為列表或用 for 循環(huán)遍歷它,以查看其內(nèi)容芳绩。例如掀亥,下面的代碼:

for x in my_range(5):
    print(x)

輸出:

0
1
2
3
4

為何要使用生成器?

生成器是構(gòu)建迭代器的 “懶惰” 方式妥色。當(dāng)內(nèi)存不夠存儲(chǔ)完整實(shí)現(xiàn)的列表時(shí)搪花,或者計(jì)算每個(gè)列表元素的代價(jià)很高,你希望盡量推遲計(jì)算時(shí)嘹害,就可以使用生成器撮竿。但是這些元素只能遍歷一次。

另一種詳細(xì)的解釋如下(詳細(xì)說(shuō)明參見 該 stack overflow 頁(yè)面吼拥。)

由于使用生成器是一次處理一個(gè)數(shù)據(jù)倚聚,在內(nèi)存和存儲(chǔ)的需求上會(huì)比使用list方式直接全部生成再存儲(chǔ)節(jié)省很多資源。

由此區(qū)別凿可,在處理大量數(shù)據(jù)時(shí)惑折,經(jīng)常使用生成器初步處理數(shù)據(jù)后,再進(jìn)行長(zhǎng)期存儲(chǔ)枯跑,而不是使用 list惨驶。因?yàn)闊o(wú)論使用生成器還是 list,都是使用過(guò)就要丟棄的臨時(shí)數(shù)據(jù)敛助。既然功能和結(jié)果一樣粗卜,那就不如用生成器。

但是生成器也有自己的局限纳击,它產(chǎn)生的數(shù)據(jù)不能回溯续扔,不像list可以任意選擇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焕数,一起剝皮案震驚了整個(gè)濱河市纱昧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堡赔,老刑警劉巖识脆,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灼捂,警方通過(guò)查閱死者的電腦和手機(jī)离例,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悉稠,“玉大人宫蛆,你說(shuō)我怎么就攤上這事〉拿停” “怎么了洒扎?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衰絮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)磷醋,這世上最難降的妖魔是什么猫牡? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮邓线,結(jié)果婚禮上淌友,老公的妹妹穿的比我還像新娘。我一直安慰自己骇陈,他們只是感情好震庭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著你雌,像睡著了一般器联。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿崭,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天拨拓,我揣著相機(jī)與錄音,去河邊找鬼氓栈。 笑死渣磷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的授瘦。 我是一名探鬼主播醋界,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼提完!你這毒婦竟也來(lái)了形纺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤氯葬,失蹤者是張志新(化名)和其女友劉穎挡篓,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡官研,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年秽澳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戏羽。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡担神,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出始花,到底是詐尸還是另有隱情妄讯,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布酷宵,位于F島的核電站亥贸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏浇垦。R本人自食惡果不足惜炕置,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望男韧。 院中可真熱鬧朴摊,春花似錦、人聲如沸此虑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)朦前。三九已至介杆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間韭寸,已是汗流浹背这溅。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棒仍,地道東北人悲靴。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像莫其,于是被迫代替她去往敵國(guó)和親癞尚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 人生苦多乱陡,快來(lái) Kotlin 浇揩,快速學(xué)習(xí)Kotlin! 什么是Kotlin憨颠? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,215評(píng)論 9 118
  • 本文翻譯自Functional Programming Howto 本文將介紹Python中函數(shù)式編程的特性胳徽。在對(duì)...
    大蟒傳奇閱讀 2,619評(píng)論 4 14
  • 〇积锅、前言 本文共108張圖,流量黨請(qǐng)慎重养盗! 歷時(shí)1個(gè)半月缚陷,我把自己學(xué)習(xí)Python基礎(chǔ)知識(shí)的框架詳細(xì)梳理了一遍。 ...
    Raxxie閱讀 18,959評(píng)論 17 410
  • 之前也自己學(xué)習(xí)過(guò)往核,但是當(dāng)時(shí)學(xué)的不是很透徹而且有點(diǎn)忘了箫爷,重新總結(jié)一下。 首先聂儒,需要說(shuō)一下虎锚,Android中的基本觸屏...
    gaaaaaaaaaao閱讀 1,058評(píng)論 1 4
  • 一個(gè)頁(yè)面上有大量圖片資源的網(wǎng)站,有哪些方法能優(yōu)化加載速度慢的問(wèn)題衩婚? 根據(jù)不同的業(yè)務(wù)場(chǎng)景及條件資源等因素窜护,從前端、后...
    英俊又可愛XD閱讀 279評(píng)論 0 0