第5章 列表和元組

2021-02-21 PythonerCN

《瘋狂的Python》節選

第5章 序列-列表和元組

序列是程序設計中常用的數據存儲方式,除了我們在前面介紹的字符串(string),Python中提供的另外兩種序列類型就是列表(list)和元組(tuple),相比字符串,列表和元祖能夠存儲的內容更豐富、更靈活多樣。其實,幾乎每一種程序設計語言都提供了序列類型的數據結構,只是名字不同,比如數組。

但是Python所提供的序列類型能夠實現的功能在所有程序設計語言中是最強大的,有時甚至超出了簡單的數據的框架。

5.1《英雄無敵》-迭代開發-構建英雄世界

學習列表之前我們先搬出英雄無敵,看一下在這個小程序中實際我們要解決的問題。經過前面的學習我們已經可以控制程序的流程了,但相信還有很多你覺得蹩腳或無法實現的效果。

現在先放下你要成為一個優秀程式設計師的想法。其實,一個成熟的應用往往並不是程式設計師一個人的功勞,一個項目從創建到落地是需要很多角色配合的結果,比如策劃、產品、經理,暫且不說角色,我們專注的看一下一個程序的誕生過程。

首先,應該沒有人像詩人一樣突然靈感爆發一氣呵成寫出一個程序,即便有,在這之前也一定有過深思熟路的積累才能爆發。通常程序開發的前期需要進行需求分析,比如《英雄無敵》這個遊戲要實現的功能、要呈現的效果、把它們列出來:

《英雄無敵》初步需求:

1. 註冊、登錄、驗證

2. 給角色起個名字,初始化英雄

3. 遊戲的前奏

4. 滿血出場

5. 有地圖

6. 發生隨機事件

7. …………

有了需求,就可以開始琢磨整個程序的大框架了,整個流程的控制,功能的設計,最後最後才是開始敲代碼,這時候其實代碼可能已經在腦子裡是個草稿了。寫出來之後還要經過反覆的測試、調試。不過,即便可以成功運行了,也不要高興得太早,可能需求這時候又變了。什麼?程序寫完了需求又變了?嗯,程式設計師永遠不知道客戶和產品經理會有什麼想法。這也是大家經常開玩笑說程式設計師和產品經理勢不兩立的原因,還好現在不用擔心,因為現在你是身兼所有職位在開發項目。那麼在這個需求當中,列表和元組有什麼作用呢?別急,往下看。

5.2 列表

作為序列類型的列表(list)跟字符串相比,相同是所有關於序列的操作都是通用的。

不同的有兩個方面,一個是字符串中的值只能是字符;在列表中值可以是任何類型。我們稱列表中的值為元素或列表項。另一點,就是列表是可變類型,也就是列表中的元素是可以改變的,這一點在後面會有詳細說明。

明確了相同和差異,就可以套用已知的字符串知識快速掌握列表了。

5.2.1創建列表

Python中創建列表的方法很多,最基本的創建形式就是通過方括號([ ]),其中所有的元素通過逗號分隔開。另外,你也可以通過list()函數創建列表,具體我們來看以下在Python會話中的幾個示例:

>>> aList = []

>>> numList = [1,2,3,4,5]

>>> hero = ['milo',100,'hero']

>>> listInList = [1,2,3,['a','b','c']]

>>> hwList = list('hello world')

>>> hero

['milo', 100, 'hero']

>>> hwList

['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

>>> type(aList)

<class 'list'>

>>>

    這幾個示例創建了幾個形式各異的列表,我們分別來看一下:

1. aList是一個空列表,也就是裡面沒有數據,不過這樣的空列表我們在程序設計過程中也會經常用到,比如有的時候我們要通過循環或遍歷構建一個新列表,這時我們就可以先建一個空列表,然後再把生成的值添加進來;

2. numList是一個純數字的列表,所有整數用逗號隔開;

3. hero混合了兩種類型的元素;

4. listInList則是一個列表中又包含了另一個列表,這種我們稱之為二元列表;

5. hwList則是通過list()函數講一個字符串轉化成了列表,每一個字符是一個元素,需要注意的是,非集合類型(數字,布爾值)的數據類型不能用list()轉化為列表;

5.2.2列表拆分

列表可以通過賦值的方式進行拆分,

>>> hero = ['milo',100,200]

>>> name, act, hp = hero

>>> name

'milo'

>>> act

100

>>> hp

200

5.3列表的序列化操作

列表有非常豐富的相關操作,這也是列表之所以強大的原因。不過,好在有些是序列通用的,所以比較好記,比如序列相關;有些功能性非常明顯,比如數據的增刪修改。我們先開看一些跟字符串相同的一些操作。

5.3.1索引和切片

讀取列表元素的方式就是變量名加索引(方括號中)因為列表與字符串同屬序列,所以,在列表操作過程中也有索引和切片,而且用法是完全一樣的,只是列表中的元素更豐富了。例如:

>>> hero = ['milo',100,'hero']

>>> hero[0]

'milo'

>>> hero[1]

100

通過索引除了讀取元素,也可以直接對指定索引的元素重新賦值。

二元列表的讀取方式:

>>> listInList = [1,2,3,['a','b','c']]

>>> listInList[3]

['a', 'b', 'c']

>>> listInList[3][1]

'b'

    這裡你只要搞清楚,listInList列表中有4各元素,其中第四個元素也是個列表。

需要注意的是列表用方括號表示,讀取索引也用方括號,注意區分,不要搞混了,例如:

    這個表達式弄明白,那說明你對列表已經理解了。這個例子經列表的創建和索引操作放在了一起,我們要從左向右閱讀表達式,左邊創建列表,右邊是這個列表的索引。

    最後就是需要注意索引越界的問題:

>>> [1,2,3,4,5][5]

Traceback (most recent call last):

 File "<pyshell#16>", line 1, in <module>

   [1,2,3,4,5][5]

IndexError: list index out of range

明確了索引的運用,接下來就是切片了,具體參照字符串中的切片操作,我們直接看例子吧,:

>>> hwList = list('hello world')

>>> numList = [1,2,3,4,5]

>>> hwList

['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

>>> hwList[::2]

['h', 'l', 'o', 'w', 'r', 'd']

5.3.2運算符及函數

字符串的重複(*)、拼接(+)、in和not in在列表上的使用效果是一樣的,我們直接看例子吧:

>>> aList = [1,2,3]

>>> bList = ['a','b','c']

>>> aList + bList

[1, 2, 3, 'a', 'b', 'c']

>>> aList * 3

[1, 2, 3, 1, 2, 3, 1, 2, 3]

>>> 3 in aList

True

>>> 'd' not in bList

True

另外,我們也可以用>、<、= =、<=、>=和!= 比較兩個列表,不過,因為列表元素類型比較多樣,應使用同一類型的元素(全數字或全字符串)避免不同類型的比較:

>>> [1,2,3,4] < [1,2,3,4,5]

True

>>> [1,2,3,4] < [1,2,3,'a']

Traceback (most recent call last):

 File "<pyshell#26>", line 1, in <module>

   [1,2,3,4] < [1,2,3,'a']

TypeError: '<' not supported between instances of 'int' and 'str'

>>>

    還有一些關於序列的通用函數是可以用於字符串、列表和元組的:

1. len()用於獲取序列的元素個數:

>>> len([1,2,3,4,5])

5

>>> len("abcde")

5

2. max()和min()返回序列中元素最大值和最小值:

>>> max([1,4,6,8,5,3,2,9])

9

>>> min([1,4,6,8,5,3,2,9])

1

>>> max('12345')

'5'

>>> min('12345')

'1'

3. sum()對數值型列表元素求和,非數值則報錯:

>>> sum([1,2,3,4,5])

15

>>> sum([1,2,3,4,5,'6'])

Traceback (most recent call last):

 File "<pyshell#38>", line 1, in <module>

   sum([1,2,3,4,5,'6'])

TypeError: unsupported operand type(s) for +: 'int' and 'str'

4. sorted()對序列進行排序,reversed()可以直接將序列倒序排列:

>>> l = [1,4,7,6,2,9]

>>> sorted(l)

[1, 2, 4, 6, 7, 9]

>>> reversed(l)

<list_reverseiterator object at 0x060D7B10>

>>> next(reversed(l))

9

這裡要注意,reversed返回的是一個迭代器,需要遍歷或調用next()。

5.3.3遍歷

在for循環中我們就已經介紹過通過range()生成一個列表迭代器的方法,現在有了列表,當然可以通過for直接遍歷了,還有上個例子中的reversed()也可以:

>>> for i in ['a', 'b', 'c']:

    print(i)

    

a

b

c

>>> for i in reversed(l):

    print(i)

    

9

2

6

7

4

1

>>>

5.4列表的操作

我們說列表時總會說它是可變的,跟字符串比較,其實就是指,你不能把字符串指定索引位置的字符變成其它字符。而列表就完全可以修改,甚至增加和刪除元素,用起來就像個資料庫一樣,而且我們也確實經常會把列表當做一個臨時的資料庫來用,說臨時是因為,列表的增刪改查都只是在你的一個程序中,程序運行結束後並不會保存下來,不過這個也不是問題,後面會介紹其他技術解決這個問題。

5.4.1可變的列表

    列表的可變性,非常有用,我們可以僅僅通過索引或切片來替換列表的元素甚至來個大換血,正因為這樣,更要避免無意的操作帶來失誤,所以我們來看些具體的一些改變列表的方式:

>>> role = ['milo',100,200,'hero']    

>>> role[0]

'milo'

>>> role[0] = 'zouqixian'    #改變第一個元素

>>> role

['zouqixian', 100, 200, 'hero']

>>> role[-1] = 'monster'    #改變最後一個元素

>>> role

['zouqixian', 100, 200, 'monster']

>>> role[1:3] = [2000]    #第二到第三個元素替換為一個元素

>>> role

['zouqixian', 2000, 'monster']

>>> role[:] = [1,2,3,4,5,6]    #遍歷列表替換為全新的元素

>>> role

[1, 2, 3, 4, 5, 6]

>>> role[:] = "hello world!"    #將列表指定元素替換為字符串字符

>>> role

['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!']

>>> role[:] = 12345    #上個操作僅限可迭代數據,整數不可迭代

Traceback (most recent call last):

 File "<pyshell#75>", line 1, in <module>

   role[:] = 12345

TypeError: can only assign an iterable

在這個例子中所有的操作都是通過指定列表索引進行賦值實現的,這裡的每個操作都對列表的值進行了修改,也就是每次列表標籤(變量名)所對應數據空間的內部數據。在這個過程中因為賦值語句不會有返回值,所以每次我們都通過變量名來查看結果。我們可以改變一個元素,也可以改變所有的元素,唯一需要注意的是被添加的元素必須是一個集合類型,集合中的每個元素作為元素單獨添加到列表中。

5.4.2列表的方法

針對列表的操作其實得益於列表對象的方法,就像字符串類型擁有大量的方法一樣。列表的所有方法可以通過help(list)看到。我們按實現的效果來看一下:

1. 檢索元素

我們可以通過索引就可以獲得列表的元素,通過列表的index(x)方法可以返回x元素的索引,如果元素不存在則報錯。

count(x)可以返回列表中x出現的次數,x是一個元素。

>>> role = ['milo',100,200,'hero']

>>> role.index('hero')

3

>>> role.count(0)    #0這個數字出現了4個,但是沒有這個單獨的元素

0

>>> role.count(100)    #100出現了1次

1

>>>

2. 增加元素

append()方法可以向列表尾部添加一個新的元素:

>>> role.append('level2')

>>> role

['milo', 100, 200, 'hero', 'level2']

extend()方法可以將另一個列表的元素添加到當前列表,這個跟通過—+號合併兩個列表是有區別的,後面單獨要說一下:

>>> bag = ['AK47','knife',100]

>>> role.extend(bag)

>>> role

['milo', 100, 200, 'hero', 'level2', 'AK47', 'knife',100]

insert()方法可以根據索引將一個元素插入到列表任何位置,這個方法需要兩個參數,第一個是位置也就是索引,第二個是需要插入的元素:

>>> role

['generral', 'milo', 100, 200, 'hero', 'level2', 'AK47', 'knife',100]

3. 刪除元素

remove()方法可以刪除一個指定值的元素,如果有多個則從左至右:

>>> role.remove(100)

>>> role

['generral', 'milo', 200, 'hero', 'level2', 'AK47', 'knife', 100]

>>> role.remove(100)

>>> role

['generral', 'milo', 200, 'hero', 'level2', 'AK47', 'knife']

如果想刪除(彈出)指定位置的元素就可以pop(),彈出的意思指刪除的同時,這個值會返回給調用者:

>>> role

['generral', 'milo', 200, 'hero', 'level2', 'AK47', 'knife']

>>> role.pop(-2)

'AK47'

>>> bag = role.pop(-1)

>>> role

['generral', 'milo', 200, 'hero', 'level2']

>>> bag

'knife'

如果你不需要返回值又想根據索引刪除,可以使用Python的del語句,del語句和切片結合就可以刪除多個元素了:

>>> del role[0]

>>> role

['milo', 200, 'hero', 'level2']

>>> del role[1:]

>>> role

['milo']

5.4.3字符串和列表

我們在字符串的章節有介紹過字符串方法split()可以把字符串按指定參數(默認是空白)分隔並返回一個列表。以及通過字符串方法join()將列表拼接成字符串。這裡不重複說了,可以參考字符串章節相關內容。

5.5列表推導式和生成器表達式

我們可以先來看一個過濾(filter)列表的例子。

    之前我們留的作業,已知10以內3,5的倍數為3、5、6、9,和是23,求1000以內3,5倍數的和,這個問題的解決方法很多,我採取下面這個辦法:

>>> numList = []

>>> for i in range(1,10):

         if i%3 == 0 or i%5 == 0:

             numList.append(i)

        

>>> numList

[3, 5, 6, 9]

>>> sum(numList)

23

5.5.1列表推導式

列表推導式(list comprehensions)是Python中很強大的、很受歡迎的特性,具有語言簡潔,速度快等優點。具體的作用是通過一個序列生成一個新的列表。什麼是通過一個序列生成一個新的列表?前面的兩個例子都是。

列表推導式的語法為:

[表達式 for 變量 in 列表]

[表達式 for 變量 in 列表 if 條件]

表達式:列表生成元素表達式,可以是有返回值的函數。

for 變量 in 列表:迭代列表將元素傳入表達式中如果有if則先交給if進行過濾。

if 條件:根據條件過濾哪些值可以。

基本的用法比如:

>>> lst = [2,6,3,5,9]

>>> [x**2 for x in lst]    #求所有元素的平方

[4, 36, 9, 25, 81]

>>> [x for x in lst if x%2 == 0]    #過濾出偶數

[2, 6]

由此,3,5倍數的例子用列表推導式只要一行代碼就可以了:

>>> [i for i in range(1,10) if i%3 ==0 or i%5 ==0]

[3, 5, 6, 9]

>>> sum([i for i in range(1,1000) if i%3 ==0 or i%5 ==0])

233168

5.5.2生成器表達式

生成器(generator)是一種特殊的迭代器,它的工作方式是每次處理一個對象,而不是一口氣處理和構造整個數據結構,這樣做的潛在優點是可以節省大量的內存。

生成器表達式(generator expression)並不真正創建列表, 而是返回一個生成器,生成器表達式語法結構和列表表達式是一樣的,區別在於表達式使用()括起來,而不是[]。上面的例子可以直接變成生成器表達式。

>>> lst = [2,6,3,5,9]

>>> (x**2 for x in lst)

<generator object <genexpr> at 0x061017E0>

這時我們就看到返回值不是列表了,可以採取迭代的方式獲取生成器的值:

>>> lst = [2,6,3,5,9]

>>> g = (x**2 for x in lst)

>>> type(g)

<class 'generator'>

>>> next(g)

4

3,5倍數用生成器表達式就變成了:

>>> sum((i for i in range(1,1000) if i%3 ==0 or i%5 ==0))

233168

看到這可能會有人問只是換了個符號,意義是什麼?這個就要回到迭代器上去了,最大的優點就是可以節省大量的內存了。

5.5.3一點建議

雖然列表推導式和生成器表達式很方便,但並不是什麼時候都可以去用,幾個建議。

1. 當只是執行一個循環就可以的時候儘量使用循環而不是列表解析,這樣更符合Python提倡的直觀性。因為列表推導式有的時候並不易讀。

2. 當有內建的操作或者類型能夠以更直接的方式實現的,不要使用列表解析。例如複製一個列表時,使用:L1=list(L)即可,不必使用:L1=[x for x in L]。

3. 如果需要對每個元素都調用並且返回結果時,應使用L1=map(f,L), 而不是 L1=[f(x) for x in L] ,map這樣的函數還有很多,我們放在函數的章節介紹。

5.6深拷貝淺拷貝

我們一直在說列表是可變的,有時我們會希望對列表做一個備份,所以,在涉及到拷貝的時候會有一些有意思或者讓新手頭疼的問題,在這,我通過一些非常簡單直觀的例子來說明一下。下面跟住我的思路過一遍應該就能明白了:

5.6.1賦值

首先看一下字符串,來作為對比:

s1 = "hello world"

>>> s2 = s1

>>> s2

'hello world'

>>> s1 = ''

>>> s1

''

我定義了字符串s1,然後s2=s1,相當於s1的數據增加了一個名字,所以通過s2訪問到的數據就是s1對應的數據,最後給s1賦值為空字符串,此時的s2的值是什麼?

這裡新手會犯一個錯誤,可能會認為s2會隨著s1的改變而改變,但實際s2的值並沒有改變,其實原因在介紹變量的時候就有說過,s1和s2都是數據的標籤而已,當執行s1=『』時,實際上相當於將s1這個標籤移動到了數據『』上,而s2並沒有移動,數據當然不會改變。

如果你並沒有搞錯,想到了正確答案,很好。那你可能會問,這有什麼意義?接下來就是關於列表的可變特性,我們看下面的例子:

>>> l1 = ['hello', 'world']

>>> l2 = l1

>>> l2

['hello', 'world']

>>> del l1[:]

>>> l1

[]

跟上面的例子類似,只是字符串變成了列表,並且刪除l1所有元素,l2的值是什麼?

想到了嗎?l2的值也清空了,別急,再看一步:

>>> l1 = ['hello', 'world']

>>> l1

['hello', 'world']

l1再賦值,l2會怎樣,同樣獲得值嗎?

依然是空。

什麼原因呢?首先明確一點,在Python中,s1 = s2和l1 = l2一樣的,都是給對象添加新的名字。但是為什麼列表的值被改變的時候,另一個名字所對應的值也變了呢?這是因為創建列表時數據的存儲方式,我們看一下l1 = l2之後的情況:

圖 引用

從這個結構表中可以看出l1和l2使用的是同一個存儲空間,所以這時我們通過任何一個名字對值進行改變,另一方所訪問的空間不變,獲取的值當然不變。而當我們第二次執行l1 = [『hello』, 』world』]時,實際上是將l1這個名字移動到一個新的列表對象上了:

圖 重新賦值

總結以上,  就是關於Python中賦值操作的效果:

1. 賦值是將一個對象的地址賦值給一個變量,讓變量指向該地址( 舊瓶裝舊酒 )。

2. 修改不可變對象(str、tuple)需要開闢新的空間。

3. 修改可變對象(list等)不需要開闢新的空間。

5.6.2淺拷貝

Python提供了一個copy模塊,其中的copy()方法可以實現淺拷貝,淺拷貝僅僅複製容器中元素的地址,效果如下:

>>>import copy

>>> a = ['hello',[1,2,3]]

>>> b = copy.copy(a)

>>> [id(x) for x in a]

[65592207, 5623045]

>>> [id(x) for x in b]

[65592207, 5623045]

>>> a[0] = 'world'

>>> a[1].append(4)

>>> print(a)

['world', [1, 2, 3, 4]]

>>> print(b)

['hello', [1, 2, 3, 4]]

這個例子中,經過淺拷貝之後的副本,再做修改之前元素的地址是相同的,此時淺拷貝只是將源列表中元素的地址複製了一份,修改a列表內的不可變元素字符串時移動了地址,b不跟著改變,而可變的列表元素則在內部增加了值,a和b的這個列表元素地址相同,所以同時變化。

總結以上,淺拷貝是在另一塊地址中創建一個新的變量或容器,但是容器內的元素的地址均是源對象的元素的地址的拷貝。也就是說新的容器中指向了舊的元素。

最後,除了copy模塊,我們還可以通過切片操作、工廠函數list()、對象的copy()方法等方法實現淺拷貝:

>>> a = [1,2,3,4]

>>> b = a[:]

>>> c = list(a)

>>> d = a.copy()

5.6.3深拷貝

深拷貝的方法是copy.deepcopy(),完全拷貝一個副本,容器內部元素地址都不一樣:

>>> from copy import deepcopy

>>> a=['hello',[1,2,3]]

>>> b=deepcopy(a)

>>> [id(x) for x in a] [46952708, 66053004]

>>> [id(x) for x in b] [48657389, 66028736]

>>> a[0]='world'

>>> a[1].append(4)

>>> print(a)

['world', [1, 2, 3, 4]]

>>> print(b)

['hello', [1, 2, 3]]

這個理中可以很明顯的看到,深拷貝後的對象地址和元素的地址都不同,可以看作是值相同的的完全拷貝的副本,原對象怎麼修改都不會影響深拷貝。

總結以上,我們用一個圖結束:

圖 淺拷貝和深拷貝

5.7元組

元組可以看作是不可變的列表。元組幾乎具備了列表所有的特徵,不同的就是元組一旦創建就不可改變,不能更改元素,也不能增減元素。

因為元組跟列表的相似,所以,基本上你可以嘗試所有的列表操作,除了更改元組元素,下面我們從區別於列表的一些特性了解一下元組。

5.7.1創建元組

元組實際是用逗號分隔的一列值,這個值也可以是任何類型的對象,創建元組是可以不用括號,但通常我們會用()將所有元素括起來,區別於列表的[]:

>>> t1 = (1, 2, 3, 'a', 'b', 'c')

>>> t2 = 1, 2, 3, 'a', 'b', 'c'

>>> t1

(1, 2, 3, 'a', 'b', 'c')

>>> t2

(1, 2, 3, 'a', 'b', 'c')

這裡需要注意一點,很多時候介紹原則的時候會有一個誤區,說元組的創建符號是(),包括我平時為了避免做過多解釋也這樣說。那就是,實際上真正創建元組的運算符是逗號,Python中圓括號大多數情況下都表示分組,圓括號加上逗號才成為元組創建的一部分,比如創建一個只有一個元素元組,只有括號沒有逗號的話跟元組一點關係也沒有:

>>> t3 = 1,

>>> t3

(1,)

>>> t4 = 1

>>> t4

1

>>> t5 = (1,)

>>> t5

(1,)

>>> t6 = (1)

>>> t6

1

>>> type(t3)

<class 'tuple'>

>>> type(t4)

<class 'int'>

>>> type(t5)

<class 'tuple'>

>>> type(t6)

<class 'int'>

>>>

還有一種特殊的元組就是空元組:

>>> t7 = ()

>>> t8 = tuple()

>>> t7

()

>>> t8

()

tuple()的另一個作用就是將其他序列轉為元組:

>>> t9 = tuple("hello")

>>> t9

('h', 'e', 'l', 'l', 'o')

>>>

5.7.2元組賦值

元組除了可以可以把一組數據賦值給一個變量,也可以進行拆分賦值,比如有一個比較經典的算法問題。有紅墨水和藍墨水各一杯,問怎樣將杯中墨水交換?解決辦法就是再找一個空杯做中轉,用傳統的賦值方式表示就是:

>>> red = "red water"

>>> blue = "blue water"

>>> temp = red

>>> red = blue

>>> blue = temp

這個辦法在Python中就顯得不那麼簡潔優雅了,Python中我們這樣:

>>> red, blue = blue, red

這種等號左右都是元組的方式就是其實就是元組拆分,這種賦值方式需要注意的就是左邊變量數跟右面元組的元素數要相等。

5.7.3列表和元組

列表和元組是可以相互轉換的,各自都提供了轉換函數list()和tuple()。除了相互轉換之外,還有一種情況會把他們拉到一起。

Python提供了一個內置函數zip(),作用是接收多個序列,每個序列取一個值放到一個元組裡,Python2中所有的元組組成一個列表,不過在Python3中不能直接看到這個列表,zip返回一個迭代器,需要迭代才能看到裡面的值。如果序列長度不同則以短的為準:

>>> x = 'xyz'

>>> l = [1,2,3,4]

>>> zip(x, l)

<zip object at 0x05450B48>

>>> for i in zip(x,l):

    print i

    

('x', 1)

('y', 2)

('z', 3)

迭代時可以利用元組賦值方式直接拆分元組:

>>> for v, k in zip(x,l):

    print(k, "===>", v)

    

1 ===> x

2 ===> y

3 ===> z

這種組合用來解決某些問題還是很有用的,比如判斷兩個序列當中是否在同一位置含有相同元素:

>>> for x, y in zip(l1, l2):

if x == y:

print(x)

5.7.4什麼時候用元組

元組與同為序列的字符串和列表,應該根據什麼決定使用元組呢?

首先是字符串,相比其他序列,字符串的限制比較多,元素只能是字符而且不可變。

列表是最靈活的,相比元組,用到的地方更多一些,所以我們用了較大篇幅來介紹。元組作為跟列表相似的數據類型,重點就在於它的不可變性,這種不可變性提供了一種具有完整性和持久性的數據結構。因此,可以為需要固定數據的地方提供不可變對象。比如在後面的字典類型的鍵就是不可變的,這時就只能用元組而不能用列表。

5.8《英雄無敵》需求落地

現在我們可以研究下開篇的英雄無敵的一些需求適合用什麼方式來實現了

1.開局玩家角色起名字:input

2.列表初始化英雄屬性:[名字, 血值, 攻擊力, 防禦力]

3.判斷名字是否為空,默認為「玩家一」:if語句

4.判斷英雄行動方向:if

5.設計地圖九宮格:列表或元組

6.優化數據結構

將字符串的英雄無敵做一下升級就大概變成這樣:

'''

Heroes beta-0.2

milo  str worldMap if while

'''

welcome = '-*-welcome to Heroes world!-*-'

mapmsg = '#######'

mapins = " -*- the world is like this -*- %s the '*' is you " % (mapmsg,)

worldMap = ['#','#','#','#','#','#','#']

instruction = '''

contrl your hero:| 'a'for left | 'd' for right |'''

print(welcome)

name = input('input your name:')

hp = 100

if not name:

   name = 'player01'

usermsg = {'name':name,'hp':hp}

print("HI!", usermsg['name'],'You Hp is :',usermsg['hp'])

print(mapins,instruction)

point = 0

while 1:

   worldMap[point] = "*"

   print('you are here',"".join(worldMap))

   userinput = input('go or quit:')

   if userinput == 'd' and point < 6:

       worldMap[point] = '#'

       point +=1

   elif userinput == 'a' and point > 0:

       worldMap[point] = '#'

       point -=1

   elif userinput == 'quit':

       print("goodbey!!")

       break

   else:

       print(instruction)

當然,這只是一個思路而已,你設計的遊戲是什麼樣子?自己實現吧!應該比我這個有意思吧。

相關焦點

  • 第3章 字符串、列表、元組和字典(一)----跟杜老師一起,趣學Python編程!
    同學們,在第2章裡,我們用Python做了一些基本的運算,並且學習了變量。在這一章裡,我們會學習Python編程中的另一些內容:字符串(string)、列表(list)、元組(tuple)和字典(map)。
  • Python元組和列表的區別
    那麼,元組和列表有哪些區別呢?元組和列表最大的區別就是,列表中的元素可以進行任意修改,就好比是用鉛筆在紙上寫的字,寫錯了還可以擦除重寫;而元組中的元素無法修改,除非將元組整體替換掉,就好比是用原子筆寫的字,寫了就擦不掉了,除非換一張紙。可以理解為,tuple 元組是一個只讀版本的 list 列表。
  • 十二、深入Python列表和元組
    只是粗學,下面進入深入學習在Pthon中數據結構是非常重要的,所以下面將深入Pyhon數據結構Python列表和元組總結什麼是列表和元組列表是動態的,長度大小不固定,可以隨意地增加、刪減或者改變tup = (1, 2, 3, 4)new_tup = tup + (5, ) # 創建新的元組 new_tup,並依次填充原元組的值new _tup(1, 2, 3, 4, 5)l = [1, 2, 3, 4]l.append(5) # 添加元素 5 到原列表的末尾l[1,
  • Python|列表與元組
    列表可以進行增刪改查,但元組一經初始化後就不能再進行修改了,需要對增刪改查進行掌握。列表創建只需要用逗號把不同的數據項分隔開即可,列表用的是「[]」,而元組用的是「()」,通常列表的增刪改查不止一種方法,需要進行對其進行理解。
  • 一文看懂Python列表、元組和字符串操作
    序列1 列表列表(List)是Python中非常重要的內置數據類型。列表由一系列元素組成,所有的元組被包含在一對方括號中。列表被創建將後,可以執行添加、刪除、修改操作。列表中可包含任意的Python數據信息,如字符串、數字、列表、元組等。
  • 【第104講】Python之循環 | 列表 | 元組 | 字典(續)
    吳老的java版《selenium webdriver 實戰寶典》和python版《selenium Webdriver 3.0 自動化測試框架實戰指南
  • python列表、元組、字典、集合的知識點及區別
    概念列表(list):是一組任意類型的值,按照一定順序組合而成的,可變的序列,支持索引、切片、合併、刪除等等操作,它們都是在原處進行修改列表。l=[1,"張三",2]元組(tuple):帶了緊箍咒的列表,元組本身不可變數據類型,沒有增刪改,但可以間接性的修改,元組內可以存儲任意數據類型。t=(1,"張三",2),t=([1,"張三",2],2)集合(set):集合裡面的元素是不可重複的。
  • python中列表(list)和元組(tuple)該如何抉擇?有什麼區別?
    列表(list)和元組(tuple
  • 史上最全的Python數據結構:列表和元組用法總結
    閱讀本文大概需要8分鐘:Python內置了很多有用的數據結構,今天我們先來介紹2大法寶,列表和元組
  • Python基礎篇——關於元組(tuple)和列表(list)區別
    一、前言在Python數據類型中有兩個對象:元組 tuple 和列表 list 。二者寫法和用法十分相似,有的同學就會去網上查找它們之間的區別,查到的無非以下幾種說法:list 是可變的,元組 tuple 是不可變的。由於 tuple 不可變,所以使用 tuple 可以使代碼更安全。等等 ...
  • 10個掌握Python列表,集合,元組的示例
    每個對象都有自己的數據屬性和與之關聯的方法。為了有效和恰當地使用一個對象,我們應該知道如何與它們進行交互。列表、元組和集合是3種重要的對象類型。它們的共同點是,它們被用作數據結構。本文中,我們將看到這些結構如何收集和存儲數據以及我們可以對它們進行的操作。並看到它們之間的異同。讓我們首先簡要解釋一下這些對象是什麼。然後對每個示例進行詳細說明。
  • python編程入門八:列表、元組、字符串的轉換及補充方法
    是不是可以理解了,上面輸出的「[1,2,3]」其實把每一個符號或數字都變成了字符串中的字符,當我們再將它轉換回列表後就能發現每一個符號和數字都被當成了一個列表中的「元素」,好好理解一下。8.4 取最大值方法–max()max()方法的作用是返回一個列表或者元組等集合中的最大值,當然,max()內的參數可以是列表、元組也可以是某些數的集合,非常簡單,舉例說明:a = [2, 4, 7, 4, 5]print(max(a))b = (3, 8, 9, 2, 4)print(max(b))print
  • Python中列表(list),元組(Tuple),字典(Dict)和集合(Set)的比較
    1.1 元素索引列表、元組的索引都是從起始位置0開始的,甚至可以採用負數,例如:>>> list[0]1>>> list[-1]5>>> list[:-1][1, 2, 3, 4]>>> tuple[-1]5>&
  • Python中的元組排序和深度比較
    元組排序的規則(本質上與字符串排序相同):使用==運算符比較每個元組的第n項(從第一個項開始,索引為0);如果它們相等,則對下一項重複這個步驟對於兩個不相等的項,「小於」的項使包含它的元組也「小於」另一個元組如果所有項都相等,則元組相等如果一個元組在步驟1中耗盡了項(一個元組是另一個元組的「子集」),則較短的元組「小於」較長的元組
  • 【翻譯】《利用Python進行數據分析·第2版》第2章(中)Python語法基礎,IPython和Jupyter
    版》第1章 準備工作【翻譯】《利用Python進行數據分析·第2版》第2章(上)Python語法基礎,IPython和Jupyter2.3 Python語法基礎在本節中,我將概述基本的Python概念和語言機制。
  • 面試必問之python列表、元組、字典的區別
    每一個元素被標識一個索引,第一個索引是0,序列的功能都能實現 可變長度,異構以及任意嵌套列表中的元素可以是任意類型,甚至是列表類型,也就是說列表可以嵌套 可變的序列支持索引、切片、合併、刪除等等操作,它們都是在原處進行修改列表 對象引用數組
  • Python tuple元組詳解
    元組(tuple)是 Python 中另一個重要的序列結構,和列表類似,元組也是由一系列按特定順序排序的元素組成。
  • R用戶Python指南:操作列表
    本文為R用戶Python指南系列第3篇,Python代碼主要取自《Python編程:從入門到實踐》第4章,R代碼根據Python代碼複寫。本文使用rmarkdown和prettydoc模板生成格式,代碼塊中#之後的內容為注釋,##之後的內容為代碼輸出結果。本文使用的R包主要為stringr,用於處理字符串,需預先加載。
  • python基礎之元組
    上一節剛說了一個有序列表 List ,現在說另一種有序列表叫元組:tuple 。tuple 和 List 非常類似,但是 tuple 一旦初始化就不能修改。那麼為什麼要有 tuple 呢?那是因為 tuple 是不可變的,所以代碼更安全,所以建議能用 tuple 代替 list 就儘量用 tuple 。
  • 【翻譯】《利用Python進行數據分析·第2版》第3章(下)Python的數據結構、函數和文件
    版》第1章 準備工作【翻譯】《利用Python進行數據分析·第2版》第2章(上)Python語法基礎,IPython和Jupyter【翻譯】《利用Python進行數據分析·第2版》第2章(中)Python語法基礎,IPython和Jupyter【翻譯】《利用Python進行數據分析·第2版》第2章(下)Python語法基礎