一、簡介
Python的條件和循環語句,決定了程序的控制流程,體現結構的多樣性。須重要理解,if、while、for以及與它們相搭配的 else、 elif、break、continue和pass語句。
二、詳解
1、if語句
Python中的if子句由三部分組成:關鍵字本身、用於判斷結果真假的條件表達式以及當表達式為真或者非零時執行的代碼塊。if 語句的語法如下:
|
1
2
|
if
expression:
expr_true_suite
|
if 語句的expr_true_suite代碼塊只有在條件表達式的結果的布爾值為真時才執行,否則將繼續執行緊跟在該代碼塊后面的語句。
(1)多重條件表達式
單個if語句可以通過使用布爾操作符and、or和not,實現多重判斷條件或是否定判斷條件。
(2)單一語句的代碼塊
如果一個復合語句(例如if子句、while或for循環)的代碼塊僅僅包含一行代碼,那么它可以和前面的語句寫在同一行上。如if make_hard_copy: send_data_to_printer(),這樣的單行語句是合法的, 盡管它可能方便,但這樣會使得代碼更難閱讀, 所以推薦將這行代碼移到下一行並合理地縮進。另外一個原因就是如果你需要添加新的代碼, 你還是得把它移到下一行。
2、else語句
Python提供了與if語句搭配使用的else語句,如果if語句的條件表達式的結果布爾值為假,那么程序將執行 else 語句后的代碼。其語法如下:
|
1
2
3
4
|
if
expression:
expr_true_suite
else
:
expr_false_suite
|
在C語言中,不會在條件語句范圍外發現else語句, 但Python不同,可以在while和for循環中使用else語句,在循環中使用時,else子句只在循環完成后執行,也就是說break語句也會跳過else塊。
例:顯示出10到20中的數字的最大約數
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/usr/bin/env python
def
showMaxFactor(num):
count
=
num
/
2
while
count >
1
:
if
(num
%
count
=
=
0
):
print
'largest factor of %d is %d'
%
(num, count)
break
count
=
count
-
1
else
:
print
eachNum,
'is prime'
for
eachNum
in
range
(
10
,
21
):
showMaxFactor(eachNum)
|
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
|
largest factor of
10
is
5
11
is
prime
largest factor of
12
is
6
13
is
prime
largest factor of
14
is
7
largest factor of
15
is
5
largest factor of
16
is
8
17
is
prime
largest factor of
18
is
9
19
is
prime
largest factor of
20
is
10
|
3、elif (即else-if )語句
elif是Python的else-if 語句,它檢查多個表達式是否為真,並在為真時執行特定代碼塊中的代碼。和else一樣,elif 聲明是可選的,然而不同的是if 語句后最多只能有一個else語句,但可以有任意數量的 elif 語句。
|
1
2
3
4
5
6
7
8
9
|
if
expression1:
expr1_true_suite
elif
expression2:
expr2_true_suite
...
elif
expressionN:
exprN_true_suite
else
:
none_of_the_above_suite
|
在將來的某天,Python可能會支持 switch /case語句,但是完全可以用其他的Python結構來模擬它。在Python中,大量的if-elif 語句並不難閱讀。
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
|
if
user.cmd
=
=
'create'
:
action
=
"create item"
elif
user.cmd
=
=
'delete'
:
action
=
'delete item'
elif
user.cmd
=
=
'update'
:
action
=
'update item'
else
:
action
=
'invalid choice... try again!'
|
上面的語句還可以用序列和成員關系操作符來簡化它:
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
|
if
user.cmd
in
(
'create'
,
'delete'
,
'update'
):
action
=
'%s item'
%
user.cmd
else
:
action
=
'invalid choice... try again!'
|
還可以用Python字典給出更加優雅的解決方案,使用映射對象(比如字典)的一個最大好處就是它的搜索操作比類似語句或是 for 循環這樣的序列查詢要快很多。
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
|
msgs
=
{
'create'
:
'create item'
,
'delete'
:
'delete item'
,
'update'
:
'update item'
}
default
=
'invalid choice... try again!'
action
=
msgs.get(user.cmd, default)
|
4、條件表達式(即"三元操作符")
三元運算符語法為:X if C else Y,只需要一行完成條件判斷和賦值操作:
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
|
>>> x, y
=
4
,
3
>>> smaller
=
x
if
x < y
else
y
>>> smaller
3
|
5、while語句
while是一個條件循環語句,與if聲明相比,如果 if 后的條件為真,就會執行一次相應的代碼塊。而while中的代碼塊會一直循環執行,直到循環條件不再為真。
(1)一般語法
while循環的語法如下:
|
1
2
|
while
expression:
suite_to_repeat
|
while循環的suite_to_repeat子句會一直循環執行,直到expression值為布爾假。
(2)計數循環
|
1
2
3
4
|
count
=
0
while
(count <
9
):
print
'the index is:'
, count
count
+
=
1
|
代碼塊里包含了print和自增語句,它們被重復執行,直到count不再小於9。索引count在每次迭代時被打印出來然后自增 1。
(3)無限循環
|
1
2
3
4
|
while
True
:
handle, indata
=
wait_for_client_connect()
outdata
=
process_request(indata)
ack_result_to_client(handle, outdata)
|
“無限”循環永遠不會結束,但它不一定是壞事,許多通訊服務器的客戶端/服務器系統就是通過它來工作的。
6、for語句
Python提供了的另一個循環機制就是for語句,它是Python中最強大的循環結構。它可以遍歷序列成員,可以用在列表解析和生成器表達式中,它會自動地調用迭代器的next()方法,捕獲StopIteration異常並結束循環(所有這一切都是在內部發生的)。 Python的for更像是shell或是腳本語言中的foreach循環。
(1)一般語法
for循環會訪問一個可迭代對象(例如序列或是迭代器)中的所有元素,,並在所有條目都處理過后結束循環。它的語法如下:
for iter_var in iterable:
suite_to_repeat
每次循環, iter_var迭代變量被設置為可迭代對象(序列、迭代器或者是其他支持迭代的對象)的當前元素,提供給suite_to_repeat 語句塊使用。
(2)用於序列類型
for循環可以迭代不同的序列對象,像字符串、 列表、以及元組。
迭代序列有三種基本方法:
通過序列項迭代
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
|
>>> nameList
=
[
'Walter'
,
"Nicole"
,
'Steven'
,
'Henry'
]
>>>
for
eachName
in
nameList:
...
print
eachName,
"Lim"
...
Walter Lim
Nicole Lim
Steven Lim
Henry Lim
|
迭代一個列表.。每次迭代,eacgName變量都被設置為列表中特定某個元素。
通過序列索引迭代
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
|
>>> nameList
=
[
'Cathy'
,
"Terry"
,
'Joe'
,
'Heather'
,
'Lucy'
]
>>>
for
nameIndex
in
range
(
len
(nameList)):
...
print
"Liu,"
, nameList[nameIndex]
...
Liu, Cathy
Liu, Terry
Liu, Joe
Liu, Heather
Liu, Lucy
|
沒有迭代元素, 而是通過列表的索引迭代。但通過直接迭代序列要比索引迭代快。
使用項和索引迭代
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
|
>>> nameList
=
[
'Donn'
,
'Shirley'
,
'Ben'
,
'Janice'
,
'David'
,
'Yen'
,
'Wendy'
]
>>>
for
i, eachLee
in
enumerate
(nameList):
...
print
"%d %s Lee"
%
(i
+
1
, eachLee)
...
1
Donn Lee
2
Shirley Lee
3
Ben Lee
4
Janice Lee
5
David Lee
6
Yen Lee
7
Wendy Lee
|
(3)用於迭代器類型
用for循環訪問迭代器和訪問序列的方法差不多,迭代器並不代表循環條目的集合,迭代器對象有一個next()方法, 調用后返回下一個條目。 所有條目迭代完后, 迭代器引發一個StopIteration異常告訴程序循環結束,for語句在內部調用next()並捕獲異常。
使用迭代器做 for 循環的代碼與使用序列條目幾乎完全相同。事實上在大多情況下,無法分辨出迭代的是一個序列還是迭代器,因此遍歷一個迭代器時,實際上可能指的是要遍歷一個序列、迭代器或是一個支持迭代的對象(它有 next()方法)。
(4)range()內建函數
內建函數range()可以把類似foreach的for循環變成你更加熟悉的語句。
Python提供了兩種不同的方法來調用range() ,完整語法要求提供兩個或三個整數參數:range(start, end, step =1),range()會返回一個包含所有k的列表,其中start <= k < end,從start到end ,k每次遞增 ste,step不可以為零,否則將發生錯誤。
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
|
>>>
range
(
3
,
7
)
[
3
,
4
,
5
,
6
]
>>>
for
eachVal
in
range
(
2
,
19
,
3
):
...
print
"value is:"
, eachVal
...
value
is
:
2
value
is
:
5
value
is
:
8
value
is
:
11
value
is
:
14
value
is
:
17
|
range() 還有兩種簡略的語法格式:range(end)和range(start, end)。 start 默認為0, step默認為1。
(5)xrange()內建函數
xrange()類似range(),不過當有一個很大的范圍列表時,xrange() 可能更為適合, 因為它不會在內存里創建列表的完整拷貝。 它只被用在 for 循環中,在 for 循環外使用它沒有意義。它的性能遠高出 range(),因為它不生成整個列表。在Python的將來版本中,range()可能會像xrange()一樣,返回一個可迭代對象(不是列表也不是一個迭代器)。
(6)與序列相關的內建函數
序列相關函數:sorted()、 reversed()、enumerate()和zip(),稱為“序列相關”是因為其中兩個函數(sorted() 和 zip())返回一個序列(列表),而另外兩個函數(reversed() 和 enumerate())返回迭代器(類似序列)。
7、break和continue語句
Python中的break語句可以結束當前循環然后跳轉到下條語句,類似C中的break。常用在當某個外部條件被觸發(一般通過 if 語句檢查),需要立即從循環中退出時.。break 語句可以用在 while 和 for 循環中。
Python里的continue語句和其他高級語言中的傳統continue並沒有什么不同,它可以被用在while和for循環里。 while循環是條件
性的,而 for 循環是迭代的,所以continue在開始下一次循環前要滿足一些先決條件,否則循環會正常結束。
程序中當遇到 continue 語句時, 程序會終止當前循環,並忽略剩余的語句,然后回到循環的頂端。在開始下一次迭代前,如果是條件循環,我們將驗證條件表達式。如果是迭代循環,將驗證是否還有元素可以迭代。只有在驗證成功的情況下,才會開始下一次迭代。
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/usr/bin/env python
valid
=
False
count
=
3
passwdList
=
(
'abc'
,)
while
count >
0
and
valid
=
=
False
:
input
=
raw_input
(
"enter password:"
).strip()
# check for valid passwd
for
eachPasswd
in
passwdList:
if
input
=
=
eachPasswd:
valid
=
True
break
if
not
valid:
# (or valid == 0)
print
"invalid input"
count
-
=
1
continue
else
:
break
|
結合使用了while、for、if、break以及continue,來驗證用戶輸入。用戶有三次機會來輸入正確的密碼,阻止用戶猜測密碼。
8、pass語句
Python中沒有對應的空大括號或是分號( ; )來表示如C語言中的“不做任何事”,如果需要子語句塊的地方不寫任何語句, 解釋器會提示語法錯誤。因此,Python 提供了pass語句,它不做任何事情,即NOP(No OPeration),pass同樣也可作為開發中的小技巧,標記以后將要完成的代碼。
def foo_func():
pass
這樣的代碼結構在開發和調試時很有用,因為編寫代碼的時候可能要先把結構定下來,但又不希望它干擾其他已經完成的代碼, 在不需要它做任何事情地方放一個pass,將是一個很好的主意。另外它在異常處理中也被經常用到,比如你跟蹤到了一個非致命的錯誤而不想采取任何措施。
9、迭代器和iter()函數
(1)什么是迭代器
迭代器為類序列對象提供了一個類序列的接口,可以利用它們的索引從0開始一直"迭代" 到序列的最后一個條目,用"計數"的方法迭代序列是很簡單的。 Python的迭代無縫地支持序列對象,而且它還允許程序員迭代非序列類型, 包括用戶定義的對象。
迭代器用起來很靈巧,可以迭代不是序列但表現出序列行為的對象,例如字典的 key 、一個文件的行等等。當使用循環迭代一個對象條目時,不必去關注它是迭代器還是序列。
(2)為什么要迭代器
迭代器的定義:提供了可擴展的迭代器接口、對列表迭代帶來了性能上的增強、在字典迭代中性能提升、創建真正的迭代接口,而不是原來的隨機對象訪問、與所有已經存在的用戶定義的類以及擴展的模擬序列和映射的對象向后兼容、迭代非序列集合(例如映射和文件)時, 可以創建更簡潔可讀的代碼。
(3)如何迭代
迭代器有一個next()方法的對象,而不是通過索引來計數。當一個循環機制(例如 for 語句)需要下一個項時,調用迭代器的next()方法就可以獲得它。條目全部取出后,會引發一個StopIteration異常,這並不表示錯誤發生,只是告訴外部調用者迭代完成。
不過,迭代器也有一些限制。 例如不能向后移動,不能回到開始,也不能復制一個迭代器。如果要再次(或者是同時)迭代同個對象,你只能去創建另一個迭代器對象。不過,還有其他的工具來幫助你使用迭代器。
reversed()內建函數將返回一個反序訪問的迭代器。enumerate()內建函數同樣也返回迭代器。另外兩個新的內建函數:any()和 all(),如果迭代器中某個/所有條目的值都為布爾真時,則它們返回值為真。
(4)使用迭代器
序列
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> myTuple
=
(
123
,
'xyz'
,
45.67
)
>>> i
=
iter
(myTuple)
>>> i.
next
()
123
>>> i.
next
()
'xyz'
>>> i.
next
()
45.670000000000002
>>> i.
next
()
Traceback (most recent call last):
File
"<stdin>"
, line
1
,
in
<module>
StopIteration
|
在for循環中for i in seq:do_something_to(i),它會自動調用迭代器的next()方法,並且監視StopIteration異常。
字典
字典和文件是另外兩個可迭代的Python數據類型。字典的迭代器會遍歷它的鍵(keys),語句for eachKey in myDict.keys()可以縮寫為for eachKey in myDict。
Python還引進了三個新的內建字典方法來定義迭代: myDict.iterkeys() (通過 keys 迭代), myDict.itervalues() (通過 values 迭代)以及myDicit.iteritems() (通過key/value 對來迭代 )。 注意 : in操作符也可以用於檢查字典的key是否存在,布爾表達式myDict.has_key(anyKey)可以被簡寫為anyKey in myDict。
文件
文件對象生成的迭代器會自動調用readline()方法。這樣,循環就可以訪問文本文件的所有行。可以使用更簡單的for eachLine in myFile替 換for eachLine in myFile.readlines()。
(5)可變對象和迭代器
在迭代可變對象的時候修改它們並不是個好主意,這在迭代器出現之前就是一個問題。一個序列的迭代器只是記錄當前到達第幾個元素,所以若在迭代時改變了元素,更新會立即反映到你所迭代的條目上。在迭代字典的key時,絕對不能改變這個字典。 使用字典的keys()方法是可以的,因為keys() 返回一個獨立於字典的列表, 而迭代器是與實際對象綁定在一起的,它將不會繼續執行下去。
(6)如何創建迭代器
對一個對象調用iter()就可以得到它的迭代器,它的語法如下:iter(obj)或iter(func, sentinel )。如果傳遞一個參數給iter(),它會檢查你傳遞的是不是一個序列,如果是則會根據索引從0一直迭代到序列結束。另一個創建迭代器的方法是使用類,一個實現__iter__()和next()方法的類可以作為迭代器使用。如果是傳遞兩個參數給iter(), 它會重復地調用func,直到迭代器的下個值等於sentinel。
10、列表解析
列表解析( List comprehensions或縮略為list comps ) 來自函數式編程語言Haskell。它是一個非常有用、簡單、而且靈活的工具, 可以用來動態地創建列表。
Python支持的函數式編程特性,例如lambda 、map() 以及filter()等,通過列表解析它們可以被簡化為一個列表解析式子。map()對所有的列表成員應用一個操作,filter()基於一個條件表達式過濾列表成員,lambda()允許快速地創建只有一行的函數對象。
列表解析的語法:[expr for iter_var in iterable], 它迭代iterable對象的所有條目。其中的expr應用於序列的每個成員,最后的結果值是該表達式產生的列表,迭代變量並不需要是表達式的一部分。
在CODE上查看代碼片派生到我的代碼片
|
1
2
|
>>> [x
*
*
2
for
x
in
range
(
6
)]
[
0
,
1
,
4
,
9
,
16
,
25
]
|
列表解析的表達式可以取代內建的map()函數以及lambda ,而且效率更高。結合 if語句,列表解析還提供了一個擴展版本的語法:[expr for iter_var in iterable if cond_expr],它在迭代時會過濾/捕獲滿足條件表達式cond_expr的序列成員。
挑選出序列中的奇數:
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
|
>>> seq
=
[
11
,
10
,
9
,
9
,
10
,
10
,
9
,
8
,
23
,
9
,
7
,
18
,
12
,
11
,
12
]
>>>
filter
(
lambda
x: x
%
2
, seq)
[
11
,
9
,
9
,
9
,
23
,
9
,
7
,
11
]
>>> [x
for
x
in
seq
if
x
%
2
]
[
11
,
9
,
9
,
9
,
23
,
9
,
7
,
11
]
|
即使不用filter()和lambda,可以使用列表解析來完成操作,獲得想要的數字。
矩陣樣例:迭代一個有三行五列的矩陣,[(x+1,y+1) for x in range(3) for y in range(5)]。
磁盤文件樣例:若有一個數據文件text.txt,需要計算出所有非空白字符的數目,可以把每行分割( split )為單詞,,然后計算單詞個數:>>> f = open('hhga.txt', 'r');len([word for line in f for word in line.split()])。快速地計算文件大小:>>>import os;os.stat('text.txt').st_size。把每個單詞的長度加起來:>>>f.seek(0);sum([len(word) for line in f for word in line.split()])。
11、生成器表達式
生成器表達式是列表解析的一個擴展,只用一行代碼就可以創建包含特定內容的列表。另一個重要特性是生成器,生成器是特定的函數,允許返回一個值,然后"暫停"代碼的執行,稍后恢復。
列表解析的一個不足就是必要生成所有的數據,用以創建整個列表。這可能對有大量數據的迭代器有負面效應, 生成器表達式通過結合列表解析和生成器解決了這個問題。
生成器表達式與列表解析非常相似,而且它們的基本語法基本相同。不過它並不真正創建數字列表而是返回一個生成器,這個生成器在每次計算出一個條目后,把這個條目“產生”(yield)出來。生成器表達式使用了"延遲計算"(lazy evaluation),所以它在使用內存上更有效。生成器並不會讓列表解析廢棄,它只是一個內存使用更友好的結構,基於此,有很多使用生成器地方。
列表解析語法:
|
1
|
[expr
for
iter_var
in
iterable
if
cond_expr]
|
生成器表達式語法:
|
1
|
(expr
for
iter_var
in
iterable
if
cond_expr)
|
磁盤文件樣例:上述計算文本文件中非空白字符總和,如果這個文件的大小變得很大, 那么這行代碼的內存性能會很低,因為要創建一個很長的列表用於存放單詞的長度。為了避免創建龐大的列表,使用生成器表達式來完成求和操作,優化后的代碼:>>> sum(len(word) for line in data for word in line.split()),是把方括號刪除,少了兩字節, 而且更節省內存。
交叉配對例子:成器表達式就好像是懶惰的列表解析(這反而成了它主要的優勢),它還可以用來處理其他列表或生成器,如:x_product_pairs = ((i, j) for i in rows for j in cols())。
重構樣例,尋找文件最長的行的例子:
以前的方法:
在CODE上查看代碼片派生到我的代碼片
|
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/usr/bin/env python
def
fun():
f
=
open
(
'/etc/motd'
,
'r'
)
longest
=
0
allLines
=
[x.strip()
for
x
in
f.readlines()]
#or allLineLens = [len(x.strip()) for x in f]
f.close()
for
line
in
allLines:
linelen
=
len
(line)
if
linelen > longest:
#or longest = max(allLineLens)
longest
=
linelen
return
longest
|
新的方法:
使用生成器表達式替換列表解析和max()函數,並去掉文件打開模式(默認為讀取):return max(len(x.strip()) for x in open('/etc/motd'))。
三、總結
(1)itertools模塊被加入,更加支持了迭代器的應用,列表解析和生成表達式的內容可結合實例分析。
(2)若有不足,請留言,在此先感謝!
借鑒網址:http://www.jb51.net/article/63790.htm
