讀書筆記-Python科學程式設計入門(A Primer on Scientific Programming with Python)(第五版)-第二章
第二章-迴圈和列表(Loops and Lists)
介紹兩個迴圈語句:for 迴圈和 while 迴圈;介紹一種儲存資料的物件(object):列表
2.1-While迴圈
用於重複執行若干條語句
- 結構為:
while 迴圈條件: 需迴圈的語句1 需迴圈的語句2 其他語句
- while 迴圈開始的標誌:冒號(:)
- while 迴圈的迴圈體:相對 while 縮排一次的連續的若干行語句
- while 迴圈結束的標誌:迴圈體後第一條與 while 平齊的語句(如上面的其他語句)
- while 迴圈過程:當滿足迴圈條件時,執行迴圈體,直至迴圈條件不滿足
- 例子:
print '------------------' # 表格開頭 C = -20 # C的初始值 dC = 5 # 迴圈內C的增長值 while C <= 40: # 迴圈由一個迴圈條件開始 F = (9.0/5)*C + 32 # 第一條迴圈語句 print C, F # 第二條迴圈語句 C = C + dC # 第三條迴圈語句 print '------------------' # 表格結尾(在迴圈之後執行)
- 其結果為:
------------------ -20 -4.0 -15 5.0 -10 14.0 -5 23.0 0 32.0 5 41.0 10 50.0 15 59.0 20 68.0 25 77.0 30 86.0 35 95.0 40 104.0 ------------------
- 其目的:在 -20 到 40 間,以 5 為差值,將所有的攝氏溫度轉化為華氏溫度,並將其打印出來
- 其中:
其為賦值語句。C 原先所指的 int 物件,在該語句執行後,自動被銷燬;原因在於,該語句執行後,C 指向了新的物件(即等號右側兩式相加的和),導致原先的 int 物件沒有任何變數指向它。(Before this assignment, C was already bound to an int object, and this object is automatically destroyed when C is bound to a new object and there are no other names (variables) referring to this previous object (if you did not get this last point, just relax and continue reading!).)C = C + dC
- 對這種型別的賦值語句有以下簡寫形式:
C += dC # 等價於 C = C + dC C -= dC # 等價於 C = C - dC C *= dC # 等價於 C = C*dC C /= dC # 等價於 C = C/dC
- 對於迴圈條件而言,根據判斷結果,其結果為 True 或 False 中的一個
C == 40 # C 等於 40 C != 40 # C 不等於 40 C >= 40 # C 大於等於 40 C <= 40 # C 小於等於 40 C > 40 # C 大於 40 C < 40 # C 小於 40
類似的表示式稱為邏輯表示式或布林表示式(logical or boolean expressions)
- 在邏輯表示式前加 not,會使其值相反
C = 1 C == 40 # 結果為True not C == 40 # 結果為False
not C == 40 與 C != 40 等價,但更推薦後一種表達方式
- 邏輯表示式可由 and 或 or 相連,如:
while x > 0 and y <= 1: print x, y
其中,and 相連的邏輯表示式結果均為 True,結果才為 True;or 相連的邏輯表示式結果任意為 True,結果即為 True;其他情況均為 False
- 注意:
- 當 and 或 or 連線的是運算式時,返回的是其中的一個運算結果:
例如,(5 + 1) or -1 的值是 6; (5 + 1) and -1 的值是 -1
a 的結果 a and b a or b 0 / False 結果為 a 結果為 b 非0 / True 結果為 b 結果為 a - 對於各種物件而言,只要數字不為 0 或者字串(string)、列表(list)、字典(dictionary)等不為空,結果均為Ture。例如:
>>> s = 'some string' >>> bool(s) True >>> s = '' # 空字串 >>> bool(s) False
2.2-列表
2.2.1
列表:將資料按一定順序儲存起來
- 形如:
C = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
其中,-20、 -15 等資料稱為列表 C 的元素;列表的元素可以是任意物件;元素可以通過列表的索引(index)進行訪問,索引從 0 開始計數,例如,C[2] 的返回值為 -10
- 列表的一些重要操作:
結構(Construction) 含義(Meaning) a = [] 初始化一個空列表 a = [1, 4.4, 'run.py'] 初始化一個列表 a.append(elem) 在列表的末尾新增一個元素 elem a + [1, 3] 兩個列表相加 a.insert(i, e) 在當前索引為 i 的元素之前新增一個元素 e a[3] 索引為 3 的元素 a[-1] 倒數第 1 個元素 a[1:3] 切片(slice):從列表 a 索引為 1 的元素開始,到索引為 2 的所有元素,複製到一個子列表(sublist)中 del a[3] 刪除索引為 3 的元素 a.remove(e) 刪除值為 e 的元素 a.index('run.py') 找到值為 'run.py' 的元素的索引 'run.py' in a 檢查列表是否包含該元素 a.count(v) 檢視值為 v 的元素的總個數 len(a) 列表 a 包含的元素個數 min(a) 列表 a 中,值最小的元素 max(a) 列表 a 中,值最大的元素 sum(a) 將列表 a 中的所有元素相加 sorted(a) 返回順序排序的列表 reversed(a) 返回倒序排序的列表 b[3][0][2] 返回巢狀列表的元素 isinstance(a, list) 如果 a 是列表,那麼返回 True type(a) is list 如果 a 是列表,那麼返回 True 其中,巢狀列表是元素為列表的列表;形如 len(a) 的表示式稱為函式(function);在形如 a.append(elem) 的表示式中,稱 append 是列表 a 的一個方法(method)
- 訪問列表元素有兩種方法:一種是通過索引來訪問,例如 C[2];另一種訪問方式依賴於列表的元素,例如:
>>> somelist = ['book.tex', 'book.log', 'book.pdf'] >>> texfile, logfile, pdf = somelist >>> texfile 'book.tex' >>> logfile 'book.log' >>> pdf 'book.pdf'
其中,第 2 行賦值語句左側變數的個數要和列表的元素個數相同,否則會報錯
2.2.2
for迴圈:遍歷列表中的每個元素,每讀取一個元素,進入一次迴圈體
- 結構為:
for 元素 in 列表: 迴圈體
- for 迴圈開始的標誌、for 迴圈的迴圈體、for 迴圈結束的標誌的表示與 while 迴圈一致
- for 迴圈過程:依次讀取列表中的每個元素,每讀取一個元素,進入一次迴圈體,直到所有元素被遍歷完畢
- 例子:
degrees = [0, 10, 20, 40, 100] for C in degrees: print 'list element:', C print 'The degrees list has', len(degrees), 'elements'
- 其結果為:
list element: 0 list element: 10 list element: 20 list element: 40 list element: 100 The degrees list has 5 elements
- 其目的:依次讀取列表 degrees 的元素,並將其打印出來;最後輸出列表 degrees 的元素個數
2.3-列表和迴圈的選擇性使用(Alternative Implementations with Lists and Loops)
2.3.1
for 迴圈和 while 迴圈可相互轉化
- 兩種等價的表達方式:
# 用 for 迴圈表示 for element in somelist: <process element> # 用 while 迴圈表示 index = 0 while index < len(somelist): element = somelist[index] <process element> index += 1
2.3.2
range 結構:按一定規則自動生成列表
- range(n) 生成列表 [0, 1, 2, ..., n-1]
- range(start, stop, step) 生成以 start 開頭、前後元素相差 step 、元素值在 start 與 stop 間但不包括 stop 的列表。例如,range(2, 8, 3) 返回 [2, 5],range(1, 11, 2) 返回 [1, 3, 5, 7, 9]
- range(start, stop) 等價於 range(start, stop, 1)
2.3.3
for 迴圈遍歷列表時的兩種等價表達方式
- 兩種等價的表達方式
# 直接訪問 for element in somelist: ... # 通過索引訪問 for i in range(len(somelist)): element = somelist[i] ...
推薦第一種表達方法,更為簡練(which is more elegant to read)
- 生成列表時,還可以用 [i]*n 生成包含 n 個值為 i 的元素的列表;如 [0]*5 返回 [0, 0, 0, 0, 0]
2.3.4
修改列表元素時的注意事項
- 試圖將每個元素均加上 5,可能會出現以下兩種方法:
# 方法一 for c in Cdegrees: c += 5 # 方法二 for i in range(len(Cdegrees)): Cdegrees[i] += 5
方法一修改失敗,而方法二修改成功。
- 方法一失敗的原因:在方法一中,c += 5 操作結果,使 c 指向了新的浮點數物件 (c + 5),即只修改了 c 的值,但是對列表沒有影響
- 方法二成功的原因:在方法二中,通過索引的直接訪問,能直接修改列表的元素
- 可呼叫enumerate函式,同時訪問索引和元素:
for i, c in enumerate(Cdegrees): Cdegrees[i] = c + 5
功能一致
2.3.5
列表推導(list comprehension):通過遍歷已有的列表,匯出新的列表
- 結構:
newlist = [E(e) for e in list]
其中,E(e) 表示包含元素 e 的表示式
2.3.6
同時遍歷多個列表:兩種方法
# 方法一 for i in range(len(Cdegrees)): print ’%5d %5.1f’ % (Cdegrees[i], Fdegrees[i]) # 方法二 for C, F in zip(Cdegrees, Fdegrees): print ’%5d %5.1f’ % (C, F)
推薦方法二;其中,zip 函式使 n 個列表 (list1, list2, list3, ...) 變為一個以 n 元組(n-tuples)為元素的列表,每個 n 元組 (e1, e2, e3, ...) 中的 e1、e2、e3、... 表示 list1、list2、list3、... 對應的元素,當列表的所有元組均被訪問過後,for 迴圈停止
2.4-巢狀表(Nested Lists)
以列表為元素的列表
2.4.1
生成巢狀表
- 生成巢狀表的幾種方法:
# 方法一 Cdegrees = range(-20, 41, 5) # -20, -15, ..., 35, 40 Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] table1 = [Cdegrees, Fdegrees] # 方法二 table2 = [] for C, F in zip(Cdegrees, Fdegrees): table2.append([C, F]) # 方法二的簡寫(利用列表推導) table2 = [[C, F] for C, F in zip(Cdegrees, Fdegrees)]
- 兩種方法生成的巢狀表的結構分別如圖所示:
- 巢狀表可通過索引直接訪問:例如,table1[0][3] 返回 35
2.4.2
列印巢狀表
- 列印巢狀表的幾種方法:
方法 特點 print table 輸出很長的一行結果
import pprint
pprint.pprint(table)
結果過長的話,自動按元素換行 import scitools.pprint2
scitools.pprint2.pprint(table)
可通過 scitools.pprint2.float_format 控制輸出格式,如通過 scitools.pprint2.float_format = ’%.2e’,使輸出結果均以保留兩位小數的科學計數法表示;預設的輸出格式為 '%g'
存在舍入誤差(round-off error)
for C, F in table:
print ’%5d %5.1f’ % (C, F)可自由地控制輸出格式
2.4.3
提取原有列表的一部分,形成新列表;該部分稱為子列表(sublist)或片段(slice)
- 提取子列表的幾種方法:
結構 含義 A[i:] 提取 A 中 A[i] 之後(包括 A[i])的所有元素 A[:j] 提取 A 中 A[j] 之前(不包括 A[j])的所有元素 A[i:j] 提取 A 中 A[i] 之後(包括 A[i])、A[j] 之前(不包括 A[j])的所有元素 - 子列表是原列表的一個拷貝(copy),對原列表的任意操作,均不影響已經生成了的子列表
2.4.4
遍歷巢狀表
- 當巢狀表內,每個列表元素的元素個數均相等時,可用以下方法遍歷:
for C, F in table: # 遍歷 C 和 F
若個數不同,則遍歷次數由包含元素個數最少的列表元素決定
- 通過索引遍歷
for p in range(len(scores)): for g in range(len(scores[p])): score = scores[p][g] print ’%4d’ % score, print
不大好,較難理解
- 通過元素遍歷
for player in scores: for game in player: print ’%4d’ % game, print
很好,形象直觀
2.5-元組(Tuples)
可看做是一種不可修改的列表
- 除了會修改元素的操作(比如:append,del,remove,index 和 sort)之外,列表的其他操作均適用於元組
- 與列表相比,元組的優勢:
- 可保護元素不被篡改
- 基於元組的程式碼,比基於列表的程式碼更快
- 元組在 Python 軟體中常被使用
- 元組可作為字典(dictionaries)的鍵值(keys),而列表不能 (詳見第 6 章)
2.6-小結(Summary)
本章所學術語
- 列表(list)
- 元組(tuple)
- 巢狀列表(和巢狀元組)(nested list (and nested tuple))
- 子列表(子元組)(sublist (subtuple) or slice a[i:j])
- while 迴圈(while loop)
- for 迴圈(for loop)
- 列表推導(list comprehension)
- 布林表示式(boolean expression)