本文為《爬著學(xué)Python》系列第七篇文章。
我們拖了好久,終于要開始真正進(jìn)行Python語法的講解了。是的,變量與對(duì)象只是Python的語義特征,編程語言的語法特征體現(xiàn)在控制結(jié)構(gòu)。
也就是我們一般說的if,while。
我們今天要講的主要就是這兩種控制結(jié)構(gòu),即判斷和循環(huán)結(jié)構(gòu)。而且,我們涉及的是非常簡(jiǎn)單而樸素的控制結(jié)構(gòu)。關(guān)于迭代器、生成器、高級(jí)函數(shù)等知識(shí)會(huì)在Python進(jìn)階部分進(jìn)行討論。我們先打好基礎(chǔ),后面學(xué)起來會(huì)比較輕松。

判斷
判斷結(jié)構(gòu)一般也叫條件判斷結(jié)構(gòu),簡(jiǎn)單理解起來,如果滿足什么條件,那么進(jìn)行什么樣的操作。實(shí)現(xiàn)方式一般是if語句。
我們直接在if后面接上判斷條件即可完成判斷,換行后空四個(gè)空格進(jìn)行根據(jù)判斷結(jié)果的執(zhí)行部分。
if 條件:
執(zhí)行語句
條件判斷結(jié)構(gòu)以外的執(zhí)行語句
注意到我們不需要任何形式的括號(hào)來包住執(zhí)行部分,Python通過縮進(jìn)判斷語句的結(jié)構(gòu)。當(dāng)你的縮進(jìn)與if語句對(duì)齊時(shí),自動(dòng)退出條件判斷結(jié)構(gòu)。在命令行中,我們通過空行來實(shí)現(xiàn)退出:
>>> a = 3
>>> if a > 2:
... print('a is bigger than 2')
...
a is bigger than 2
簡(jiǎn)單的判斷語句結(jié)構(gòu)就是這樣。當(dāng)if后面的條件滿足時(shí),就會(huì)執(zhí)行判斷結(jié)構(gòu)中的執(zhí)行語句,否則直接跳過執(zhí)行部分推出判斷結(jié)構(gòu)。
布爾值
為了進(jìn)一步了解條件判斷結(jié)構(gòu),我們需要了解一下布爾值這種數(shù)據(jù)類型。
>>> type(True)
<class 'bool'>
布爾值分為兩種,True和False,即我們一般所說的“真”和“假”。在Python中布爾值一般有兩種出現(xiàn)方式,一種是直接賦值給變量,一種是通過判斷來得到。
>>> a = True
>>> if a:
... print('a')
...
a
>>> if a is True:
... print('a is True')
...
a is True
其中,a = True是直接把布爾值True賦給變量a,所以我們把a當(dāng)作判斷條件的時(shí)候,程序會(huì)完成執(zhí)行部分。而a is True則是在進(jìn)行判斷,這個(gè)判斷的結(jié)果為True,所以程序一樣會(huì)完成執(zhí)行部分。
而我們所謂的“進(jìn)行判斷”,其實(shí)可以看作條件判斷結(jié)構(gòu)中會(huì)自動(dòng)對(duì)判斷條件調(diào)用bool()函數(shù)。
>>> bool(a > 3)
False
事實(shí)上,之前提到的條件判斷結(jié)構(gòu)中if 條件:是根據(jù)條件返回的的布爾值來進(jìn)行判斷完成功能的。條件返回值為True則執(zhí)行,否則不執(zhí)行。這也是為什么if a:可以當(dāng)作判斷條件。
布爾值其他細(xì)節(jié)
我們知道了if 條件:在進(jìn)行判斷時(shí),實(shí)際上是在判斷條件表達(dá)式返回的布爾值。因此返回布爾值的任何對(duì)象都可以作為判斷條件。
常見的是值的大小比較,即>,<,>=,<=。很好理解,它們分別對(duì)應(yīng)“大于”、“小于”、“大于等于”、“小于等于”。
我們要特別把等于單獨(dú)說是因?yàn)?,我們不能直接用等?hào)來判斷是否等于,例如if a = 3:,我們很清楚a = 3是個(gè)賦值語句,這樣會(huì)造成歧義。因此,在判斷相等時(shí),我們連用兩個(gè)等號(hào)if a == 3:,不等于的形式為if a != 3:。
之后我們需要知道的,就是布爾值的簡(jiǎn)單邏輯運(yùn)算,包括“與”、“或”、“非”,Python中分別表示為 and,or,not。
-
條件A 與 條件B在兩個(gè)條件都為真時(shí)整個(gè)表達(dá)式的布爾值為真,否則為假。 -
條件A 或 條件B在兩個(gè)條件都為假時(shí)整個(gè)表達(dá)式的布爾值為假,否則為真。 -
非 條件直接反轉(zhuǎn)條件的布爾值。
我們可以看出and和or是二元操作符,not是一元操作符。
布爾值的邏輯結(jié)構(gòu)可以組合使用,其中and和or結(jié)合優(yōu)先度高于not,但為了代碼可讀性,還是建議在組合邏輯結(jié)構(gòu)中使用括號(hào)方便理解。
>>> a = 3
>>> if not (a > 2 and a < 4):
... print(a)
...
>>>
最后要補(bǔ)充一點(diǎn)的就是,除了布爾值以外,其實(shí)還有一些情況也能作為判斷條件。
>>> if a:
... print('a')
...
但我們直接把變量當(dāng)作判斷條件時(shí),它也可以不必是布爾值,對(duì)象直接作為判斷條件會(huì)返回一個(gè)布爾值。對(duì)于整型和浮點(diǎn)數(shù)來說,0為假;對(duì)于簡(jiǎn)單數(shù)據(jù)結(jié)構(gòu),包括字符串,它的內(nèi)容為空時(shí)是假;最后None是假。
None就好像布爾值變量一樣是一種特殊的數(shù)據(jù)類型。它的類型叫作無類型。
>>> type(None)
<class 'NoneType'>
再舉幾個(gè)例子驗(yàn)證一下:
>>> bool(0.0)
False
>>> bool([])
False
>>> bool(None)
False
>>> bool([None])
True
>>> bool('None')
True
最后還要提醒一點(diǎn),不要輕易用浮點(diǎn)數(shù)當(dāng)作判斷條件。因?yàn)镻ython中是把一個(gè)極小的浮點(diǎn)數(shù)作為0來使用的。
>>> bool(1e-323)
True
>>> bool(1e-324)
False
判斷結(jié)構(gòu)中的else
我們剛才說的判斷結(jié)構(gòu)的邏輯是,如果滿足條件就做一些對(duì)應(yīng)的事情,否則不做。其實(shí),判斷結(jié)構(gòu)還可以完成:如果滿足條件就做一些對(duì)應(yīng)的事情,否則做另一些事情。使用else就能完成這樣的功能:
>>> a = 3
>>> if a > 4:
... print('a is bigger than 4')
... else:
... print('a is not bigger than 4')
...
a is not bigger than 4
這種結(jié)構(gòu)比較簡(jiǎn)單,易于理解。
事實(shí)上,else 還可以再次進(jìn)行判斷,但我們要用elif來完成更具體的條件判斷結(jié)構(gòu):
>>> a = 4
>>> if a > 4:
... print('a is bigger than 4')
... elif a < 4:
... print('a is smaller than 4')
... else:
... print('a is equal to 4')
...
a is equal to 4
如果使用這種結(jié)構(gòu)根據(jù)不同情況分別處理時(shí),不管有沒有窮盡所有可能,都建議最后留出一個(gè)else:來處理一些其他情況防止遺漏。
關(guān)于條件判斷結(jié)構(gòu),最后要說的是,Python并不具有switch結(jié)構(gòu),可以用字典檢索通過表驅(qū)動(dòng)的方式來完成這樣的功能。
def function_1(...):
...
functions = {'a': function_1,
'b': function_2,
'c': self.method_1, ...}
func = functions[value]
func()
詳見Design and History FAQ — Python 2.7.13 documentation。
循環(huán)
講過判斷結(jié)構(gòu)以后再來講循環(huán)就簡(jiǎn)單了。我們知道條件判斷結(jié)構(gòu)是用來讓程序根據(jù)某種條件做或者不做某種事情。當(dāng)我們需要程序重復(fù)做某件事情的時(shí)候,我們就需要循環(huán)結(jié)構(gòu)了。
Python循環(huán)結(jié)構(gòu)主要有兩種實(shí)現(xiàn)語法,一種是按條件循環(huán),一種是按次數(shù)循環(huán),對(duì)應(yīng)的方法分別是while和for。
while簡(jiǎn)單使用的具體結(jié)構(gòu)如下:
while 條件:
執(zhí)行語句
循環(huán)結(jié)構(gòu)以外的語句
不難看出,while的用法和if大同小異。區(qū)別在于,if只判斷一次條件,程序順序執(zhí)行;while重復(fù)判斷,只要條件滿足,程序重復(fù)執(zhí)行,直到條件第一次不滿足為止。
>>> a = 3
>>> while a > 0 :
... print(a)
... a -= 1
...
3
2
1
上面這個(gè)控制結(jié)構(gòu)實(shí)現(xiàn)的功能很簡(jiǎn)單,依次輸出小于等于a的所有正整數(shù)。我們實(shí)現(xiàn)的方法是輸出a之后把a(bǔ)減去1,直到a不大于0了停止。
在while循環(huán)結(jié)構(gòu)中,我們的條件部分工作原理和判斷結(jié)構(gòu)中相似。但在循環(huán)結(jié)構(gòu)中,有一個(gè)新的問題,一般來說,循環(huán)結(jié)構(gòu)需要一個(gè)“出口”來停止循環(huán)。這個(gè)出口有兩種實(shí)現(xiàn)方式,一種是通過破壞判斷條件來退出,一種是在循環(huán)結(jié)構(gòu)內(nèi)部設(shè)計(jì)判斷結(jié)構(gòu)來退出。我們先講前者,后者在介紹完for循環(huán)結(jié)構(gòu)以后再討論。
正如剛才的示例循環(huán)結(jié)構(gòu)一樣,當(dāng)循環(huán)條件可變時(shí),程序就有可能退出。而我們?cè)O(shè)計(jì)循環(huán)結(jié)構(gòu)時(shí),會(huì)有意地設(shè)置循環(huán)條件,讓程序在適當(dāng)?shù)臅r(shí)候退出循環(huán)結(jié)構(gòu)。我們可以在執(zhí)行語句的基礎(chǔ)上增加一個(gè)變量作為循環(huán)次數(shù)的“計(jì)數(shù)器”:
>>> i = 0
>>> while i < 3 :
... print('hello')
... i += 1
...
hello
hello
hello
在這個(gè)程序中,變量i沒有實(shí)際意義,它是用來保存循環(huán)次數(shù)的變量??梢钥吹贸鰜恚覀?cè)谑褂?code>i之前要對(duì)其賦值進(jìn)行初始化,再進(jìn)行使用,這很不方便。事實(shí)上,while語句更多的是用來進(jìn)行循環(huán)次數(shù)不可知或者量極大時(shí)才會(huì)使用的,有事我們會(huì)看到while True:這樣的語句,這是無限循環(huán),會(huì)永遠(yuǎn)進(jìn)行下去。對(duì)于循環(huán)次數(shù)比較確定的場(chǎng)景,for循環(huán)結(jié)構(gòu)更加得心應(yīng)手。
for循環(huán)的一般結(jié)構(gòu)如下:
for 變量 in 范圍:
執(zhí)行語句
循環(huán)結(jié)構(gòu)以外的語句
其中變量是用來標(biāo)記范圍中的元素,方便在執(zhí)行語句中對(duì)其進(jìn)行操作或者引用;范圍是個(gè)可迭代對(duì)象(iterable),一般來說是簡(jiǎn)單數(shù)據(jù)結(jié)構(gòu)如列表字典等,也可以是迭代器,最簡(jiǎn)單的是range類型的對(duì)象。我們剛才說到if和while在判斷條件時(shí)會(huì)自動(dòng)調(diào)用bool()函數(shù),其實(shí)for語句一直在調(diào)用next()函數(shù),相關(guān)內(nèi)容以后深入,目前了解即可。
range是外形最為原始的Python內(nèi)置類。定義方式就像普通類,range接受3個(gè)參數(shù)range(a, b, c),你可以把它看作會(huì)生成一個(gè)以a為首項(xiàng),c為公差,元素小于b的列表。當(dāng)只給兩個(gè)參數(shù)時(shí),默認(rèn)c=1,當(dāng)只給一個(gè)參數(shù)時(shí),默認(rèn)a=0, c=1。
我們之前while中的例子可以改寫為:
>>> for i in range(3):
... print(i + 1)
...
1
2
3
關(guān)于for方法的一些技巧性的操作,會(huì)在以后的簡(jiǎn)單數(shù)據(jù)結(jié)構(gòu)和函數(shù)式編程相關(guān)內(nèi)容中進(jìn)一步介紹。
break和continue
我們之前提到,退出循環(huán)有兩種方式,一種是通過破壞循環(huán)條件退出,另一種,就是在循環(huán)結(jié)構(gòu)內(nèi)部退出。
首先,return會(huì)跳出當(dāng)前函數(shù)運(yùn)行環(huán)境,因此在循環(huán)體內(nèi)可以作為退出的方式。我們可以在函數(shù)體內(nèi)部增加一個(gè)判斷結(jié)構(gòu),在某個(gè)變量滿足某個(gè)條件時(shí),函數(shù)取得返回值,程序退出循環(huán)結(jié)構(gòu)所在的函數(shù)。
不過return不是我們要講的重點(diǎn),有關(guān)內(nèi)容會(huì)在程序結(jié)構(gòu)設(shè)計(jì)等內(nèi)容中討論。我們要說的是break和continue,我們作為比較將兩者一起講。
>>> for i in range(3):
... print('running')
... if i > 0:
... break
... print(i)
...
running
0
running
break會(huì)直接退出循環(huán)結(jié)構(gòu)。
>>> for i in range(3):
... print('running')
... if i > 0:
... continue
... print(i)
...
running
0
running
running
continue會(huì)跳過循環(huán)結(jié)構(gòu)中本次執(zhí)行過程中continue后面的執(zhí)行語句,但是不會(huì)破環(huán)循環(huán)使其結(jié)束,循環(huán)會(huì)從循環(huán)變量的下一個(gè)值繼續(xù)運(yùn)行,繼續(xù)判斷,繼續(xù)執(zhí)行,直到循環(huán)結(jié)構(gòu)有其他出口退出循環(huán)。
循環(huán)結(jié)構(gòu)中的else
我們剛才判斷結(jié)構(gòu)最后說了一個(gè)else的功能,即規(guī)定在判斷條件不滿足時(shí)才執(zhí)行的語句。其實(shí)循環(huán)結(jié)構(gòu)中也可以使用else關(guān)鍵字,但是應(yīng)用場(chǎng)景不是很多。
>>> for i in range(3):
... print('running')
... if i > 0:
... continue
... print(i)
... else:
... print('ending')
...
running
0
running
running
ending
可以看到上面的這段腳本輸出結(jié)果是不一樣的。在這里,只是為了展示一下while語句中else的格式,要注意不能把else和if對(duì)齊,否則就成了判斷語句的一部分了。
else在循環(huán)結(jié)構(gòu)中的功能為,如果循環(huán)條件沒有被破環(huán)即循環(huán)次數(shù)用完后正常退出循環(huán)結(jié)構(gòu),則執(zhí)行else部分的語句,否則跳過。所以else往往是和continue和break搭配使用,這也是為什么要先講循環(huán)的退出再討論循環(huán)中else的運(yùn)用。循環(huán)中的else在各種項(xiàng)目中見得不多,主要是因?yàn)闀?huì)影響代碼的可讀性。只要能理解別人代碼中出現(xiàn)的這種結(jié)構(gòu)就可以了,對(duì)控制結(jié)構(gòu)操作技巧要求較高的可以嘗試使用。
熟練運(yùn)用控制結(jié)構(gòu)的功能是必備的能力,這需要積極練習(xí)加深理解。實(shí)際運(yùn)用中,尤其是面向過程時(shí),我們會(huì)將判斷和循環(huán)結(jié)構(gòu)交相嵌套,完成相應(yīng)的復(fù)雜功能。這些都會(huì)在以后的深入學(xué)習(xí)中逐漸接觸。
至此,我計(jì)劃中的Python基礎(chǔ)部分就算告一段落了。我們第一次接觸了Python對(duì)象的概念,我們見識(shí)了Python簡(jiǎn)單數(shù)據(jù)類型的使用方式,我們初步了解了Python中控制結(jié)構(gòu)的形式。這就算有一些Python基礎(chǔ)了。
接下來我們會(huì)開始嘗試Python的實(shí)際使用,我們需要了解Python的內(nèi)置數(shù)據(jù)結(jié)構(gòu)的基本用法,我們需要學(xué)會(huì)定義函數(shù)集成一些簡(jiǎn)單的功能,我們需要了解Python第三方庫的使用方法和管理工具,之后,我們就可以開始嘗試編寫第一個(gè)爬蟲了。