關於我
一個有思想的程序猿,終身學習實踐者,目前在一個創業團隊任team lead,技術棧涉及Android、Python、Java和Go,這個也是我們團隊的主要技術棧。
Github:https://github.com/hylinux1024
微信公眾號:終身開發者(angrycode)
數組類型是各種編程語言中基本的數組結構了,本文來盤點下Python
中各種“數組”類型的實現。
list
tuple
array.array
str
bytes
bytearray
其實把以上類型都說成是數組是不准確的。這里把數組當作一個廣義的概念,即把列表、序列、數組都當作array-like
數據類型來理解。
注意本文所有代碼都是在Python3.7
中跑的^_^
0x00 可變的動態列表list
list
應該是Python
最常用到的數組類型了。它的特點是可變的、能動態擴容,可存儲Python
中的一切對象,使用時不用指定存儲的元素的類型。
使用非常簡單
>>> arr = ["one","two","three"]
>>> arr[0]
'one'
# 動態擴容
>>> arr.append(4)
>>> arr
['one', 'two', 'three', 4]
# 刪除一個元素
>>> del arr[2]
>>> arr
['one', 'two', 4]
0x01 不可變的tuple
tuple
的操作與list
類似。它的特點是不可變,不能擴容,可存儲Python
中的一切對象,使用時不用指定存儲的元素的類型。
>>> t = 'one','two',3
>>> t
('one', 'two', 3)
>>> t.append(4)
AttributeError: 'tuple' object has no attribute 'append'
>>> del t[0]
TypeError: 'tuple' object doesn't support item deletion
tuple
可以使用+
運算符,這個運算將創建一個新的tuple
對象用於存儲數據。
>>> t+(1,)
('one', 'two', 3, 1)
>>> tcopy = t+(1,)
>>> tcopy
('one', 'two', 3, 1)
>>> id(tcopy)
4604415336
>>> id(t)
4605245696
可以看出tuple
執行+
運算符之后兩個對象的地址是不一樣
0x02 array.array
如果在Python
中要用到其它語言中類似“數組”的數據結構,就需要用到array
模塊了。它的特點是可變的、存儲相同類型的數值,不能存儲對象。
因為array
在使用的時候要指定元素數據類型,因此它比list
和tuple
都有比較高效空間性能。
# 使用時指定元素數據類型為`float`
>>> arr = array.array('f', (1.0, 1.5, 2.0, 2.5))
>>> arr
array('f', [1.0, 1.5, 2.0, 2.5])
# 修改一個元素
>>> arr[1]=12.45
>>> arr
array('f', [1.0, 12.449999809265137, 2.0, 2.5])
# 刪除一個元素
>>> del arr[2]
>>> arr
array('f', [1.0, 12.449999809265137, 2.5])
# 增加一個元素
>>> arr.append(4.89)
>>> arr
array('f', [1.0, 12.449999809265137, 2.5, 4.889999866485596])
# 如果將一個字符串類型數據存儲到一個浮點數的數組將會報錯
>>> arr[0]='hello'
TypeError: must be real number, not str
array
中元素的數據類型可以參考下表
Type code | C Type | Python Type |
---|---|---|
'b' | signed char | int |
'B' | unsigned char | int |
'u' | Py_UNICODE | Unicode character |
'h' | signed short | int |
'H' | unsigned short | int |
'i' | signed int | int |
'I' | unsigned int | int |
'l' | signed long | int |
'L' | unsigned long | int |
'q' | signed long long | int |
'Q' | unsigned long long | int |
'f' | float | float |
'd' | double | float |
0x03 字符串序列str
Python3
中使用str
對象來表示一個文本字符序列(看,這跟Java
中的字符串String
是多么相似呢)。它的特點不可變的Unicode
字符序列。
在str
中它的每一個元素都是字符串對象。
>>> s ='123abc'
>>> s
'123abc'
>>> s[0]
'1'
>>> s[2]
'3'
# 字符串是不可變的序列,不能刪除其中的元素
>>> del s[1]
TypeError: 'str' object doesn't support item deletion
# 要對字符串進行操作,可以轉化成list
>>> sn = list(s)
>>> sn
['1', '2', '3', 'a', 'b', 'c']
>>> sn.append(9)
>>> sn
['1', '2', '3', 'a', 'b', 'c', 9]
# 字符串中的元素也是字符串對象
>>> type(s[2])
<class 'str'>
>>> type(s)
<class 'str'>
str
對象也可以執行+
操作,它也會生成一個新對象用於存儲。
>>> s2 = s+'33'
>>> s2
'123abc33'
>>> id(s2)
4605193648
>>> id(s)
4552640416
0x04 bytes
bytes
對象用於存儲字節序列,它的特點是不可變存儲,可存儲0-256的數值。
>>> b = bytes([0,2,4,8])
>>> b[2]
4
>>> b
b'\x00\x02\x04\x08'
>>> b[0]=33
TypeError: 'bytes' object does not support item assignment
>>> del b[0]
TypeError: 'bytes' object doesn't support item deletion
0x05 bytearray
bytearray
對象與bytes
類似,用於存儲字節序列。它的特點是可變的,能動態擴容的字節數組。
>>> ba = bytearray((1,3,5,7,9))
>>> ba
bytearray(b'\x01\x03\x05\x07\t')
>>> ba[1]
3
# 刪除一個元素
>>> del ba[1]
>>> ba
bytearray(b'\x01\x05\x07\t')
>>> ba[0]=2
>>> ba[0]
2
# 添加一個元素
>>> ba.append(6)
# 只能添加字節
>>> ba.append(s)
TypeError: 'str' object cannot be interpreted as an integer
>>> ba
bytearray(b'\x02\x05\x07\t\x06')
# 字節的范圍是0-256
>>> ba[2]=288
ValueError: byte must be in range(0, 256)
bytearray
可以轉化成bytes
對象,但效率不是很高。
# bytearray轉成bytes將生成一個新對象
>>> bn = bytes(ba)
>>> id(bn)
4604114344
>>> id(ba)
4552473544
0x06 各個類型相互轉化
tuple->list
>>> tuple(l)
('a', 'b', 'c')
list->tuple
>>> t
('a', 'b', 'c')
>>> list(t)
['a', 'b', 'c']
str->list
>>> l = list('abc')
>>> l
['a', 'b', 'c']
list->str
>>> l
['a', 'b', 'c']
>>> ''.join(l)
'abc'
str->bytes
>>> s = '123'
>>> bytes(s)
TypeError: string argument without an encoding
>>> bytes(s,encoding='utf-8')
b'123'
# 或者使用str的encode()方法
>>> s.encode()
b'123'
bytes->str
>>> b = b'124'
>>> b
b'124'
>>> type(b)
<class 'bytes'>
>>> str(b,encoding='utf-8')
'124'
# 或使用bytes的decode()
>>> b.decode()
'124'
0x07 總結
這些數據類型都是Python
自帶的,在實際開發中應該根據具體需求選擇合適的數據類型。例如當要存儲的元素類型是多種多樣的,那么就應該使用list
或者tuple
。而array.array
相對來說擁有較好的空間性能,但它只能存儲單一類型。
我相信在很多業務場景中list
或tuple
是可以滿足需求的,只是其它數據結構也要有所了解,在我們做一些基礎組件時,會考慮數據結構的性能,或者閱讀他人的代碼時,能做到心中有數。