條件判斷
計算機之所以能做很多自動化的任務,因為它可以自己做條件判斷。
比如,輸入用戶年齡,根據年齡打印不同的內容,在Python程序中,用if
語句實現:
age = 20 if age >= 18: print('your age is', age) print('adult')
根據Python的縮進規則,如果if
語句判斷是True
,就把縮進的兩行print語句執行了,否則,什么也不做。
也可以給if
添加一個else
語句,意思是,如果if
判斷是False
,不要執行if
的內容,去把else
執行了:
age = 3 if age >= 18: print('your age is', age) print('adult') else: print('your age is', age) print('teenager')
注意不要少寫了冒號:
。
當然上面的判斷是很粗略的,完全可以用elif
做更細致的判斷:
age = 3 if age >= 18: print('adult') elif age >= 6: print('teenager') else: print('kid')
elif
是else if
的縮寫,完全可以有多個elif
,所以if
語句的完整形式就是:
if <條件判斷1>: <執行1> elif <條件判斷2>: <執行2> elif <條件判斷3>: <執行3> else: <執行4>
輸入:
輸出:
if
語句執行有個特點,它是從上往下判斷,如果在某個判斷上是True
,把該判斷對應的語句執行后,就忽略掉剩下的elif
和else
,所以,請測試並解釋為什么下面的程序打印的是teenager
:
age = 20 if age >= 6: print('teenager') elif age >= 18: print('adult') else: print('kid')
if
判斷條件還可以簡寫,比如寫:
if x: print('True')
只要x
是非零數值、非空字符串、非空list等,就判斷為True
,否則為False
。
注意:返回False、None
的時候Python的交互環境不顯示結果。
再議 input
最后看一個有問題的條件判斷。很多同學會用input()
讀取用戶的輸入,這樣可以自己輸入,程序運行得更有意思:
birth = input('birth: ') if birth < 2000: print('00前') else: print('00后')
輸入1982
,結果報錯:
Traceback (most recent call last):
File "<stdin>", line 1, in <module> TypeError: unorderable types: str() > int()
這是因為input()
返回的數據類型是str
,str
不能直接和整數比較,必須先把str
轉換成整數。
Python提供了int()
函數來將字符串轉化為數字:
s = input('birth: ') birth = int(s) if birth < 2000: print('00前') else: print('00后')
輸入:
輸出:
再次運行,就可以得到正確地結果。但是,如果輸入abc
呢?又會得到一個錯誤信息:
Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'abc'
原來int()
函數發現一個字符串並不是合法的數字時就會報錯,程序就退出了。
如何檢查並捕獲程序運行期的錯誤呢?后面的錯誤和調試會講到。
循環
要計算1+2+3,我們可以直接寫表達式:
>>> 1 + 2 + 3 6
要計算1+2+3+...+10,勉強也能寫出來。
但是,要計算1+2+3+...+10000,直接寫表達式就不可能了。
為了讓計算機能計算成千上萬次的重復運算,我們就需要循環語句。
for...in循環
Python的循環有兩種,一種是for...in循環,依次把list或tuple中的每個元素迭代出來,看例子:
names = ['Michael', 'Bob', 'Tracy'] for name in names: print(name)
執行這段代碼,會依次打印names
的每一個元素:
Michael
Bob
Tracy
所以for x in ...
循環就是把每個元素代入變量x
,然后每一次都執行縮進塊的語句進行輸出。
再比如我們想計算1-10的整數之和,可以用一個sum
變量做累加:
sum = 0 for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: sum = sum + x print(sum)
如果要計算1-100的整數之和,從1寫到100有點困難,
Python提供一個range()
函數,可以生成一個整數序列,再通過list()
函數可以轉換為list。比如range(5)
生成的序列是從0開始小於5的整數:
>>> list(range(5)) [0, 1, 2, 3, 4]

range(101)
就可以生成0-100的整數序列,計算如下:
第一種:
輸入: 輸出:
第二種:
輸入: 輸出:
注意縮進,會輸出不一樣的結果:
輸入: 輸出:
while循環
第二種循環是while循環,只要條件滿足,就不斷循環,條件不滿足時退出循環,輸出的是最后一個循環的結果。
比如我們要計算100以內所有奇數之和,可以用while循環實現:
sum = 0 n = 99 while n > 0: sum = sum + n n = n - 2 print(sum)
在循環內部變量n
不斷自減,直到變為-1
時,不再滿足while條件,循環退出。
輸入: 輸出:
break
在循環中,break
語句可以提前退出循環,程序結束。例如,打印出1~10后,緊接着打印END
,程序結束。
n = 1 while n <= 100: if n > 10: # 當n = 11時,條件滿足,執行break語句 break # break語句會結束當前循環 print(n) n = n + 1 print('END')
continue
在循環過程中,也可以通過continue
語句,跳過當前的這次循環,直接開始下一次循環。
如果我們想只打印 1-10之間的奇數,可以用continue
語句跳過某些循環:
n = 0 while n < 10: n = n + 1 if n % 2 == 0: # 如果n是偶數,執行continue語句 continue # continue語句會直接繼續下一輪循環,后續的print()語句不會執行 print(n)
執行上面的代碼可以看到,打印的不再是1~10,而是1,3,5,7,9。
可見continue
的作用是提前結束本輪循環,並直接開始下一輪循環。
小結
break
語句可以在循環過程中直接退出循環,而continue
語句可以提前結束本輪循環,並直接開始下一輪循環。這兩個語句通常都必須配合if
語句使用。
要特別注意,不要濫用break
和continue
語句。break
和continue
會造成代碼執行邏輯分叉過多,容易出錯。大多數循環並不需要用到break
和continue
語句,上面的兩個例子,都可以通過改寫循環條件或者修改循環邏輯,去掉break
和continue
語句。
有些時候,如果代碼寫得有問題,會讓程序陷入“死循環”,也就是永遠循環下去。這時可以用Ctrl+C
退出程序,或者強制結束Python進程。
dict,{}
Python內置了字典:dict的支持,dict全稱dictionary,在其他語言中也稱為map,使用鍵-值(key-value)存儲,具有極快的查找速度。
舉個例子,假設要根據同學的名字查找對應的成績,如果用dict實現,只需要一個“名字”-“成績”的對照表,直接根據名字查找成績,無論這個表有多大,查找速度都不會變慢。用Python寫一個dict如下:
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} >>> d['Michael'] 95
這種key-value存儲方式,在放進去的時候,必須根據key算出value的存放位置,這樣,取的時候才能根據key直接拿到value。
把數據放入dict的方法,除了初始化時指定外,還可以通過key放入:
>>> d['Adam'] = 67 >>> d['Adam'] 67
由於一個key只能對應一個value,所以,多次對一個key放入value,后面的值會把前面的值沖掉:
>>> d['Jack'] = 90 >>> d['Jack'] 90 >>> d['Jack'] = 88 >>> d['Jack'] 88
>>> d
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85,
'Adam':67,
'Jack':88
}
如果key不存在,dict就會報錯:
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module> KeyError: 'Thomas'
要避免key不存在的錯誤,有兩種辦法,一是通過in
判斷key是否存在:
>>> 'Thomas' in d False
二是通過dict提供的get()
方法,如果key不存在,可以返回None
,或者自己指定的value:
>>> d.get('Thomas') >>> d.get('Thomas', -1) -1
注意:返回None
的時候Python的交互環境不顯示結果。
要刪除一個key,用pop(key)
方法,對應的value也會從dict中刪除:
>>> d.pop('Bob') 75 >>> d {'Michael': 95, 'Tracy': 85}
請務必注意,dict內部存放的順序和key放入的順序是沒有關系的。
和list比較,dict有以下幾個特點:
- 查找和插入的速度極快,不會隨着key的增加而變慢;
- 需要占用大量的內存,內存浪費多。
而list相反:
- 查找和插入的時間隨着元素的增加而增加;
- 占用空間小,浪費內存很少。
所以,dict是用空間來換取時間的一種方法。
dict可以用在需要高速查找的很多地方,在Python代碼中幾乎無處不在,正確使用dict非常重要,需要牢記的第一條就是dict的key必須是不可變對象。
這是因為dict根據key來計算value的存儲位置,如果每次計算相同的key得出的結果不同,那dict內部就完全混亂了。這個通過key計算位置的算法稱為哈希算法(Hash)。
要保證hash的正確性,作為key的對象就不能變。
在Python中,字符串、整數等都是不可變的,因此,可以放心地作為key。而list是可變的,就不能作為key:
>>> key = [1, 2, 3]
>>> d[key] = 'a list'
Traceback (most recent call last):
File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list'
set
set和dict類似,也是一組key的集合,但不存儲value。由於key不能重復,所以,在set中,沒有重復的key。
要創建一個set,需要提供一個list作為輸入集合:
>>> s = set([1, 2, 3]) >>> s {1, 2, 3}
注意,傳入的參數[1, 2, 3]
是一個list,而顯示的{1, 2, 3}
只是告訴你這個set內部有1,2,3這3個元素,顯示的順序也不表示set是有序的。。
重復元素在set中自動被過濾:
>>> s = set([1, 1, 2, 2, 3, 3]) >>> s {1, 2, 3}
通過add(key)
方法可以添加元素到set中,可以重復添加,但不會有效果:
>>> s.add(4) >>> s {1, 2, 3, 4} >>> s.add(4) >>> s {1, 2, 3, 4}
通過remove(key)
方法可以刪除元素:
>>> s.remove(4) >>> s {1, 2, 3}
set可以看成數學意義上的無序和無重復元素的集合,因此,兩個set可以做數學意義上的交集、並集等操作:
>>> s1 = set([1, 2, 3]) >>> s2 = set([2, 3, 4]) >>> s1 & s2 {2, 3} >>> s1 | s2 {1, 2, 3, 4}
set和dict的唯一區別僅在於沒有存儲對應的value,但是,set的原理和dict一樣,所以,同樣不可以放入可變對象,因為無法判斷兩個可變對象是否相等,也就無法保證set內部“不會有重復元素”。試試把list放入set,看看是否會報錯。
再議不可變對象
上面我們講了,str是不變對象,而list是可變對象。
對於可變對象,比如list,對list進行操作,list內部的內容是會變化的,比如:
>>> a = ['c', 'b', 'a'] >>> a.sort() >>> a ['a', 'b', 'c']
而對於不可變對象,比如str,對str進行操作呢:
>>> a = 'abc' >>> a.replace('a', 'A') 'Abc' >>> a 'abc'
雖然字符串有個replace()
方法,也確實變出了'Abc'
,但變量a
最后仍是'abc'
,應該怎么理解呢?
我們先把代碼改成下面這樣:
>>> a = 'abc' >>> b = a.replace('a', 'A') >>> b 'Abc' >>> a 'abc'
要始終牢記的是,a
是變量,而'abc'
才是字符串對象!有些時候,我們經常說,對象a
的內容是'abc'
,但其實是指,a
本身是一個變量,它指向的對象的內容才是'abc'
:
┌───┐ ┌───────┐
│ a │─────────────────>│ 'abc' │
└───┘ └───────┘
當我們調用a.replace('a', 'A')
時,實際上調用方法replace
是作用在字符串對象'abc'
上的,而這個方法雖然名字叫replace
,但卻沒有改變字符串'abc'
的內容。相反,replace
方法創建了一個新字符串'Abc'
並返回,如果我們用變量b
指向該新字符串,就容易理解了,變量a
仍指向原有的字符串'abc'
,但變量b
卻指向新字符串'Abc'
了:
┌───┐ ┌───────┐
│ a │─────────────────>│ 'abc' │
└───┘ └───────┘
┌───┐ ┌───────┐
│ b │─────────────────>│ 'Abc' │
└───┘ └───────┘
所以,對於不變對象來說,調用對象自身的任意方法,也不會改變該對象自身的內容。相反,這些方法會創建新的對象並返回,這樣,就保證了不可變對象本身永遠是不可變的。
小結
使用key-value存儲結構的dict在Python中非常有用,選擇不可變對象作為key很重要,最常用的key是字符串。
tuple雖然是不變對象,但試試把(1, 2, 3)
和(1, [2, 3])
放入dict或set中,並解釋結果。