【Python 1-8】Python手把手教程之——管理列表List

作者 | 弗拉德
來源 | 弗拉德(公眾號:fulade_me)

上一節(jié)我們學習了如何創(chuàng)建一個列表,在列表里面插入、刪除數(shù)據(jù)等操作。
本節(jié)我們學習如何管理列表。

遍歷列表

在日常開發(fā)中,我們經(jīng)常需要遍歷列表的所有元素,對每個元素執(zhí)行相同的操作。例如,在管理商場的蔬菜時候,需要給所有的蔬菜商品都打7折,并重新生成價格。當我們需要對列表中的每個元素都執(zhí)行相同的操作時,可使用Python中的for循環(huán)。

假設我們有一個蔬菜名單,需要將其中每種蔬菜的名字都打印出來。為此,我們可以采用元素下標的方式分別獲取名單中的每個名字,但這種做法會導致多個問題。例如,如果名單很長,將包含大量重復的代碼。另外,每當名單的長度發(fā)生變化時,都必須修改代碼。通過使用for循環(huán),可讓Python去處理這些問題。
下面使用for循環(huán)來打印蔬菜單中的所有名字:

vegetables = ['potato','tomato','onion']
for name in vegetables:
    print(name)

這行代碼讓Python從列表vegetables中取出一個名字,并將其存儲在變量name中。最后,我們讓Python打印前面存儲的變量name中的名字。這樣,對于列表中的每個名字,Python都將重復執(zhí)行print(name)代碼。你可以這樣解讀這些代碼:對于列表vegetables中的每種蔬菜,都將其名字打印出來。輸出很簡單,就是列表中所有蔬菜的姓名:

potato
tomato
onion
詳解遍歷列表執(zhí)行過程

循環(huán)這種概念很重要,因為它是讓計算機自動完成重復工作的常見方式之一。例如,在前面的代碼中使用的簡單循環(huán)中,Python將首先讀取其中的第一行代碼:

for name in vegetables:

這行代碼讓Python獲取列表vegetables中的第一個值potato,并將其存儲到變量name 中。接下來,Python讀取下一行代碼:

print(name) 

它讓Python打印vegetables的值potato。由于該列表還包含其他值,Python返回到循環(huán)的第一行:

for name in vegetables:

Python獲取列表中的下一個名字tomato,并將其存儲到變量name中,再執(zhí)行下面這行代碼:

print(name) 

Python再次打印變量vegetables的值tomato。
接下來,Python再次執(zhí)行整個循環(huán),對列表中的最后一個值onion進行處理。
至此,列表中沒有其他的值了,因此Python接著執(zhí)行程序的下一行代碼。在這個示例中,for循環(huán)后面沒有其他的代碼,因此程序就此結束。
剛開始使用循環(huán)時需要牢記,對列表中的每個元素,都將執(zhí)行循環(huán)指定的步驟,而不管列表包含多少個元素。如果列表包含一百萬個元素,Python就重復執(zhí)行指定的步驟一百萬次,且通常速度非???。
另外,編寫for循環(huán)時,對于用于存儲列表中每個值的臨時變量,可指定任何名稱。比如說:

for dog in dogs:
for cat in cats:
for item in item_list:

這些寫法都是可以的。

在For循環(huán)中做更多操作

在for循環(huán)中,可以獲取到每一個元素,可對每個元素執(zhí)行任何操作。比如說我們對每一種蔬菜都輸出一句話。

vegetables = ['potato','tomato','onion']
for name in vegetables:
    print(name + ' is good !')

相比于前一個示例,唯一的不同是對于每種蔬菜,都打印了一條以其名字為抬頭的消息。這個循環(huán)第一次迭代時,變量name的值為potato,因此Python打印的第一條消息的抬頭為potato。第二次迭代時,消息的抬頭為tomato,而第三次迭代時,抬頭為onion
下面的輸出表明,對于列表中的每種蔬菜,都打印了一條個性化消息:

potato is good !
tomato is good !
onion is good !

在for循環(huán)中,想包含多少行代碼都可以。在代碼行for name in vegetables后面,每個縮進的代碼行都是循環(huán)的一部分,且將針對列表中的每個值都執(zhí)行一次。因此,可對列表中的每個值執(zhí)行任意次數(shù)的操作。
下面再添加一行代碼:

vegetables = ['potato','tomato','onion']
for name in vegetables:
    print(name + ' is good !')
    print(name + ' is a vegetable!')

由于兩條print語句都縮進了,因此它們都將針對列表中的每位蔬菜都執(zhí)行一次。輸出結果如下:

potato is good !
potato is a vegetable!
tomato is good !
tomato is a vegetable!
onion is good !
onion is a vegetable!

for循環(huán)中,想包含多少行代碼都可以。這種方式在開發(fā)過程中很有用。

避免縮進錯誤

Python根據(jù)縮進來判斷代碼行與前一個代碼行的關系。在前面的示例中,對每種蔬菜的輸出代碼行是for循環(huán)的一部分,因為它們縮進了。Python通過使用縮進讓代碼更易讀。
簡單地說,它要求你使用縮進讓代碼整潔而結構清晰。在較長的Python程序中,你將看到縮進程度各不相同的代碼塊,這讓你對程序的組織結構有大致的認識。 當你開始使用縮進時,需要注意一些常見的縮進錯誤。
例如,有時候,程序員會將不需要縮進的代碼塊縮進,而對于必須縮進的代碼塊卻忘了縮進。通過查看這些錯誤示例,有助于我們以后避開它們,以及在它們出現(xiàn)在程序中時進行修復。下面來看一些較為常見的縮進錯誤。

忘記縮進

對于位于for語句后面且屬于循環(huán)組成部分的代碼行,一定要縮進。如果你忘記縮進,運行會直接報錯:

vegetables = ['potato','tomato','onion']
for name in vegetables:
print(name)

print語句應縮進卻沒有縮進。Python沒有找到期望縮進的代碼塊時,會讓你知道哪行代碼有問題。

 File "<stdin>", line 2
    print(name)
        ^
IndentationError: expected an indented block

通常,將緊跟在for語句后面的代碼行縮進,可消除這種縮進錯誤。

忘記縮進額外的代碼行

有時候,循環(huán)能夠運行而不會報告錯誤,但結果可能會出乎意料。試圖在循環(huán)中執(zhí)行多項任務,卻忘記縮進其中的一些代碼行時,就會出現(xiàn)這種情況。

vegetables = ['potato','tomato','onion']
for name in vegetables:
    print(name + ' is good !')
print(name + ' is a vegetable!')

第二個print語句原本需要縮進,但Python發(fā)現(xiàn)for語句后面有一行代碼是縮進的,因此它沒有報告錯誤。最終的結果是,對于列表中的每種蔬菜,都執(zhí)行了第一條print語句,因為它縮進了;而第二條print語句沒有縮進,因此它只在循環(huán)結束后執(zhí)行一次。由于變量 name 的終值為onion,因此只有一條輸出了onion is a vegetable!:

potato is good !
tomato is good !
onion is good !
onion is a vegetable!

這是一個邏輯錯誤。從語法上看,這些代碼是沒問題的,但由于存在邏輯錯誤,結果并不符合預期。如果你預期某項操作將針對每個列表元素都執(zhí)行一次,但它卻只執(zhí)行了一次,請確定是否需要將一行或多行代碼縮進。

不必要的縮進

如果你不小心縮進了無需縮進的代碼行,同樣運行的時候也會報錯:

message = "Hello Python world!"
    print(message)

print語句無需縮進,因為它并不屬于前一行代碼,運行的時候會幫我們指出這種錯誤:

    print(message)
    ^
IndentationError: unexpected indent

為避免意外縮進錯誤,請只縮進需要縮進的代碼。在前面編寫的程序中,只有要在for循環(huán)中對每個元素執(zhí)行的代碼就需要縮進。

循環(huán)后不必要的縮進

如果我們不小心縮進了應在循環(huán)結束后執(zhí)行的代碼,這些代碼將針對每個列表元素重復執(zhí)行。 在有些情況下,這可能導致Python報告語法錯誤,但在大多數(shù)情況下,這只會導致邏輯錯誤。例如:

vegetables = ['potato','tomato','onion']
for name in vegetables:
    print(name + ' is good !')
    print(name + ' is a vegetable!')
    ## 這一行代碼被縮進
    print('There are three kinds of vegetables.')

那么輸出就會變成以下這個樣子:

potato is good !
potato is a vegetable!
There are three kinds of vegetables
tomato is good !
tomato is a vegetable!
There are three kinds of vegetables
onion is good !
onion is a vegetable!
There are three kinds of vegetables.

這也是一個邏輯錯誤。Python不知道你的本意,只要代碼符合語法,它就會運行。所以我們應該時刻保持警惕,不要用錯了縮進。

遺漏了冒號

for語句末尾的冒號告訴Python,下一行是循環(huán)的第一行。

vegetables = ['potato','tomato','onion']
for name in vegetables
    print(name + ' is good !')

    for name in vegetables
                         ^
SyntaxError: invalid syntax

如果你不小心遺漏了冒號,如上所示,將導致語法錯誤,因為Python不知道你意欲何為。這種錯誤雖然易于消除,但并不那么容易發(fā)現(xiàn)。

數(shù)值列表

Python函數(shù)range()讓你能夠輕松地生成一系列的數(shù)字。例如,可以像下面這樣使用函數(shù)range()來打印一系列的數(shù)字:

for value in range(1,5):
    print(value)

上述代碼好像應該打印數(shù)字1~5,但實際上它不會打印數(shù)字5:

1
2
3
4

在這個示例中,range()只是打印數(shù)字1~4,這是你在編程語言中經(jīng)??吹降牟钜恍袨榈慕Y果。函數(shù)range()讓Python從你指定的第一個值開始數(shù),并在到達你指定的第二個值后停止,因此輸出不包含第二個值(這里為5)。
要打印數(shù)字1~5,需要使用range(1,6):

for value in range(1,6):
    print(value)

這樣,輸出將從1開始,到5結束:

1
2
3
4
5

使用range()時,如果輸出不符合預期,請嘗試將指定的值加1或減1

使用range()創(chuàng)建數(shù)字列表

要創(chuàng)建數(shù)字列表,可使用函數(shù)list()range()的結果直接轉(zhuǎn)換為列表。如果將range()作為list()的參數(shù),輸出將為一個數(shù)字列表。
在上面的示例中,我們打印了一系列數(shù)字。要將這些數(shù)字轉(zhuǎn)換為一個列表,可使用list():

numbers = list(range(1,6))
print(numbers)

結果如下:

[1, 2, 3, 4, 5]

使用函數(shù)range()時,還可指定步長。例如,下面的代碼打印1~10內(nèi)的偶數(shù):

even_numbers = list(range(2,11,2)) 
print(even_numbers)

在這個示例中,函數(shù)range()從2開始數(shù),然后不斷地加2,直到達到或超過終值(11),因此 輸出如下:

[2, 4, 6, 8, 10]

使用函數(shù)range()幾乎能夠創(chuàng)建任何需要的數(shù)字集,例如,如何創(chuàng)建一個列表,其中包含前10個整數(shù)(即1~10)的平方呢?在Python中,兩個星號**表示乘方運算。下面的代碼演示如何將前10個整數(shù)的平方加入到一個列表中:

squares = []
for value in range(1,11):
    square = value**2
    squares.append(square)
print(squares)

首先,我們創(chuàng)建了一個空列表;接下來,使用函數(shù)range()讓Python遍歷1~10的值。在循環(huán)中,計算當前值的平方,并將結果存儲到變量square中。然后,將新計算得到的平方值附加到列表squares末尾。最后,循環(huán)結束后,打印列表squares:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
對數(shù)字列表執(zhí)行簡單的統(tǒng)計計算

有幾個專門用于處理數(shù)字列表的Python函數(shù)。例如,你可以輕松地找出數(shù)字列表的最大值、最小值和總和:

digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] 
### 輸出最小值
print(min(digits))
### 輸出最大值
print(max(digits))
### 計算總和
print(sum(digits))
0
9
45
列表解析

列表解析將for循環(huán)和創(chuàng)建新元素的代碼合并成一行,并自動附加新元素。下面的示例使用列表解析創(chuàng)建你在前面看到的平方數(shù)列表:

squares = [value**2 for value in range(1,11)] 
print(squares)

要使用這種語法,首先指定一個描述性的列表名,如squares;然后,指定一個左方括號,并定義一個表達式,用于生成你要存儲到列表中的值。在這個示例中,表達式為value**2,它來計算平方值。接下來,編寫一個for循環(huán),用于給表達式提供值,再加上右方括號。在這個示例中,for循環(huán)為for value in range(1,11),它將值1~10提供給表達式value**2。請注意,這里的for語句末尾沒有冒號。
結果與你在前面看到的平方數(shù)列表相同:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

要創(chuàng)建自己的列表解析,需要經(jīng)過一定的練習,但能夠熟練地創(chuàng)建常規(guī)列表后,你會發(fā)現(xiàn)這樣做是完全值得的。當你覺得編寫三四行代碼來生成列表有點繁復時,就應考慮創(chuàng)建列表解析了。

列表中的一部分

在上面的內(nèi)容中,我們學習了如何訪問單個列表元素。接下來,我們將學習如何處理列表的所有元素。我們還可以處理列表的部分元素——Python稱之為切片

切片

要創(chuàng)建切片,可指定要使用的第一個元素和最后一個元素的索引。與函數(shù)range()一樣,Python 在到達你指定的第二個索引前面的元素后停止。要輸出列表中的前三個元素,需要指定索引0~3, 這將輸出分別為0、1和2的元素。
我們還是以蔬菜列表為例:

vegetables = ['potato','tomato','onion','leek']
print(vegetables[0:3])

上面的代碼打印該列表的一個切片,其中只包含三種蔬菜。輸出也是一個列表,其中包含前三種蔬菜:

['potato', 'tomato', 'onion']

你可以生成列表的任何子集,例如,如果你要提取列表的第2~4個元素,可將起始索引指定為1,并將終止索引指定為4:

vegetables = ['potato','tomato','onion','leek']
print(vegetables[1:4])

這一次,切片始于tomato,終于leek:

['tomato', 'onion', 'leek']

如果你沒有指定第一個索引,Python將自動從列表開頭開始:

vegetables = ['potato','tomato','onion','leek']
print(vegetables[:4])

由于沒有指定起始索引,Python從列表開頭開始提取:

['potato', 'tomato', 'onion', 'leek']

要讓切片終止于列表末尾,也可使用類似的語法。例如,如果要提取從第3個元素到列表末 尾的所有元素,可將起始索引指定為2,并省略終止索引:

vegetables = ['potato','tomato','onion','leek']
print(vegetables[2:])

Python將返回從第3個元素到列表末尾的所有元素:

['onion', 'leek']

無論列表多長,這種語法都能夠讓你輸出從特定位置到列表末尾的所有元素。前面我們了解過,負數(shù)索引返回離列表末尾相應距離的元素,因此你可以輸出列表末尾的任何切片。例如,如果你要輸出名單上的最后三種蔬菜,可使用切片vegetables[-3:]:

vegetables = ['potato','tomato','onion','leek']
print(vegetables[-3:])
['tomato', 'onion', 'leek']
遍歷切片

如果要遍歷列表的部分元素,可在for循環(huán)中使用切片。在下面的示例中,我們遍歷前三種蔬菜,并打印它們的名字:

vegetables = ['potato','tomato','onion','leek']
print("Here are the first three vegetable:")
for name in vegetables[:3]:
    print(name.title())

輸出結果:

Here are the first three vegetable:
Potato
Tomato
Onion

在很多情況下,切片都很有用。例如,編寫游戲時,你可以在玩家退出游戲時將其最終得分加入到一個列表中。然后,為獲取該玩家的三個最高得分,你可以將該列表按降序排列,再創(chuàng)建一個只包含前三個得分的切片。處理數(shù)據(jù)時,可使用切片來進行批量處理;編寫Web應用程序時,可使用切片來分頁顯示信息,并在每頁顯示數(shù)量合適的信息。

復制列表

我們經(jīng)常需要根據(jù)既有列表創(chuàng)建全新的列表。下面來介紹復制列表的工作原理,以及復制列表可提供極大幫助。
要復制列表,可創(chuàng)建一個包含整個列表的切片,方法是同時省略起始索引和終止索引([:])。 這讓Python創(chuàng)建一個始于第一個元素,終止于最后一個元素的切片,即復制整個列表。
例如,假設有一個列表,其中包含你最喜歡的四種食品,而你還想創(chuàng)建另一個列表,在其中包含一位朋友喜歡的所有食品。不過,你喜歡的食品,這位朋友都喜歡,因此你可以通過復制來創(chuàng)建這個列表:

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)

我們首先創(chuàng)建了一個名為my_foods的食品列表,然后創(chuàng)建了一個名為friend_foods的新列表。我們在不指定任何索引的情況下從列表my_foods中提取一個切片,從而創(chuàng)建了這個列表的副本,再將該副本存儲到變量friend_foods中。打印每個列表后,我們發(fā)現(xiàn)它們包含的食品相同:

My favorite foods are:
['pizza', 'falafel', 'carrot cake']
My friend's favorite foods are: 
['pizza', 'falafel', 'carrot cake']

為了核實我們確實有兩個列表,下面在每個列表中都添加一種食品,并核實每個列表都記錄了相應人員喜歡的食品:

my_foods = ['pizza', 'falafel', 'carrot cake'] 5
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關聯(lián)到包含在my_foods中的列表,因此這兩個變量都指向同一個列表。鑒于此,當我們將cannoli添加到my_foods中時,它也將出現(xiàn)在friend_food中;同樣,雖然ice cream好像只被加入到了friend_foods中,但它也將出現(xiàn)在這兩個列表中。
輸出表明,兩個列表是相同的,這并非我們想要的結果:

My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']

8-1 動物:想出至少三種有共同特征的動物,將這些動物的名稱存儲在一個列表中,再使用for循環(huán)將每種動物的名稱都打印出來。
修改這個程序,使其針對每種動物都打印一個句子,如"A dog would make a great pet"。在程序末尾添加一行代碼,指出這些動物的共同之處,如打印諸如"Any of these animals would make a great pet!"這樣的句子。
8-2 數(shù)到 20:使用一個 for 循環(huán)打印數(shù)字 1~20(含)。
8-3 計算 1~ 1000000 的總和:創(chuàng)建一個列表,其中包含數(shù)字1~1000000,再使用min()和max()核實該列表確實是從1開始,到1000000 結束的。另外,對這個列表調(diào)用函數(shù)sum(),體會一下Python將一百萬個數(shù)字相加需要多長時間。
8-4 3的倍數(shù):創(chuàng)建一個列表,其中包含 3~30 內(nèi)能被3整除的數(shù)字;再使用一個for循環(huán)將這個列表中的數(shù)字都打印出來。
8-5 切片:修改8-1的代碼,在末尾添加幾行代碼,以完成如下任務。 打印消息"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:",再使用切片來打印列表末尾的三個元素。

想查看作業(yè)答案可以去我的Githu倉庫


?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容