Python 基礎系列--你是否真的了解標準數據類型
來自專欄 Python 學習之道
紙上得來終覺淺,絕知此事要躬行。
數字、字元串、列表、元組、字典、集合是 Python 的六種標準數據類型,每一個 Python 程序都必然有這些數據類型的應用,如果會熟練使用數據類型,基本上 Python 編程已經會了一半了。
首先來看一下 Python 標準數據類型的分類:
這裡就有必要了解下什麼是可變數據類型,什麼是不可變數據類型,這對理解使用函數是否會改變傳入的參數的值非常重要,也可避免因數據類型導致的程序 bug。
不可變數據類型
不可變數據類型是:變數所指向的內存地址處的值是不可以被改變的。你可能不太理解上面這句話,那麼接著往下看。
python 世界裡,一切皆為對象(object),任何變數都是對象的引用。因此不用擔心 Python 有類似於 C/C++ 中指針的複雜問題。以不可變數據類型中的整數(int)為例:
隨便選取一個整數,例如 18 ,在 python 中 id(18) 來獲得 18 在內存中的地址。>>> id(18)1409838640>>> x=18>>> id(x)1409838640>>> y=18>>> id(y)1409838640>>> z=18>>> id(z)1409838640>>>
如上所示,在某一次 Python 程序執行的過程中,變數 18 在內存中的地址為 1409838640,你定義 x = 18; y = 18; z = 18;無論定義多少個變數,只要它的值為 18 ,他們地址均為 1409838640,在 python 內部執行垃圾回收之前,地址 1409838640 處的值一直都是 18 ,不可被改變。
有人可能有疑問了:變數 x 是整數類型,直接給 x 賦值 19 不就改改變了 x 的值了,為什麼說整數是不可變數據類型 ?
答:確實改變了 x 的值,但是請注意,Python 中一切皆為對象,任何變數都是對象的引用,因此當 x = 18 時,x 是對象 18 的引用;給 x 賦值 19 時,x 是新對象 19 的引用,x 的地址變為整數 19 的內存地址,內存地址1409838640 處的值仍是 18,請看下面的交互環境輸出結果。
>>> x = 19>>> id(x)1409838672>>> id(19)1409838672>>> id(18)1409838640>>> id(y)1409838640>>> id(z)1409838640
可以看出執行 x = 19 後變數 x 的地址就是 19 的地址 1409838672,變數 y 和 z 仍指向整數 18 。內存中對於整數 18 只佔用了一個地址,而不管有多少個引用指向了它,都只有一個地址值,只是有一個引用計數會記錄指向這個地址的引用到底有幾個而已。當變數 x,y,z 都指向 18 時,18 的引用計數就是 3,18 在內存中只有一份,當所有的變數都不指向 18 時,垃圾回收程序就會在適當的時機收回 18 , 收回 18 後,18 這個對象在內存中就中不存在了。
之所以說 x 是不可變數據類型,指的是 x 引用的地址處的值是不能被改變的,也就是 1409838640 地址處的值在沒被垃圾回收之前一直都是 18,不能改變,如果要把 x 賦值為 19 ,那麼只能將 x 引用的地址從 1409838640 變為 1409838672,相當於 x = 19 這個賦值操作又創建了一個對象,即 19 這個對象。所以說整數這個數據類型是不可變的,如果想對整數類型的變數再次賦值,在內存中相當於又創建了一個新的對象,而不再是之前的對象。其他不可變類型也是同樣的道理。
注意:元組是個特例,值相同的元組的地址可能不同,因為它的本質是只讀的列表。
可變數據類型
可變數據類型是:變數所指向的內存地址處的值是可以被改變的。
以可變數據類型中的列表 list 為例,如果不知道 python 的列表也沒關係,本文後面會介紹。
先看一段互動式環境中的輸出>>> x=[1,2,3]>>> id(x)2429731524424>>> x=[1,2,3]>>> id(x)2429731548808
可以看出,對變數 x 執行兩次同樣的賦值操作,變數 x 的地址卻不是同一個,這與不可變數據類型有明顯的區別,其實兩次賦值操作在內存中創建了兩個不同的對象,因此對於可變類型,具有同樣值的對象是不同的對象,他們彼此是獨立的。
接下來我們來改變列表值,看一看變數地址的變化情況 。
>>> x=[1,2,3]>>> id(x)2429731548808>>> y=[1,2,3]>>> id(y)2429731524424>>> z=[1,2,3]>>> id(z)2429731565704>>> x.append("a")>>> x[1, 2, 3, a]>>> y[1, 2, 3]>>> z[1, 2, 3]>>> id(x)2429731548808>>> id(y)2429731524424>>> id(z)2429731565704>>>del x[2]>>>x[1,2,a]>>>id(x)2429731548808
我們首先定義了三個變數 x,y,z ,分別賦值為 [1,2,3],但他們是不同的對象,因此在內存中的地址也不一樣。當對變數 x 指向的列表增加一個元素 "a" 時,變數 x 的值發生的變化,但內存中的地址還和以前一樣,變數 y ,z沒有做任何操作,他們的值和地址都不變,後面刪除列表中的第三個元素 x[2],同樣發現 x 的地址仍沒有變化。
因此可變數據類型是說對一個變數所指向的內存地址處的值是可以被變的,值的變化並不會引起新建對象,即地址是不會變的。
理解了可變數據類型和不可變數據類型,相信你非常容易解釋如下現象:
>>> x=y=z=1>>> x=2>>> x,y,z #這裡,y 與 z 的值沒有被改變(2, 1, 1)>>> a=b=c=[1,2,3]>>> a.append(a)>>> a,b,c #這裡,b 與 c 的值卻被改變([1, 2, 3, a], [1, 2, 3, a], [1, 2, 3, a])
上一篇文章介紹了字元串及編碼,本文介紹一下 Python 里最常用的 4種標準數據類型:列表,元組,字典、集合:
1.列表(list)
列表類似於 C 語言中的數組,是一種線性的數據結構,與 C 語言的數組不同地是,Python 中的列表可以存儲不同的數據類型,列表內部也可以嵌套列表。
在 Python中,使用 "[]" 來定義一個列表,元素之間使用 "," 隔開。>>> list1 = [zhuang, xiao0.h,赤色彗星,]>>> list2 = [0,1,2,abcd,[1,2,3]]>>> list3 = ["上路", "中路", "下路"]>>> list4 = [list1,list3]>>> print(list1);[zhuang, xiao0.h, 赤色彗星]>>> print(list2);[0, 1, 2, abcd, [1, 2, 3]]>>> print(list3);[上路, 中路, 下路]>>> print(list4);[[zhuang, xiao0.h, 赤色彗星], [上路, 中路, 下路]]
查詢:訪問列表元素、遍歷
使用下標索引來訪問列表中的值,同樣你也可以使用方括弧的形式截取字元,使用 for 循環遍歷列表,如下所示:
(赤色彗星, [赤色彗星])>>> list1[0]zhuang>>> list1[1]xiao0.h>>> list1[1:3][xiao0.h, 赤色彗星]>>> for item in list1:... print(item)...zhuangxiao0.h赤色彗星>>> for i,item in enumerate(list1): # 如果需要使用下標就使用 enumerate(list),不推薦使用 len(list)... print(i,item)...0 zhuang1 xiao0.h2 赤色彗星>>> for i in list4:... print(i)...[zhuang, xiao0.h, 赤色彗星][上路, 中路, 下路]
列表的增,刪,改。
>>> list1[zhuang, xiao0.h, 赤色彗星]>>> list1.append("somenzz") #增加值為 somenzz 的元素,放在最後位置>>> list1[zhuang, xiao0.h, 赤色彗星, somenzz]>>>>>> list1.append("somenzz1") #增加值為 somenzz1 的元素,放在最後位置>>> list1.insert(0,"somenzz") #增加值為 somenzz 的元素,放在第一位>>> list1[somenzz, zhuang, xiao0.h, 赤色彗星, somenzz, somenzz1]>>> list1.remove(somenzz1) #刪除第一個值為 somenzz1 的元素 >>> list1[somenzz, zhuang, xiao0.h, 赤色彗星, somenzz]>>> list1[4]=xxxxxxxx #修改第五個元素的值為 xxxxxxxx >>> list1[somenzz, zhuang, xiao0.h, 赤色彗星, xxxxxxxx]>>> list1.pop() #刪除最後一個元素xxxxxxxx>>> list1[somenzz, zhuang, xiao0.h, 赤色彗星]>>> list1.pop(0) #刪除指定元素,刪除下標為 0 的元素 ,即第一個元素somenzz>>> list1[zhuang, xiao0.h, 赤色彗星]>>> del list1[1] #刪除指定元素,刪除下標為 1 的元素 ,即第二個元素>>> list1[zhuang, 赤色彗星]>>>
Python列表函數&方法
請使用 help(list) 來獲取 Python 提供的所有關於列表的函數或方法。
>>>help(list)
2.元組(tuple)
Python 的元組與列表類似,不同之處在於元組的元素不能修改。元組使用小括弧,列表使用方括弧。元組創建很簡單,只需要在括弧中添加元素,並使用逗號隔開即可。
>>> a=("上路","中路","下路","中路",)>>> a[0]上路>>> a[3]中路>>> a[0:3](上路, 中路, 下路)>>> a[:](上路, 中路, 下路, 中路)>>> a.count("中路")2>>> type(a)<class tuple>>>> help(tuple)Help on class tuple in module builtins:class tuple(object) | tuple() -> empty tuple | tuple(iterable) -> tuple initialized from iterables items | | If the argument is a tuple, the return value is the same object. | | Methods defined here: | | __add__(self, value, /) | Return self+value....... | | count(...) | T.count(value) -> integer -- return number of occurrences of value | | index(...) | T.index(value, [start, [stop]]) -> integer -- return first index of value. | Raises ValueError if the value is not present.
請注意:元組的元素不能修改,其實是指元組中的元素所指向的內存地址是不可更改的,如果元組的元素是可變數據類型,則該元素的值是可以改變的。請看下面的例子:
>>> b=("a","b",[1,2,3])>>> id(b)2429731461592>>> id(b[-1])2429737198920>>> b[-1].append(4)>>> b(a, b, [1, 2, 3, 4])>>> id(b)2429731461592>>> id(b[-1]) # b[-1] 就是 b[2]2429737198920>>>
從上面的結果可以看出元組 b 的第三個元素的值 [1,2,3] 變為了 [1,2,3,4] 但 b 的地址和 b[2] 的地址都沒有變化。
3.字典(dict)
提到字典,我們會想到中華字典,英語詞典,通過給定的單詞(key),查找其含義(value),在字典里,要查找的單詞(key)在字典里是唯一的,但不同的單詞的含義(value)可能相同。Python 里的字典就是鍵值對(key-value)組成的集合,且可存儲任意類型對象。定義一個字典非常簡單:使用一對花括弧{}括起,鍵值對之間使用「,」分隔。如:
>>> dict = { hello:你好,world:世界,} #定義一個字典dict>>> dict{hello: 你好, world: 世界}>>> dict[hello]你好>>> len(dict) #計算字典元素個數,即鍵的總數。2>>>str(dict) #輸出字典,以可列印的字元串表示。"{hello: 你好, world: 世界}"
字典值可以是任何的 python 對象,既可以是標準的對象,也可以是用戶定義的,但鍵不行。兩個重要的點需要記住:
(1)不允許同一個鍵出現兩次。創建時如果同一個鍵被賦值兩次,後一個值會被記住,如下實例:>>> dict = { hello:你好,world:世界,hello:world} #鍵hello的值被更新為world>>> dict{hello: world, world: 世界}
(2)鍵必須不可變,可以用數字,字元串或元組充當,而用列表就不行,即:鍵必須為不可變數據類型。如下實例:
>>> d = { a:1,b:2, [a]:abc} #鍵是列表,會報錯Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unhashable type: list
遍歷字典:
>>> d = { a:1, b:2, c:3, d:4, e:5, f:6 } #定義一個字典>>> for key,value in d.items(): #d.items()方法返回一個鍵值對的元組(key,value)... print(key,value)...a 1b 2c 3d 4e 5f 6>>> for key in d: #以鍵來取值... print(key,d[key]) #python強制縮進,與上一行比有4個空格...a 1b 2c 3d 4e 5f 6>>>
修改字典:
>>> d = { a:1, b:2, c:3, d:4, e:5, f:6 }>>> d[b]=b>>> d{a: 1, b: b, c: 3, d: 4, e: 5, f: 6}
刪除字典元素:可以刪除單一的元素,也可以一次性刪除所有元素,清空字典,顯式地刪除一個字典用del命令,如下所示:
>>> del d[b] #刪除鍵b>>> d #刪除鍵b後{a: 1, c: 3, d: 4, e: 5, f: 6}>>> d.clear() #清空字典 >>> d{}>>> del d #刪除字典>>> d #刪除字典後,字典d已不存在Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name d is not defined
字典的內置方法
help(dict)
4.集合(set)
集合 set 是一個無序不重複元素集,基本功能包括關係測試和消除重複元素.。集合對象還支持 union (聯合), intersection (交), difference (差) 和 sysmmetric difference (對稱差集)等數學運算。
在 Python 中可以使用 」x in set」 來判斷x是否在集合中,使用 」len(set)」 來獲取集合元素個數,使用 」for x in set」 來遍歷集合中的元素。但由於集合不記錄元素位置,因此集合不支持獲取元素位置和切片等操作。 下面舉例說明:>>> x=set(abcd) #創建集合x由單個字元組成>>> y=set([a,bc,d,10]) #創建集合y,由列表的元素組成>>> x,y #列印x,y({a, b, d, c}, {a, d, 10, bc})>>> x & y #取交集 {a, d}>>> x|y #取並集{c, bc, d, 10, b, a}>>> x-y #差集,表示x里有,y里沒有的{b, c}>>> x^y #對稱差集(項在x或y中,但不會同時出現在二者中){bc, c, 10, b}
集合操作也可以用以去重元素:
>>> a = [11,22,33,44,11,22]>>> b = set(a)>>> bset([33, 11, 44, 22])
集合的基本操作有:
函數說明s.add(x)# 添加一項s.update([10,37,42])# 在s中添加多項s.remove(H)#使用remove()可以刪除一項:len(s)#set的長度x in s#測試x是否是s的成員x not in s#測試x是否不是s的成員s.issubset(t)#相當於s <= t測試是否s中的每一個元素都在t中s.issuperset(t)#相當於s >= t測試是否t中的每一個元素都在s中s.union(t)# 相當於s | t 返回一個新的set包含s和t中的每一個元素s.intersection(t)#相當於s&t 返回一個新的set包含s和t中的公共元素s.difference(t)#相當於s-t返回一個新的set包含s中有但是t中沒有的元素s.symmetric_difference(t)#相當於s^t返回一個新的set包含s和t中不重複的元素s.copy()#返回集合s的一個淺複製s.discard(x)#如果在 set 「s」中存在元素 x, 則刪除s.pop()#刪除並且返回 set 「s」中的一個不確定的元素, 如果為空則引發 KeyErrors.clear()#刪除set 「s」中的所有元素
詳細信息請推薦使用 help(set) 命令獲取。
總結:紙上得來終覺淺,絕知此事要躬行,請初學者多敲代碼,多實踐,才能深入理解。
(完)
文章首發公眾號,如果覺得這篇文章對您有幫助,請關注公眾號 somenzz 獲取最新消息或推薦給需要的朋友。
http://weixin.qq.com/r/6igJEUzEexEErQhy9334 (二維碼自動識別)
推薦閱讀: