Python的資料結構(四)bytes和bytearray

LittleHuang950620發表於2018-08-11

1. bytes

1.1 bytes的概念

它們倆是python3 中引入的兩個新的型別。

bytes 表示位元組序列,是一個不可變的資料型別。
bytearray 表示位元組陣列,是一個可變的資料型別。

定義這兩種型別的資料,在記憶體中開闢的空間都得是連續的。

聽著是很懵逼的,得解釋一下:

通常在常用的ASCII、utf-8 和unicode 編碼中,像 a 這樣一個英文字元,在記憶體中佔一個位元組。(一個漢字在ASCII和unicode編碼裡佔兩個位元組,在utf-8 編碼中佔三個位元組,太麻煩就不說了)

一個位元組有八位,也就是八個數字,也叫8個bit 。

計算機中的最小儲存單位就是bit,bit是二進位制的,所以計算機中的資料全都是0和1,沒有其他的數字。

還是以一個字元 a 為例,在ASCII編碼表中:
這裡寫圖片描述

只要看十進位制那列和字元那列就行,別的對於我們理解沒什麼用。

找到小寫字母 a ,它對應的十進位制數字是97(十六進位制數字就是16),如果轉化成二進位制數字,就是 0110 0001。

所以這個字元,小寫字母 a , 在記憶體中的形式就是 0110 0001。但是一定要注意,如果有兩個位元組在記憶體中是 0110 0001,它不一定代表的是小寫字母 a。因為記憶體中的0和1填在不同的bit上,形成了一個個位,八個位組成了一個位元組,但是不知道這個位元組的資料型別,所以不能確定這個位元組的意思。況且,就算知道這個位元組代表的是字串型別,如果不知道用的是哪種編碼,也是不知道的。

可以看到上面的ASCII碼一共有128個,從0000 0000 到0111 1111,正好128個,剩下的128個叫做擴充套件ASCII 表。

1.2 bytes的相關函式

1.2.1 bytes的定義

bytes()
定義空位元組,空位元組前面有個 b 來區分。

a = bytes()
a
b''

bytes(int)
直接定義位元組的個數,就是創造了幾個空位元組,但是每個位元組裡面是空的。

a = bytes(3)
a
b'\x00\x00\x00'
# 這是ASCII 0 ,不是阿拉伯數字0,阿拉伯數字0是十進位制48,十六進位制30.

bytes(iteratable)
創造可迭代物件的元素個數相等的位元組,然後把每個元素填充進去。
注意,必須是整型int 的可迭代物件。

a = bytes(range(15))
a
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e'
# 看ASCII表,9 是\t,10是\n,13是\r。這就是用ASCII表來解碼的位元組。
# 前面那些 00 01 02 03,也有自己的意思,但是沒辦法用字元表示出來,所以就用它的十六進位制表示法表示出來。

bytes(byte) or bytes(‘string’,encode)
造一個位元組序列,還是得用位元組。

a = bytes(range(3))
a 
b'\x00\x01\x02'

b = a
b
b'\x00\x01\x02'

c = bytes(b'fuck')

或者用b字首,這樣也可以,總之裡面得是整數,可迭代物件(裡面元素為整數),或者是位元組型別的。

d = bytes('fuck','utf-8')
d
b'fuck'

這樣定義是,把裡面的字串,用utf-8這種編碼來解碼返回相應個位元組的位元組資料。其實返回的不應該是b’fuck’,應該是 \x66\x75\x63\x6b ,這樣一串,只不過在ipython等工具中,把它優化成了,便於人類理解的形式。

e = b'fuck'
f = b'\x61\x62\x63'

不過一般定義位元組序列型別的值,都用上面的方法直接定義。

1.2.2 bytes的“修改”

bytes 和 str 一樣,都是不可修改的型別,所以,所謂的修改,都是創造一個新的bytes 和str。

二者的用法也類似。

b'fuck'.replace(b'f',b's')
b'suck'
# 替換位元組

b'fuck'.find(b'u')
1
# 查詢某個位元組的索引號

bytes.fromhex(‘hexstr’)
這個意思是,用一串由十六進位制數字組成的字串,來表示位元組。

bytes.fromhex('53 75 63 6b 20 4d 79 20 44 69 63 6b')
b'Suck My Dick'
# 注意,在括號內,空格是無效的,相當於沒輸入,所以想打出空格,就要打ASCII編碼表裡空格對應的編碼,也就是20。

再倒著回來,一個字串,用encode() 變成位元組,然後再用hex() 取它的十六進位制表達,得出的和上面輸入的是一樣的。

'Suck My Dick'.encode().hex()
'5375636b204d79204469636b'

位元組序列,稱為序列是有序的,所以也可以用索引

'Suck My Dick'.encode()[0]
83
# 這裡返回的是十進位制的數字,換成十六進位制,也就是我們上面輸入的S 的編碼53。

2. bytearray

叫做位元組陣列,是可變的,有序的。

我的理解是,這個bytearray 型別,是好多bytes 組合在一起。

還有一點要注意的是,b字首,代表的是bytes 型別;而bytearray 型別,表示方法是bytearray(b’ ‘)。

bytearray 型別的操作,和bytes 型別的操作基本差不多。

2.1 bytearray 的定義

bytearray( )
空的位元組陣列

bytearray(int)
創造一個有int個位元組的位元組陣列,所有位元組都被十六進位制的0x0填充,也就是被null 填充。

bytearray(interatable_of_int)
把一個由int 組成的可迭代物件裡的元素,依次取出,放在位元組陣列的位元組中。返回值為bytearray(b’ ‘)。

bytearray(‘string’,encode)
把字串string,按encode 指定的編碼來解碼,然後把解碼之後的十六進位制數字,放入位元組中,組成位元組陣列。

bytearray(bytes_or_buffer)
從一個位元組序列或者是buffer中,複製一個新的bytearray,buffer是啥,我暫時還不知道呢,知道了補上。

2.2 bytearray 的修改

用法都和以前一樣,就不贅述了。

bytearray.replace(old,new)
替換,雖然說bytearray 可變,但是這個替換不是就地修改,返回值是修改之後的,一個新的bytearray 。

bytearray.find(sub)
尋找目標的子位元組,然後返回索引號。

bytearray.fromhex(‘string’)
把一個字串(這個字串必須是兩個字元的十六進位制形式,例如 ‘5375636b204d79204469636b’ ),放在一個bytearray 裡。

bytearray(‘string’,encode()).hex()
先把一個字串,以某種編碼形式,轉換成bytearray 型別的資料,然後再用十六進位制表示出來。

bytearray(bytes)[index]
返回索引為index 的位元組的十進位制數字,型別為int。

因為是可變的,所以bytearray 可以就地修改,修改方法和list 的修改方法類似。
bytearray.append(int)
bytearray.insert(index,int)
bytearray.extend(iteratable_of_int)
bytearray.pop()
bytearray.remove(value)
bytearray.clear()
bytearray.reverse()

2.3 整型和位元組序列的互相轉化

如果無論字串str 還是整型int ,在記憶體中都是以位元組來儲存,那麼二者之間可以通過bytes 互相轉化。

int.from_bytes(bytes,byteorder)

int.from_bytes(b'fuck','big')
1718969195

以上的意思就是,把字串 ‘fuck’,通過解碼,以整型int(十進位制)表示出來。

後面的byteorder 是指大小端模式。

int.to_bytes(length,byteorder)
把一個整型的值,轉換成位元組。

1718969195.to_bytes(4,'big')
b'fuck'

length 是指定有多少個字元,只能多不能少,多了話,多餘的字元會被十六進位制的0填充,少了的話會報錯。

相關文章