申明: 本站飛宇網 https://feiyetopro.blogspot.com/。自網路收集整理之書籍、文章、影音僅供預覽交流學習研究,其[書籍、文章、影音]情節內容, 評論屬其個人行為, 與本網站無關。版權歸原作者和出版社所有,請在下載 24 小時內刪除,不得用作商業用途;如果您喜歡其作品,請支持訂閱購買[正版]。謝謝!
第 4 章 操作列表
在第3章,你學習了如何創建簡單的列表,還學習了如何操作清單元素。在本章中,你將學習如何遍歷 整個列表,這只需要幾行代碼,無論列表有多長。迴圈讓你能夠對清單的每個元素都採取一個或一系列相同的措施,從而高效地處理任何長度的列表,包括包含數千乃至數百萬個元素的清單。
4.1 遍歷整個列表
你經常需要遍歷清單的所有元素,對每個元素執行相同的操作。例如,在遊戲中,可能需要將每個介面元素平移相同的距離;對於包含數位的清單,可能需要對每個元素執行相同的統計運算;在網站中,可能需要顯示文章清單中的每個標題。需要對清單中的每個元素都執行相同的操作時,可使用Python中的for 迴圈。
假設我們有一個魔術師名單,需要將其中每個魔術師的名字都列印出來。為此,我們可以分別獲取名單中的每個名字,但這種做法會導致多個問題。例如,如果名單很長,將包含大量重複的代碼。另外,每當名單的長度發生變化時,都必須修改代碼。通過使用for 迴圈,可讓Python去處理這些問題。
下面使用for 迴圈來列印魔術師名單中的所有名字:
magicians.py
❶ magicians
= ['alice', 'david', 'carolina']
❷ for magician
in magicians:
❸ print(magician)
首先,我們像第3章那樣定義了一個列表(見❶)。接下來,我們定義了一個for 迴圈(見❷);這行代碼讓Python從列表magicians 中取出一個名字,並將其存儲在變數magician 中。最後,我們讓Python列印前面存儲到變數magician 中的名字(見❸)。這樣,對於列表中的每個名字,Python都將重複執行❷處和❸處的代碼行。你可以這樣解讀這些代碼:對於列表magicians 中的每位魔術師,都將其名字列印出來。輸出很簡單,就是列表中所有的姓名:
alice
david
carolina
4.1.1 深入地研究迴圈
迴圈這種概念很重要,因為它是讓電腦自動完成重複工作的常見方式之一。例如,在前面的magicians.py中使用的簡單迴圈中,Python將首先讀取其中的第一行代碼:
for
magician in magicians:
這行代碼讓Python獲取列表magicians 中的第一個值('alice' ),並將其存儲到變數magician 中。接下來,Python讀取下一行代碼:
print(magician)
它讓Python列印magician 的值——依然是'alice' 。鑒於該列表還包含其他值,Python返回到迴圈的第一行:
for
magician in magicians:
Python獲取列表中的下一個名字——'david' ,並將其存儲到變數magician 中,再執行下面這行代碼:
print(magician)
Python再次列印變數magician 的值——當前為'david' 。接下來,Python再次執行整個迴圈,對列表中的最後一個值——'carolina' 進行處理。至此,列表中沒有其他的值了,因此Python接著執行程式的下一行代碼。在這個示例中,for 迴圈後面沒有其他的代碼,因此程式就此結束。
剛開始使用迴圈時請牢記,對清單中的每個元素,都將執行迴圈指定的步驟,而不管清單包含多少個元素。如果清單包含一百萬個元素,Python就重複執行指定的步驟一百萬次,且通常速度非常快。
另外,編寫for 迴圈時,對於用於存儲清單中每個值的臨時變數,可指定任何名稱。然而,選擇描述單個清單元素的有意義的名稱大有幫助。例如,對於小貓列表、小狗列表和一般性列表,像下面這樣編寫for 迴圈的第一行代碼是不錯的選擇:
for
cat in cats:
for
dog in dogs:
for
item in list_of_items:
這些命名約定有助於你明白for 迴圈中將對每個元素執行的操作。使用單數和複數式名稱,可幫助你判斷程式碼片段處理的是單個清單元素還是整個清單。
4.1.2 在for 迴圈中執行更多的操作
在for 迴圈中,可對每個元素執行任何操作。下面來擴展前面的示例,對於每位魔術師,都列印一條消息,指出他的表演太精彩了。
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
❶ print(magician.title() + ", that was
a great trick!")
相比於前一個示例,唯一的不同是對於每位魔術師,都列印了一條以其名字為抬頭的消息(見❶)。這個迴圈第一次反覆運算時,變數magician 的值為'alice' ,因此Python列印的第一條消息的抬頭為'Alice' 。第二次反覆運算時,消息的抬頭為'David' ,而第三次反覆運算時,抬頭為'Carolina' 。
下面的輸出表明,對於列表中的每位魔術師,都列印了一條個性化消息:
Alice,
that was a great trick!
David,
that was a great trick!
Carolina,
that was a great trick!
在for 迴圈中,想包含多少行代碼都可以。在代碼行for magician in magicians 後面,每個縮進的代碼行都是迴圈的一部分,且將針對列表中的每個值都執行一次。因此,可對列表中的每個值執行任意次數的操作。
下面再添加一行代碼,告訴每位魔術師,我們期待他的下一次表演:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was
a great trick!")
❶ print("I can't wait to see your next
trick, " + magician.title() + ".\n")
由於兩條print 語句都縮進了,因此它們都將針對列表中的每位魔術師執行一次。第二條print 語句中的分行符號"\n" (見❶)在每次反覆運算結束後都插入一個空行,從而整潔地將針對各位魔術師的消息編組:
Alice,
that was a great trick!
I
can't wait to see your next trick, Alice.
David,
that was a great trick!
I
can't wait to see your next trick, David.
Carolina,
that was a great trick!
I
can't wait to see your next trick, Carolina.
在for 迴圈中,想包含多少行代碼都可以。實際上,你會發現使用for 迴圈對每個元素執行眾多不同的操作很有用。
4.1.3 在for 迴圈結束後執行一些操作
for 迴圈結束後再怎麼做呢?通常,你需要提供總結性輸出或接著執行程式必須完成的其他任務。
在for 迴圈後面,沒有縮進的代碼都只執行一次,而不會重複執行。下面來列印一條向全體魔術師致謝的消息,感謝他們的精彩表演。想要在列印給各位魔術師的消息後面列印一條給全體魔術師的致謝消息,需要將相應的代碼放在for 迴圈後面,且不縮進:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was
a great trick!")
print("I can't wait to see your next
trick, " + magician.title() + ".\n")
❶
print("Thank you, everyone. That was a great magic show!")
你在前面看到了,開頭兩條print 語句針對列表中每位魔術師重複執行。然而,由於第三條print 語句沒有縮進,因此只執行一次:
Alice,
that was a great trick!
I
can't wait to see your next trick, Alice.
David,
that was a great trick!
I
can't wait to see your next trick, David.
Carolina,
that was a great trick!
I
can't wait to see your next trick, Carolina.
Thank
you, everyone. That was a great magic show!
使用for 迴圈處理資料是一種對資料集執行整體操作的不錯的方式。例如,你可能使用for 迴圈來初始化遊戲——遍歷角色列表,將每個角色都顯示到螢幕上;再在迴圈後面添加一個不縮進的代碼塊,在螢幕上繪製所有角色後顯示一個Play Now按鈕。
4.2 避免縮進錯誤
Python根據縮進來判斷代碼行與前一個代碼行的關係。在前面的示例中,向各位魔術師顯示消息的代碼行是for 迴圈的一部分,因為它們縮進了。Python通過使用縮進讓代碼更易讀;簡單地說,它要求你使用縮進讓代碼整潔而結構清晰。在較長的Python程式中,你將看到縮進程度各不相同的代碼塊,這讓你對程式的組織結構有大致的認識。
當你開始編寫必須正確縮進的代碼時,需要注意一些常見的縮進錯誤 。例如,有時候,程式師會將不需要縮進的代碼塊縮進,而對於必須縮進的代碼塊卻忘了縮進。通過查看這樣的錯誤示例,有助於你以後避開它們,以及在它們出現在程式中時進行修復。
下面來看一些較為常見的縮進錯誤。
4.2.1 忘記縮進
對於位於for 語句後面且屬於迴圈組成部分的代碼行,一定要縮進。如果你忘記縮進,Python會提醒你:
magicians.py
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
❶
print(magician)
print 語句(見❶)應縮進卻沒有縮進。Python沒有找到期望縮進的代碼塊時,會讓你知道哪行代碼有問題。
File "magicians.py", line 3
print(magician)
^
IndentationError:
expected an indented block
通常,將緊跟在for 語句後面的代碼行縮進,可消除這種縮進錯誤。
4.2.2 忘記縮進額外的代碼行
有時候,迴圈能夠運行而不會報告錯誤,但結果可能會出乎意料。試圖在迴圈中執行多項任務,卻忘記縮進其中的一些代碼行時,就會出現這種情況。
例如,如果忘記縮進迴圈中的第2行代碼(它告訴每位魔術師,我們期待他的下一次表演),就會出現這種情況:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was
a great trick!")
❶
print("I can't wait to see your next trick, " + magician.title() +
".\n")
第二條print 語句(見❶)原本需要縮進,但Python發現for 語句後面有一行代碼是縮進的,因此它沒有報告錯誤。最終的結果是,對於列表中的每位魔術師,都執行了第一條print 語句,因為它縮進了;而第二條print 語句沒有縮進,因此它只在迴圈結束後執行一次。由於變數magician 的終值為'carolina' ,因此只有她收到了消息“looking forward to the next trick”:
Alice,
that was a great trick!
David,
that was a great trick!
Carolina,
that was a great trick!
I
can't wait to see your next trick, Carolina.
這是一個邏輯錯誤 。從語法上看,這些Python代碼是合法的,但由於存在邏輯錯誤,結果並不符合預期。如果你預期某項操作將針對每個清單元素都執行一次,但它卻只執行了一次,請確定是否需要將一行或多行代碼縮進。
4.2.3 不必要的縮進
如果你不小心縮進了無需縮進的代碼行,Python將指出這一點:
hello_world.py
message = "Hello Python world!"
❶ print(message)
print 語句(見❶)無需縮進,因為它並不屬於前一行代碼,因此Python將指出這種錯誤:
File "hello_world.py", line 2
print(message)
^
IndentationError:
unexpected indent
為避免意外縮進錯誤,請只縮進需要縮進的代碼。在前面編寫的程式中,只有要在for 迴圈中對每個元素執行的代碼需要縮進。
4.2.4 迴圈後不必要的縮進
如果你不小心縮進了應在迴圈結束後執行的代碼,這些代碼將針對每個清單元素重複執行。在有些情況下,這可能導致Python報告語法錯誤,但在大多數情況下,這只會導致邏輯錯誤。
例如,如果不小心縮進了感謝全體魔術師精彩表演的代碼行,結果將如何呢?
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was
a great trick!")
print("I can't wait to see your next
trick, " + magician.title() + ".\n")
❶ print("Thank you everyone, that was a
great magic show!")
由於❶處的代碼行被縮進,它將針對列表中的每位魔術師執行一次,如❷所示:
Alice, that was a great trick!
I can't wait to see your next trick, Alice.
❷ Thank you
everyone, that was a great magic show!
David, that was a great trick!
I can't wait to see your next trick, David.
❷ Thank you
everyone, that was a great magic show!
Carolina, that was a great trick!
I can't wait to see your next trick,
Carolina.
❷ Thank you
everyone, that was a great magic show!
這也是一個邏輯錯誤,與4.2.2節的錯誤類似。Python不知道你的本意,只要代碼符合語法,它就會運行。如果原本只應執行一次的操作執行了多次,請確定你是否不應該縮進執行該操作的代碼。
4.2.5 遺漏了冒號
for 語句末尾的冒號告訴Python,下一行是迴圈的第一行。
magicians = ['alice', 'david', 'carolina']
❶ for
magician in magicians
print(magician)
如果你不小心遺漏了冒號,如❶所示,將導致語法錯誤,因為Python不知道你意欲何為。這種錯誤雖然易於消除,但並不那麼容易發現。程式師為找出這樣的單字元錯誤,花費的時間多得令人驚訝。這樣的錯誤之所以難以發現,是因為通常在我們的意料之外。
動手試一試
4-1 比薩 :想出至少三種你喜歡的比薩,將其名稱存儲在一個清單中,再使用for 迴圈將每種比薩的名稱都列印出來。
·
修改這個for 迴圈,使其列印包含比薩名稱的句子,而不僅僅是比薩的名稱。對於每種比薩,都顯示一行輸出,如“I like
pepperoni pizza”。
·
在程式末尾添加一行代碼,它不在for 迴圈中,指出你有多喜歡比薩。輸出應包含針對每種比薩的消息,還有一個總結性句子,如“I really love
pizza!”。
favorite_pizzas = ['pepperoni', 'hawaiian', 'veggie']
# 列印所有比薩的名稱。
for pizza in favorite_pizzas:
print(pizza)
print("\n")
# 針對每種比薩列印一個句子。
for pizza in favorite_pizzas:
print("I really love " + pizza + " pizza!")
print("\nI really
love pizza!")
輸出:
pepperoni
hawaiian
veggie
I really love pepperoni pizza!
I really love hawaiian pizza!
I really love veggie pizza!
I really love pizza!
練習4-3 數到20
使用一個for迴圈打印數1~20(含)。
numbers = list(range(1, 21))
for number in numbers:
print(number)
輸出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
4-2 動物 :想出至少三種有共同特徵的動物,將這些動物的名稱存儲在一個清單中,再使用for 迴圈將每種動物的名稱都列印出來。
·
修改這個程式,使其針對每種動物都列印一個句子,如“A dog would
make a great pet”。
·
在程式末尾添加一行代碼,指出這些動物的共同之處,如列印諸如“Any of these
animals would make a great pet!”這樣的句子。
4.3 創建數值列表
需要存儲一組數位的原因有很多,例如,在遊戲中,需要跟蹤每個角色的位置,還可能需要跟蹤玩家的幾個最高得分。在資料視覺化中,處理的幾乎都是由數位(如溫度、距離、人口數量、經度和緯度等)組成的集合。
清單非常適合用於存儲數位集合,而Python提供了很多工具,可説明你高效地處理數位清單。明白如何有效地使用這些工具後,即便清單包含數百萬個元素,你編寫的代碼也能運行得很好。
4.3.1 使用函數range()
Python函數range() 讓你能夠輕鬆地生成一系列的數字。例如,可以像下面這樣使用函數range() 來列印一系列的數字:
numbers.py
for
value in range(1,5):
print(value)
上述代碼好像應該列印數字1~5,但實際上它不會列印數字5:
1
2
3
4
在這個示例中,range() 只是列印數字1~4,這是你在程式設計語言中經常看到的差一行為的結果。函數range() 讓Python從你指定的第一個值開始數,並在到達你指定的第二個值後停止,因此輸出不包含第二個值(這裡為5)。
要列印數位1~5,需要使用range(1,6) :
for
value in range(1,6):
print(value)
這樣,輸出將從1開始,到5結束:
1
2
3
4
5
使用range() 時,如果輸出不符合預期,請嘗試將指定的值加1或減1。
4.3.2 使用range() 創建數位清單
要創建數位清單,可使用函數list() 將range() 的結果直接轉換為列表。如果將range() 作為list() 的參數,輸出將為一個數字清單。
在前一節的示例中,我們列印了一系列數字。要將這些數位轉換為一個清單,可使用list() :
numbers
= list(range(1,6))
print(numbers)
結果如下:
[1,
2, 3, 4, 5]
使用函數range() 時,還可指定步長。例如,下面的代碼列印1~10內的偶數:
even_numbers.py
even_numbers
= list(range(2,11,2))
print(even_numbers)
在這個示例中,函數range() 從2開始數,然後不斷地加2,直到達到或超過終值(11),因此輸出如下:
[2,
4, 6, 8, 10]
使用函數range() 幾乎能夠創建任何需要的數位集,例如,如何創建一個列表,其中包含前10個整數(即1~10)的平方呢?在Python中,兩個星號(** )表示乘方運算。下面的代碼演示了如何將前10個整數的平方加入到一個列表中:
squares.py
❶ squares =
[]
❷ for value
in range(1,11):
❸ square = value**2
❹ squares.append(square)
❺ print(squares)
首先,我們創建了一個空列表(見❶);接下來,使用函數range() 讓Python遍歷1~10的值(見❷)。在迴圈中,計算當前值的平方,並將結果存儲到變數square 中(見❸)。然後,將新計算得到的平方值附加到列表squares 末尾(見❹)。最後,迴圈結束後,列印列表squares (見❺):
[1,
4, 9, 16, 25, 36, 49, 64, 81, 100]
為讓這些代碼更簡潔,可不使用臨時變數square ,而直接將每個計算得到的值附加到列表末尾:
squares = []
for value in range(1,11):
❶ squares.append(value**2)
print(squares)
❶處的代碼與squares.py中❸處和❹處的代碼等效。在迴圈中,計算每個值的平方,並立即將結果附加到列表squares 的末尾。
創建更複雜的列表時,可使用上述兩種方法中的任何一種。有時候,使用臨時變數會讓代碼更易讀;而在其他情況下,這樣做只會讓代碼無謂地變長。你首先應該考慮的是,編寫清晰易懂且能完成所需功能的代碼;等到審核代碼時,再考慮採用更高效的方法。
4.3.3 對數字清單執行簡單的統計計算
有幾個專門用於處理數位清單的Python函數。例如,你可以輕鬆地找出數位清單的最大值、最小值和總和:
>>>
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>>
min(digits)
0
>>>
max(digits)
9
>>>
sum(digits)
45
注意 出於版面考慮,本節使用的數字清單都很短,但這裡介紹的知識也適用于包含數百萬個數字的清單。
4.3.4 列表解析
前面介紹的生成清單squares 的方式包含三四行代碼,而列表解析讓你只需編寫一行代碼就能生成這樣的列表。清單解析 將for 迴圈和創建新元素的代碼合併成一行,並自動附加新元素。面向初學者的書籍並非都會介紹清單解析,這裡之所以介紹列表解析,是因為等你開始閱讀他人編寫的代碼時,很可能會遇到它們。
下面的示例使用列表解析創建你在前面看到的平方數列表:
squares.py
squares
= [value**2 for value in range(1,11)]
print(squares)
要使用這種語法,首先指定一個描述性的列表名,如squares ;然後,指定一個左方括號,並定義一個運算式,用於生成你要存儲到清單中的值。在這個示例中,運算式為value**2 ,它計算平方值。接下來,編寫一個for 迴圈,用於給運算式提供值,再加上右方括號。在這個示例中,for 迴圈為for value in range(1,11) ,它將值1~10提供給運算式value**2 。請注意,這裡的for 語句末尾沒有冒號。
結果與你在前面看到的平方數列表相同:
[1,
4, 9, 16, 25, 36, 49, 64, 81, 100]
要創建自己的清單解析,需要經過一定的練習,但能夠熟練地創建常規列表後,你會發現這樣做是完全值得的。當你覺得編寫三四行代碼來生成列表有點繁複時,就應考慮創建列表解析了。
動手試一試
4-3 數到20 :使用一個for 迴圈列印數字1~20(含)。
4-4 一百萬 :創建一個清單,其中包含數字1~1 000 000,再使用一個for 迴圈將這些數字列印出來(如果輸出的時間太長,按Ctrl + C停止輸出,或關閉輸出窗口)。
4-5 計算1~1 000 000的總和 :創建一個清單,其中包含數字1~1 000 000,再使用min() 和max() 核實該列表確實是從1開始,到1 000 000結束的。另外,對這個清單調用函數sum() ,看看Python將一百萬個數位相加需要多長時間。
numbers = list(range(1, 1000001))
print(min(numbers))
print(max(numbers))
print(sum(numbers))
輸出:
1
1000000
500000500000
練習4-7 3的倍數
創建一個列表,其中包含3~30能被3整除的數;再使用一個for迴圈將這個清單中的數字都列印出來。
threes = list(range(3, 31, 3))
for number in threes:
print(number)
輸出:
3
6
9
12
15
18
21
24
27
30
4-6 奇數 :通過給函數range() 指定第三個參數來創建一個列表,其中包含1~20的奇數;再使用一個for 迴圈將這些數字都列印出來。
4-7 3的倍數 :創建一個列表,其中包含3~30內能被3整除的數字;再使用一個for 迴圈將這個清單中的數字都列印出來。
4-8 立方 :將同一個數字乘三次稱為立方。例如,在Python中,2的立方用2**3 表示。請創建一個清單,其中包含前10個整數(即1~10)的立方,再使用一個for 迴圈將這些立方數都列印出來。
cubes = []
for number in range(1, 11):
cube = number**3
cubes.append(cube)
for cube in cubes:
print(cube)
輸出:
1
8
27
64
125
216
343
512
729
1000
練習4-9 立方解析
使用列表解析生成一個列表,其中包含前10個整數的立方。
cubes = [number**3 for number in range(1,11)]
for cube in cubes:
print(cube)
輸出:
1
8
27
64
125
216
343
512
729
1000
4-9 立方解析 :使用列表解析生成一個列表,其中包含前10個整數的立方。
4.4 使用列表的一部分
在第3章中,你學習了如何訪問單個清單元素。在本章中,你一直在學習如何處理清單的所有元素。你還可以處理清單的部分元素——Python稱之為切片 。
4.4.1 切片
要創建切片,可指定要使用的第一個元素和最後一個元素的索引。與函數range() 一樣,Python在到達你指定的第二個索引前面的元素後停止。要輸出清單中的前三個元素,需要指定索引0~3,這將輸出分別為0 、1 和2 的元素。
下面的示例處理的是一個運動隊成員列表:
players.py
players = ['charles', 'martina', 'michael',
'florence', 'eli']
❶
print(players[0:3])
❶處的代碼列印該列表的一個切片,其中只包含三名隊員。輸出也是一個列表,其中包含前三名隊員:
['charles',
'martina', 'michael']
你可以生成列表的任何子集,例如,如果你要提取列表的第2~4個元素,可將起始索引指定為1 ,並將終止索引指定為4 :
players
= ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[1:4])
這一次,切片始於'marita' ,終於'florence' :
['martina',
'michael', 'florence']
如果你沒有指定第一個索引,Python將自動從列表開頭開始:
players
= ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])
由於沒有指定起始索引,Python從清單開頭開始提取:
['charles',
'martina', 'michael', 'florence']
要讓切片終止於列表末尾,也可使用類似的語法。例如,如果要提取從第3個元素到清單末尾的所有元素,可將起始索引指定為2 ,並省略終止索引:
players
= ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[2:])
Python將返回從第3個元素到清單末尾的所有元素:
['michael',
'florence', 'eli']
無論清單多長,這種語法都能夠讓你輸出從特定位置到清單末尾的所有元素。本書前面說過,負數索引返回離清單末尾相應距離的元素,因此你可以輸出列表末尾的任何切片。例如,如果你要輸出名單上的最後三名隊員,可使用切片players[-3:] :
players
= ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:])
上述代碼列印最後三名隊員的名字,即便隊員名單的長度發生變化,也依然如此。
4.4.2 遍歷切片
如果要遍歷清單的部分元素,可在for 迴圈中使用切片。在下面的示例中,我們遍歷前三名隊員,並列印他們的名字:
players = ['charles', 'martina', 'michael',
'florence', 'eli']
print("Here are the first three players
on my team:")
❶ for
player in players[:3]:
print(player.title())
❶處的代碼沒有遍歷整個隊員列表,而只遍歷前三名隊員:
Here
are the first three players on my team:
Charles
Martina
Michael
在很多情況下,切片都很有用。例如,編寫遊戲時,你可以在玩家退出遊戲時將其最終得分加入到一個列表中。然後,為獲取該玩家的三個最高得分,你可以將該列表按降冪排列,再創建一個隻包含前三個得分的切片。處理資料時,可使用切片來進行批量處理;編寫Web應用程式時,可使用切片來分頁顯示資訊,並在每頁顯示數量合適的資訊。
4.4.3 複製列表
你經常需要根據既有清單創建全新的列表。下面來介紹複製列表的工作原理,以及複製列表可提供極大幫助的一種情形。
要複製列表,可創建一個包含整個列表的切片,方法是同時省略起始索引和終止索引([:] )。這讓Python創建一個始於第一個元素,終止於最後一個元素的切片,即複製整個列表。
例如,假設有一個列表,其中包含你最喜歡的四種食品,而你還想創建另一個列表,在其中包含一位朋友喜歡的所有食品。不過,你喜歡的食品,這位朋友都喜歡,因此你可以通過複製來創建這個列表:
foods.py
❶ my_foods
= ['pizza', 'falafel', 'carrot cake']
❷ friend_foods
= my_foods[:]
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods
are:")
print(friend_foods)
我們首先創建了一個名為my_foods 的食品列表(見❶),然後創建了一個名為friend_foods 的新列表(見❷)。我們在不指定任何索引的情況下從清單my_foods 中提取一個切片,從而創建了這個列表的副本,再將該副本存儲到變數friend_foods 中。列印每個列表後,我們發現它們包含的食品相同:
My
favorite foods are:
['pizza',
'falafel', 'carrot cake']
My
friend's favorite foods are:
['pizza',
'falafel', 'carrot cake']
為核實我們確實有兩個列表,下面在每個列表中都添加一種食品,並核實每個清單都記錄了相應人員喜歡的食品:
my_foods = ['pizza', 'falafel', 'carrot
cake']
❶
friend_foods = my_foods[:]
❷ my_foods.append('cannoli')
❸
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
與前一個示例一樣,我們首先將my_foods 的元素複製到新清單friend_foods 中(見❶)。接下來,在每個列表中都添加一種食品:在列表my_foods 中添加'cannoli' (見❷),而在friend_foods 中添加'ice cream' (見❸)。最後,列印這兩個列表,核實這兩種食品包含在正確的列表中。
My favorite foods are:
❹ ['pizza',
'falafel', 'carrot cake', 'cannoli']
My friend's favorite foods are:
❺ ['pizza',
'falafel', 'carrot cake', 'ice cream']
❹處的輸出表明,'cannoli' 包含在你喜歡的食品列表中,而'ice
cream' 沒有。❺處的輸出表明,'ice
cream' 包含在你朋友喜歡的食品列表中,而'cannoli' 沒有。倘若我們只是簡單地將my_foods 賦給friend_foods ,就不能得到兩個列表。例如,下例演示了在不使用切片的情況下複製清單的情況:
my_foods = ['pizza', 'falafel', 'carrot
cake']
#這行不通
❶
friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods
are:")
print(friend_foods)
這裡將my_foods 賦給friend_foods ,而不是將my_foods 的副本存儲到friend_foods (見❶)。這種語法實際上是讓Python將新變數friend_foods 關聯到包含在my_foods 中的列表,因此這兩個變數都指向同一個清單。鑒於此,當我們將'cannoli' 添加到my_foods 中時,它也將出現在friend_foods 中;同樣,雖然'ice
cream' 好像只被加入到了friend_foods 中,但它也將出現在這兩個列表中。
輸出表明,兩個列表是相同的,這並非我們想要的結果:
My
favorite foods are:
['pizza',
'falafel', 'carrot cake', 'cannoli', 'ice cream']
My
friend's favorite foods are:
['pizza',
'falafel', 'carrot cake', 'cannoli', 'ice cream']
注意 現在暫時不要考慮這個示例中的細節。基本上,當你試圖使用列表的副本時,如果結果出乎意料,請確認你像第一個示例那樣使用切片複製了列表。
動手試一試
4-10 切片 :選擇你在本章編寫的一個程式,在末尾添加幾行代碼,以完成如下任務。
·
列印消息“The first three
items in the list are:”,再使用切片來列印清單的前三個元素。
·
列印消息“Three items
from the middle of the list are:”,再使用切片來列印清單中間的三個元素。
·
列印消息“The last three
items in the list are:”,再使用切片來列印清單末尾的三個元素。
4-11 你的比薩和我的比薩 :在你為完成練習4-1而編寫的程式中,創建比薩清單的副本,並將其存儲到變數friend_pizzas 中,再完成如下任務。
·
在原來的比薩列表中添加一種比薩。
·
在列表friend_pizzas 中添加另一種比薩。
·
核實你有兩個不同的列表。為此,列印消息“My favorite pizzas
are:”,再使用一個for 迴圈來列印第一個列表;列印消息“My friend's favorite pizzas are:”,再使用一個for 迴圈來列印第二個列表。核實新增的比薩被添加到了正確的列表中。
favorite_pizzas = ['pepperoni', 'hawaiian', 'veggie']
friend_pizzas = favorite_pizzas[:]
favorite_pizzas.append("meat lover's")
friend_pizzas.append('pesto')
print("My
favorite pizzas are:")
for pizza in favorite_pizzas:
print("- " + pizza)
print("\nMy
friend's favorite pizzas are:")
for pizza in friend_pizzas:
print("- " + pizza)
輸出:
My favorite pizzas are:
- pepperoni
- hawaiian
- veggie
- meat lover's
My friend's favorite pizzas are:
- pepperoni
- hawaiian
- veggie
- pesto
練習4-13 自助餐
有一家自助式餐館,只提供五種簡單的食品。請想出五種簡單的食品,並將其存儲在一個元組中。
l 使用一個for迴圈將該餐館提供的五種食品都列印出來。
l 嘗試修改其中的一個元素,核實Python確實會拒絕你這樣做。
l 餐館調整了功能表,替換了它提供的其中兩種食品。請編寫一個這樣的代碼塊:給元組變數賦值,並使用一個for迴圈將新元組的每個元素都列印出來。
menu_items = (
'rockfish sandwich', 'halibut nuggets', 'smoked salmon chowder',
'salmon burger', 'crab cakes',
)
print("You can
choose from the following menu items:")
for item in menu_items:
print("- " + item)
menu_items = (
'rockfish sandwich', 'halibut nuggets', 'smoked salmon chowder',
'black cod tips', 'king crab legs',
)
print("\nOur menu
has been updated.")
print("You can
now choose from the following items:")
for item in menu_items:
print("- " + item)
輸出:
You can choose from the following menu items:
- rockfish sandwich
- halibut nuggets
- smoked salmon chowder
- salmon burger
- crab cakes
Our menu has been updated.
You can now choose from the following items:
- rockfish sandwich
- halibut nuggets
- smoked salmon chowder
- black cod tips
- king crab legs
4-12 使用多個迴圈 :在本節中,為節省篇幅,程式foods.py的每個版本都沒有使用for 迴圈來列印列表。請選擇一個版本的foods.py,在其中編寫兩個for 迴圈,將各個食品列表都列印出來。
4.5 元組
清單非常適合用於存儲在程式運行期間可能變化的資料集。列表是可以修改的,這對處理網站的用戶列表或遊戲中的角色列表至關重要。然而,有時候你需要創建一系列不可修改的元素,元組可以滿足這種需求。Python將不能修改的值稱為不可變的 ,而不可變的列表被稱為元組 。
4.5.1 定義元組
元組看起來猶如列表,但使用圓括號而不是方括號來標識。定義元組後,就可以使用索引來訪問其元素,就像訪問清單元素一樣。
例如,如果有一個大小不應改變的矩形,可將其長度和寬度存儲在一個元組中,從而確保它們是不能修改的:
dimensions.py
❶
dimensions = (200, 50)
❷
print(dimensions[0])
print(dimensions[1])
我們首先定義了元組dimensions (見❶),為此我們使用了圓括號而不是方括號。接下來,我們分別列印該元組的各個元素,使用的語法與訪問清單元素時使用的語法相同(見❷):
200
50
下面來嘗試修改元組dimensions 中的一個元素,看看結果如何:
dimensions = (200, 50)
❶
dimensions[0] = 250
❶處的代碼試圖修改第一個元素的值,導致Python返回類型錯誤消息。由於試圖修改元組的操作是被禁止的,因此Python指出不能給元組的元素賦值:
Traceback
(most recent call last):
File "dimensions.py", line 3, in
<module>
dimensions[0] = 250
TypeError:
'tuple' object does not support item assignment
代碼試圖修改矩形的尺寸時,Python報告錯誤,這很好,因為這正是我們希望的。
4.5.2 遍歷元組中的所有值
像列表一樣,也可以使用for 迴圈來遍歷元組中的所有值:
dimensions
= (200, 50)
for
dimension in dimensions:
print(dimension)
就像遍歷列表時一樣,Python返回元組中所有的元素,:
200
50
4.5.3 修改元組變數
雖然不能修改元組的元素,但可以給存儲元組的變數賦值。因此,如果要修改前述矩形的尺寸,可重新定義整個元組:
❶
dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
❷
dimensions = (400, 100)
❸
print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)
我們首先定義了一個元組,並將其存儲的尺寸列印了出來(見❶);接下來,將一個新元組存儲到變數dimensions 中(見❷);然後,列印新的尺寸(見❸)。這次,Python不會報告任何錯誤,因為給元組變數賦值是合法的:
Original
dimensions:
200
50
Modified
dimensions:
400
100
相比於清單,元組是更簡單的資料結構。如果需要存儲的一組值在程式的整個生命週期內都不變,可使用元組。
動手試一試
4-13 自助餐 :有一家自助式餐館,只提供五種簡單的食品。請想出五種簡單的食品,並將其存儲在一個元組中。
·
使用一個for 迴圈將該餐館提供的五種食品都列印出來。
·
嘗試修改其中的一個元素,核實Python確實會拒絕你這樣做。
·
餐館調整了功能表,替換了它提供的其中兩種食品。請編寫一個這樣的代碼塊:給元組變數賦值,並使用一個for 迴圈將新元組的每個元素都列印出來。
4.6 設置代碼格式
隨著你編寫的程式越來越長,有必要瞭解一些代碼格式設置約定。請花時間讓你的代碼盡可能易於閱讀;讓代碼易於閱讀有助於你掌握程式是做什麼的,也可以幫助他人理解你編寫的代碼。
為確保所有人編寫的代碼的結構都大致一致,Python程式師都遵循一些格式設置約定。學會編寫整潔的Python後,就能明白他人編寫的Python代碼的整體結構——只要他們和你遵循相同的指南。要成為專業程式師,應從現在開始就遵循這些指南,以養成良好的習慣。
4.6.1 格式設置指南
若要提出Python語言修改建議,需要編寫Python改進提案 (Python Enhancement Proposal,PEP)。PEP 8是最古老的PEP之一,它向Python程式師提供了代碼格式設置指南。PEP 8的篇幅很長,但大都與複雜的編碼結構相關。
Python格式設置指南的編寫者深知,代碼被閱讀的次數比編寫的次數多。代碼編寫出來後,調試時你需要閱讀它;給程式添加新功能時,需要花很長的時間閱讀代碼;與其他程式師分享代碼時,這些程式師也將閱讀它們。
如果一定要在讓代碼易於編寫和易於閱讀之間做出選擇,Python程式師幾乎總是會選擇後者。下面的指南可説明你從一開始就編寫出清晰的代碼。
4.6.2 縮進
PEP 8建議每級縮進都使用四個空格,這既可提高可讀性,又留下了足夠的多級縮進空間。
在文書處理文檔中,大家常常使用定位字元而不是空格來縮進。對於文書處理文檔來說,這樣做的效果很好,但混合使用定位字元和空格會讓Python解譯器感到迷惑。每款文字編輯器都提供了一種設置,可將輸入的定位字元轉換為指定數量的空格。你在編寫代碼時應該使用定位字元鍵,但一定要對編輯器進行設置,使其在文檔中插入空格而不是定位字元。
在程式中混合使用定位字元和空格可能導致極難解決的問題。如果你混合使用了定位字元和空格,可將檔中所有的定位字元轉換為空格,大多數編輯器都提供了這樣的功能。
4.6.3 行長
很多Python程式師都建議每行不超過80字元。最初制定這樣的指南時,在大多數電腦中,終端視窗每行只能容納79字元;當前,電腦螢幕每行可容納的字元數多得多,為何還要使用79字元的標準行長呢?這裡有別的原因。專業程式師通常會在同一個螢幕上打開多個檔,使用標準行長可以讓他們在螢幕上並排打開兩三個檔時能同時看到各個檔的完整行。PEP 8還建議注釋的行長都不超過72字元,因為有些工具為大型項目自動生成文檔時,會在每行注釋開頭添加格式化字元。
PEP 8中有關行長的指南並非不可逾越的紅線,有些小組將最大行長設置為99字元。在學習期間,你不用過多地考慮代碼的行長,但別忘了,協作編寫程式時,大家幾乎都遵守PEP 8指南。在大多數編輯器中,都可設置一個視覺標誌——通常是一條分隔號,讓你知道不能越過的界線在什麼地方。
注意 附錄B介紹了如何配置文字編輯器,以使其:在你按定位字元鍵時插入四個空格;顯示一條垂直輔助線,幫助你遵守行長不能超過79字元的約定。
4.6.4 空行
要將程式的不同部分分開,可使用空行。你應該使用空行來組織程式檔,但也不能濫用;只要按本書的示例展示的那樣做,就能掌握其中的平衡。例如,如果你有5行創建列表的代碼,還有3行處理該列表的代碼,那麼用一個空行將這兩部分隔開是合適的。然而,你不應使用三四個空行將它們隔開。
空行不會影響代碼的運行,但會影響代碼的可讀性。Python解譯器根據水準縮進情況來解讀代碼,但不關心垂直間距。
4.6.5 其他格式設置指南
PEP 8還有很多其他的格式設置建議,但這些指南針對的程式大都比目前為止本書提到的程式複雜。等介紹更複雜的Python結構時,我們再來分享相關的PEP 8指南。
動手試一試
4-14 PEP 8 :請訪問https://python.org/dev/peps/pep-0008/ ,閱讀PEP 8格式設置指南。當前,這些指南適用的不多,但你可以大致流覽一下。
4-15 代碼審核 :從本章編寫的程式中選擇三個,根據PEP 8指南對它們進行修改。
·
每級縮進都使用四個空格。對你使用的文字編輯器進行設置,使其在你按Tab鍵時都插入四個空格;如果你還沒有這樣做,現在就去做吧(有關如何設置,請參閱附錄B)。
·
每行都不要超過80字元。對你使用的編輯器進行設置,使其在第80個字元處顯示一條垂直輔助線。
·
不要在程式檔中過多地使用空行。
4.7 小結
在本章中,你學習了:如何高效地處理清單中的元素;如何使用for 迴圈遍歷清單,Python如何根據縮進來確定程式的結構以及如何避免一些常見的縮進錯誤;如何創建簡單的數位清單,以及可對數字清單執行的一些操作;如何通過切片來使用列表的一部分和複製列表。你還學習了元組(它對不應變化的值提供了一定程度的保護),以及在代碼變得越來越複雜時如何設置格式,使其易於閱讀。
在第5章中,你將學習如何使用if 語句在不同的條件下採取不同的措施;學習如何將一組較複雜的條件測試組合起來,並在滿足特定條件時採取相應的措施。你還將學習如何在遍歷列表時,通過使用if 語句對特定元素採取特定的措施。

0 留言:
發佈留言