學(xué)習(xí)Python爬蟲記錄第5篇——Python語法之函數(shù)

不管哪門編程語言竹握,我們寫的最多的應(yīng)該就是函數(shù)了,我們使用別人提供的庫辆飘,實際上往往使用的就是這些庫中的各個函數(shù)了啦辐。那么污秆,函數(shù)究竟是什么,如何編寫一個簡單的函數(shù)呢昧甘?

函數(shù)(Functions)是指可重復(fù)使用的程序片段。它們允許你為某個代碼塊賦予名字战得,允許你通過這一特殊的名字在你的程序任何地方來運(yùn)行代碼塊充边,并可重復(fù)任何次數(shù)。這就是所謂的調(diào)用(Calling)函數(shù)常侦。我們已經(jīng)使用過了許多內(nèi)置的函數(shù)浇冰,例如 lenrange

函數(shù)概念可能是在任何復(fù)雜的軟件(無論使用的是何種編程語言)中重要的構(gòu)建塊聋亡,所以我們接下來將在本章中探討有關(guān)函數(shù)的各個方面肘习。

函數(shù)可以通過關(guān)鍵字 def 來定義。這一關(guān)鍵字后跟一個函數(shù)的標(biāo)識符名稱坡倔,再跟一對圓括號漂佩,其中可以包括一些變量的名稱,再以冒號結(jié)尾罪塔,結(jié)束這一行投蝉。隨后而來的語句塊是函數(shù)的一部分。下面的案例將會展示出這其實非常簡單:

案例(保存為 function1.py):

def say_hello():
    # 該塊屬于這一函數(shù)
    print('hello world')
# 函數(shù)結(jié)束

say_hello()  # 調(diào)用函數(shù)
say_hello()  # 再次調(diào)用函數(shù)

輸出:

$ python function1.py
hello world
hello world

它是如何工作的

我們以上文解釋過的方式定義名為 say_hello 的函數(shù)征堪。這個函數(shù)不使用參數(shù)瘩缆,因此在括號中沒有聲明變量。函數(shù)的參數(shù)只是輸入到函數(shù)之中佃蚜,以便我可以傳遞不同的值給它庸娱,并獲得相應(yīng)的結(jié)果。

要注意到我們可以兩次調(diào)用相同的函數(shù)谐算,這意味著我們不必重新把代碼再寫一次熟尉。

函數(shù)參數(shù)1

函數(shù)可以獲取參數(shù),這個參數(shù)的值由你所提供氯夷,借此臣樱,函數(shù)便可以利用這些值來一些事情。這些參數(shù)與變量類似腮考,這些變量的值在我們調(diào)用函數(shù)時已被定義雇毫,且在函數(shù)運(yùn)行時均已賦值完成。

函數(shù)中的參數(shù)通過將其放置在用以定義函數(shù)的一對圓括號中指定踩蔚,并通過逗號予以分隔棚放。當(dāng)我們調(diào)用函數(shù)時,我們以同樣的形式提供需要的值馅闽。要注意在此使用的術(shù)語——在定義函數(shù)時給定的名稱稱作“形參”(Parameters)飘蚯,在調(diào)用函數(shù)時你所提供給函數(shù)的值稱作“實參”(Arguments)馍迄。

案例(保存為 function_param.py):

def print_max(a, b):
    if a > b:
        print(a, 'is maximum')
    elif a == b:
        print(a, 'is equal to', b)
    else:
        print(b, 'is maximum')

# 直接傳遞字面值
print_max(3, 4)

x = 5
y = 7

# 以參數(shù)的形式傳遞變量
print_max(x, y)

輸出:

$ python function_param.py
4 is maximum
7 is maximum

它是如何工作的

在這里,我們將函數(shù)命名為 print_max 并使用兩個參數(shù)分別稱作 ab局骤。我們使用一個簡單的 if...else 語句來找出更大的那個數(shù)攀圈,并將它打印出來。

第一次調(diào)用函數(shù) print_max 時峦甩,我們以實參的形式直接向函數(shù)提供這一數(shù)字赘来。在第二次調(diào)用時,我們將變量作為實參來調(diào)用函數(shù)凯傲。print_max(x, y) 將使得實參 x 的值將被賦值給形參 a犬辰,而實參 y 的值將被賦值給形參 b。在兩次調(diào)用中冰单,print_max 都以相同的方式工作幌缝。

局部變量2

當(dāng)你在一個函數(shù)的定義中聲明變量時,它們不會以任何方式與身處函數(shù)之外但具有相同名稱的變量產(chǎn)生關(guān)系诫欠,也就是說涵卵,這些變量名只存在于函數(shù)這一局部(Local)。這被稱為變量的作用域(Scope)荒叼。所有變量的作用域是它們被定義的塊缘厢,從定義它們的名字的定義點開始。

案例(保存為 function_local.py):

x = 50

def func(x):
    print('x is', x)
    x = 2
    print('Changed local x to', x)

func(x)
print('x is still', x)

輸出:

$ python function_local.py
x is 50
Changed local x to 2
x is still 50

它是如何工作的

當(dāng)我們第一次打印出存在于函數(shù)塊的第一行的名為 x 的值時甩挫,Python 使用的是在函數(shù)聲明之上的主代碼塊中聲明的這一參數(shù)的值贴硫。

接著,我們將值 2 賦值給 x伊者。x 是我們這一函數(shù)的局部變量英遭。因此,當(dāng)我們改變函數(shù)中 x 的值的時候亦渗,主代碼塊中的 x 則不會受到影響挖诸。

隨著最后一句 print 語句,我們展示出主代碼塊中定義的 x 的值法精,由此確認(rèn)它實際上不受先前調(diào)用的函數(shù)中的局部變量的影響多律。

global 語句

如果你想給一個在程序頂層的變量賦值(也就是說它不存在于任何作用域中,無論是函數(shù)還是類)搂蜓,那么你必須告訴 Python 這一變量并非局部的狼荞,而是全局(Global)的。我們需要通過 global 語句來完成這件事帮碰。因為在不使用 global 語句的情況下相味,不可能為一個定義于函數(shù)之外的變量賦值。

你可以使用定義于函數(shù)之外的變量的值(假設(shè)函數(shù)中沒有具有相同名字的變量)殉挽。然而丰涉,這種方式不會受到鼓勵而且應(yīng)該避免拓巧,因為它對于程序的讀者來說是含糊不清的,無法弄清楚變量的定義究竟在哪一死。而通過使用 global 語句便可清楚看出這一變量是在最外邊的代碼塊中定義的肛度。

案例(保存為 function_global.py):

x = 50

def func():
    global x

    print('x is', x)
    x = 2
    print('Changed global x to', x)

func()
print('Value of x is', x)

輸出:

$ python function_global.py
x is 50
Changed global x to 2
Value of x is 2

它是如何工作的

global 語句用以聲明 x 是一個全局變量——因此,當(dāng)我們在函數(shù)中為 x 進(jìn)行賦值時投慈,這一改動將影響到我們在主代碼塊中使用的 x 的值贤斜。

你可以在同一句 global 語句中指定不止一個的全局變量,例如 global x, y, z逛裤。

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

對于一些函數(shù)來說,你可能為希望使一些參數(shù)可選并使用默認(rèn)的值猴抹,以避免用戶不想為他們提供值的情況带族。默認(rèn)參數(shù)值可以有效幫助解決這一情況。你可以通過在函數(shù)定義時附加一個賦值運(yùn)算符(=)來為參數(shù)指定默認(rèn)參數(shù)值蟀给。

要注意到蝙砌,默認(rèn)參數(shù)值應(yīng)該是常數(shù)。更確切地說跋理,默認(rèn)參數(shù)值應(yīng)該是不可變的——這將在后面的章節(jié)中予以更詳細(xì)的解釋择克。就目前來說,只要記住就行了前普。

案例(保存為 function_default.py):

def say(message, times=1):
    print(message * times)

say('Hello')
say('World', 5)

輸出:

$ python function_default.py
Hello
WorldWorldWorldWorldWorld

它是如何工作的

名為 say 的函數(shù)用以按照給定的次數(shù)打印一串字符串肚邢。如果我們沒有提供一個數(shù)值,則將按照默認(rèn)設(shè)置拭卿,只打印一次字符串骡湖。我們通過為參數(shù) times 指定默認(rèn)參數(shù)值 1 來實現(xiàn)這一點。

在第一次使用 say 時峻厚,我們只提供字符串因而函數(shù)只會將這個字符串打印一次响蕴。在第二次使用 say 時,我們既提供了字符串惠桃,同時也提供了一個參數(shù) 5浦夷,聲明我們希望說(Say)這個字符串五次。

注意

只有那些位于參數(shù)列表末尾的參數(shù)才能被賦予默認(rèn)參數(shù)值辜王,意即在函數(shù)的參數(shù)列表中擁有默認(rèn)參數(shù)值的參數(shù)不能位于沒有默認(rèn)參數(shù)值的參數(shù)之前劈狐。

這是因為值是按參數(shù)所處的位置依次分配的。舉例來說呐馆,def func(a, b=5) 是有效的懈息,但 def func(a=5, b)無效的

關(guān)鍵字參數(shù)3

如果你有一些具有許多參數(shù)的函數(shù)摹恰,而你又希望只對其中的一些進(jìn)行指定辫继,那么你可以通過命名它們來給這些參數(shù)賦值——這就是關(guān)鍵字參數(shù)(Keyword Arguments)——我們使用命名(關(guān)鍵字)而非位置(一直以來我們所使用的方式)來指定函數(shù)中的參數(shù)怒见。

這樣做有兩大優(yōu)點——其一,我們不再需要考慮參數(shù)的順序姑宽,函數(shù)的使用將更加容易遣耍。其二,我們可以只對那些我們希望賦予的參數(shù)以賦值炮车,只要其它的參數(shù)都具有默認(rèn)參數(shù)值舵变。

案例(保存為 function_keyword.py):

def func(a, b=5, c=10):
    print('a is', a, 'and b is', b, 'and c is', c)

func(3, 7)
func(25, c=24)
func(c=50, a=100)

輸出:

$ python function_keyword.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50

它是如何工作的

名為 func 的函數(shù)有一個沒有默認(rèn)參數(shù)值的參數(shù),后跟兩個各自帶有默認(rèn)參數(shù)值的參數(shù)瘦穆。

在第一次調(diào)用函數(shù)時纪隙,func(3, 7),參數(shù) a 獲得了值 3扛或,參數(shù) b 獲得了值 7绵咱,而 c 獲得了默認(rèn)參數(shù)值 10

在第二次調(diào)用函數(shù)時熙兔,func(25, c=24)悲伶,由于其所處的位置,變量 a 首先獲得了值 25住涉。然后麸锉,由于命名——即關(guān)鍵字參數(shù)——指定,變量 c 獲得了值 24舆声。變量 b 獲得默認(rèn)參數(shù)值 5花沉。

在第三次調(diào)用函數(shù)時,func(c=50, a=100)媳握,我們?nèi)渴褂藐P(guān)鍵字參數(shù)來指定值主穗。在這里要注意到,盡管 ac 之前定義毙芜,但我們還是在變量 a 之前指定了變量 c忽媒。

可變參數(shù)4

有時你可能想定義的函數(shù)里面能夠有任意數(shù)量的變量,也就是參數(shù)數(shù)量是可變的腋粥,這可以通過使用星號來實現(xiàn)(將下方案例保存為 function_varargs.py):

def total(a=5, *numbers, **phonebook):
    print('a', a)

    #遍歷元組中的所有項目
    for single_item in numbers:
        print('single_item', single_item)

    #遍歷字典中的所有項目
    for first_part, second_part in phonebook.items():
        print(first_part,second_part)

print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))

輸出:

$ python function_varargs.py
a 10
single_item 1
single_item 2
single_item 3
Inge 1560
John 2231
Jack 1123
None

它是如何工作的

當(dāng)我們聲明一個諸如 *param 的星號參數(shù)時晦雨,從此處開始直到結(jié)束的所有位置參數(shù)(Positional Arguments)都將被收集并匯集成一個稱為“param”的元組(Tuple)。

類似地隘冲,當(dāng)我們聲明一個諸如 **param 的雙星號參數(shù)時闹瞧,從此處開始直至結(jié)束的所有關(guān)鍵字參數(shù)都將被收集并匯集成一個名為 param 的字典(Dictionary)。

我們將在后面的章節(jié)探索有關(guān)元組與字典的更多內(nèi)容展辞。

return 語句

return 語句用于從函數(shù)中返回奥邮,也就是中斷函數(shù)。我們也可以選擇在中斷函數(shù)時從函數(shù)中返回一個值

案例(保存為 function_return.py):

def maximum(x, y):
    if x > y:
        return x
    elif x == y:
        return 'The numbers are equal'
    else:
        return y

print(maximum(2, 3))

輸出:

$ python function_return.py
3

它是如何工作的

maximum 函數(shù)將會返回參數(shù)中的最大值洽腺,在本例中是提供給函數(shù)的數(shù)值脚粟。它使用一套簡單的 if...else 語句來找到較大的那個值并將其返回

要注意到如果 return 語句沒有搭配任何一個值則代表著 返回 None蘸朋。None 在 Python 中一個特殊的類型核无,代表著虛無。舉個例子藕坯, 它用于指示一個變量沒有值团南,如果有值則它的值便是 None(虛無)

每一個函數(shù)都在其末尾隱含了一句 return None炼彪,除非你寫了你自己的 return 語句吐根。你可以運(yùn)行 print(some_function()),其中 some_function 函數(shù)不使用 return 語句辐马,就像這樣:

def some_function():
    pass

Python 中的 pass 語句用于指示一個沒有內(nèi)容的語句塊拷橘。

提示:有一個名為 max 的內(nèi)置函數(shù)已經(jīng)實現(xiàn)了“找到最大數(shù)”這一功能,所以盡可能地使用這一內(nèi)置函數(shù)齐疙。

DocStrings

Python 有一個甚是優(yōu)美的功能稱作文檔字符串(Documentation Strings),在稱呼它時通常會使用另一個短一些的名字docstrings旭咽。DocStrings 是一款你應(yīng)當(dāng)使用的重要工具贞奋,它能夠幫助你更好地記錄程序并讓其更加易于理解。令人驚嘆的是穷绵,當(dāng)程序?qū)嶋H運(yùn)行時轿塔,我們甚至可以通過一個函數(shù)來獲取文檔!

案例(保存為 function_docstring.py):

def print_max(x, y):
    '''打印兩個數(shù)值中的最大數(shù)仲墨。

    這兩個數(shù)都應(yīng)該是整數(shù)'''
    # 如果可能勾缭,將其轉(zhuǎn)換至整數(shù)類型
    x = int(x)
    y = int(y)

    if x > y:
        print(x, 'is maximum')
    else:
        print(y, 'is maximum')

print_max(3, 5)
print(print_max.__doc__)

輸出:

$ python function_docstring.py
5 is maximum
打印兩個數(shù)值中的最大數(shù)。

    這兩個數(shù)都應(yīng)該是整數(shù)

它是如何工作的

函數(shù)的第一行邏輯行中的字符串是該函數(shù)的 文檔字符串(DocString)目养。這里要注意文檔字符串也適用于后面相關(guān)章節(jié)將提到的模塊(Modules)類(Class) 俩由。

該文檔字符串所約定的是一串多行字符串,其中第一行以某一大寫字母開始癌蚁,以句號結(jié)束幻梯。第二行為空行,后跟的第三行開始是任何詳細(xì)的解釋說明努释。5在此強(qiáng)烈建議你在你所有重要功能的所有文檔字符串中都遵循這一約定碘梢。

我們可以通過使用函數(shù)的 __doc__(注意其中的雙下劃綫)屬性(屬于函數(shù)的名稱)來獲取函數(shù) print_max 的文檔字符串屬性。只消記住 Python 將所有東西都視為一個對象伐蒂,這其中自然包括函數(shù)煞躬。我們將在后面的類(Class)章節(jié)討論有關(guān)對象的更多細(xì)節(jié)。

如果你曾使用過 Python 的 help() 函數(shù),那么你應(yīng)該已經(jīng)了解了文檔字符串的用途了恩沛。它所做的便是獲取函數(shù)的 __doc__ 屬性并以一種整潔的方式將其呈現(xiàn)給你在扰。你可以在上方的函數(shù)中嘗試一下——只需在程序中包含 help(print_max) 就行了。要記住你可以通過按下 q 鍵來退出 help复唤。

自動化工具可以以這種方式檢索你的程序中的文檔健田。因此,我強(qiáng)烈推薦你為你編寫的所有重要的函數(shù)配以文檔字符串佛纫。你的 Python 發(fā)行版中附帶的 pydoc 命令與 help() 使用文檔字符串的方式類似妓局。

總結(jié)

我們已經(jīng)了解了許多方面的函數(shù),但我們依舊還未覆蓋到所有類型的函數(shù)呈宇。不過好爬,我們已經(jīng)覆蓋到了大部分你每天日常使用都會使用到的 Python 函數(shù)。

接下來甥啄,我們將了解如何創(chuàng)建并使用 Python 模塊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末存炮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜈漓,更是在濱河造成了極大的恐慌穆桂,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件融虽,死亡現(xiàn)場離奇詭異享完,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)有额,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門般又,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人巍佑,你說我怎么就攤上這事茴迁。” “怎么了萤衰?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵堕义,是天一觀的道長。 經(jīng)常有香客問我脆栋,道長胳螟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任筹吐,我火速辦了婚禮糖耸,結(jié)果婚禮上鲁冯,老公的妹妹穿的比我還像新娘萌腿。我一直安慰自己,他們只是感情好诽凌,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舍扰,像睡著了一般倦蚪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上边苹,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天陵且,我揣著相機(jī)與錄音,去河邊找鬼个束。 笑死慕购,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茬底。 我是一名探鬼主播沪悲,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阱表!你這毒婦竟也來了殿如?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤最爬,失蹤者是張志新(化名)和其女友劉穎涉馁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爱致,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡烤送,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒜鸡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胯努。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡牢裳,死狀恐怖逢防,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蒲讯,我是刑警寧澤忘朝,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站判帮,受9級特大地震影響局嘁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晦墙,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一悦昵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晌畅,春花似錦但指、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拦坠。三九已至,卻和暖如春剩岳,著一層夾襖步出監(jiān)牢的瞬間贞滨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工拍棕, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留晓铆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓莫湘,卻偏偏與公主長得像尤蒿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子幅垮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359