bytes and bytearray

scm1911發表於2019-01-06

bytes and bytearray

1 bytes和bytearray的介紹

  • bytesbytearray 是 python3中引入了兩個新型別
  • bytes 是不可變的位元組序列
  • bytearray 是可變的位元組陣列

記憶體中的資料都是二進位制的0和1,並且我們按照位元組的方式邏輯上將這些0和1分成一個一個的位元組(位元組仍然是二進位制的0和1),一個位元組佔 8 位,當一個位元組中的高位是 0, 就按照 ASCII解碼; 如果一個位元組的高位是1, 就不會按照 ASCII編碼表解碼。此時如果不指定編碼的方式(解碼的方式),計算機就不知道如何把這些數字翻譯成正確的字元,由於我們的計算機使用的是中文,那麼計算機就會預設將兩兩位元組組合起來去解碼,但是如果這些數當初不是按照兩兩位元組組合的中字符集編碼的,那麼解碼之後就是亂碼。   

2 字串與bytes

  • 字串字元組成的有序序列,字元可以使用編碼來理解
  • bytes位元組組成的有序的不可變序列
  • bytearray位元組組成的有序的可變序列

3 編碼與解碼

字串 --> bytes(二進位制) 編碼 encode
bytes(二進位制) --> 字串 解碼 decode

3.1 我們先來思考一個例子:

num = "1" 和 num = 1 在計算機中是怎樣的,我們使用文字方式開啟後又是什麼樣子?

字串 num = "1" 以文字方式顯示(也就是人類可讀)

bytes and bytearray

此時的1就是我們人類可見的字串 1

字串 num = "1" 以二進位制方式顯示(也就是計算機可讀)

bytes and bytearray

31 就是 ASCII編碼表中對應的字串1對應的 16 進位制數字

數字 num = 1 以二進位制方式顯示(也就是計算機可讀)

bytes and bytearray

此時的1就是實際在計算機中存在的 16 進位制數字1

數字 num = 1 以文字方式顯示(也就是人類可讀)

bytes and bytearray

SOH 就是 ASCII編碼表中 16 進位制數字對應的字串

通過上面的例子我們可以得出以下結論:

計算機只認得二進位制數字,二進位制的世界裡是一個個位元組,文字的世界裡是一個個字元。
字串要儲存在計算機裡面:
        查表去 --> 轉換為對應的是二進位制數字(也可以理解為16進位制數字) --> 儲存
要將二計算進中存貯的二進位制數字以人類可讀方式檢視(比如通過文字編輯器): 
        查表去 --> 轉換為二進位制數字(也可以理解為16進位制數字)對應的字元 --> 顯示

3.2 encode & decode

字串按照不同的字符集編碼encode返回位元組序列bytes

encode(encoding='utf-8', errors='strict') -> bytes
--------------------------------------------------------------------------------------
In [9]: '中國'.encode(encoding='utf-8', errors='strict')         
Out[9]: b'\xe4\xb8\xad\xe5\x9b\xbd'

位元組序列按照不同的字符集解碼decode返回字串

bytes.decode(encoding="utf-8", errors="strict") -> str
bytearray.decode(encoding="utf-8", errors="strict") -> str
--------------------------------------------------------------------------------------
In [12]: b'\xe4\xb8\xad\xe5\x9b\xbd'.decode(encoding="utf-8", errors="strict")                      
Out[12]: '中國'

編碼和解碼的演示

位元組的世界裡沒有編碼,字串的世界裡才有編碼

# 編碼的過程:我們將字串“中國”編碼為二進位制的bytes
In [1]: "中國".encode()  # 預設編碼使用的是 utf-8 字符集                                        
Out[1]: b'\xe4\xb8\xad\xe5\x9b\xbd'   # 返回的結果中前面有一個'b',說明這不是一個簡單的字串,而是一個bytes(位元組)

# 解碼的過程:我們將二進位制的bytes解碼為字串
In [2]: "中國".encode().decode()                                 
Out[2]: '中國'

如果編碼和解碼的時候使用的不是同一個字符集,那麼就會轉換失敗(使用文字剪輯器開啟的時候就是亂碼)

In [3]: "中國".encode().decode(encoding='gbk')                   
--------------------------------------------------------------------------------------
UnicodeDecodeError              Traceback (most recent call last)
<ipython-input-3-5784dfe3e469> in <module>
----> 1 "中國".encode().decode(encoding='gbk')

UnicodeDecodeError: 'gbk' codec can't decode byte 0xad in position 2: illegal multibyte sequence                                       

我們編碼和解碼使用相同的字符集,就是成功的

In [4]: "中國".encode(encoding='gbk').decode(encoding='gbk')     
Out[4]: '中國'

此時我們再來看看使用utf-8和gbk兩種字符集對字串"中國"進行編碼後的結果有什麼不同

In [6]: "中國".encode(encoding='utf-8')                          
Out[6]: b'\xe4\xb8\xad\xe5\x9b\xbd'   # utf-8字符集三個位元組對應一個漢字

In [7]: "中國".encode(encoding='gbk')  # gbk 字符集兩個位元組對應一個漢字                          
Out[7]: b'\xd6\xd0\xb9\xfa'

4 ASCII 碼

ASCII(American Standard Code for Information Interchange,美國資訊交換標準程式碼)是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,並等同於國際標準ISO/IEC 646。

ASCII

5 bytes

5.1 bytes定義

bytes()     # 空bytes
bytes(int)  # 指定位元組的bytes,被 0 填充
bytes(iterable_of_ints) -> bytes    # [0,255] 的int組成的可迭代物件
bytes(string, encoding[, errors]) -> bytes # 等價與 string,encode()
bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer  # 從一個位元組序列或者buffer複製出一個新的不可變的bytes物件
使用 b 字首定義
    只允許基於ASCII使用字元形式 b'scm7'
    使用16進製表示 b'\x73\x63\x6d\x37'

bytes()

In [13]: s = bytes()                                                                                

In [14]: s                                                                                          
Out[14]: b''

In [17]: s = bytes(0)                                                                               

In [18]: s                                                                                          
Out[18]: b''

bytes(int)

In [15]: s = bytes(5)                                                                               

In [16]: s                                                                                          
Out[16]: b'\x00\x00\x00\x00\x00'   # 由於無法顯示ASCII中16進位制對應的字元,只能用16進位制數字直接顯示

# bytes型別是不可變的
In [19]: s = bytes(5)                                                                               

In [20]: s                                                                                          
Out[20]: b'\x00\x00\x00\x00\x00'   # 注意前面有 'b',說明這是一個bytes,而不是普通的字串

In [21]: s[1] = 10                                                                                  
--------------------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-d8b471273ca8> in <module>
----> 1 s[1] = 10

TypeError: 'bytes' object does not support item assignment

bytes型別是可以解碼的

In [22]: s.decode()                                                                                 
Out[22]: '\x00\x00\x00\x00\x00'  # 注意,前面的 'b' 不見了。說明已經轉為字串型別了(5個字元0)

bytes(iterable_of_ints)

返回bytes, [0,255] 的int組成的可迭代物件


In [23]: s = bytes(range(65,68))       # 65,66,67                                                            

In [24]: s                                                                                          
Out[24]: b'ABC'

In [25]: s = bytes(range(5))    # 0 1 2 3 4                                                               

In [26]: s                                                                                          
Out[26]: b'\x00\x01\x02\x03\x04'    # 由於無法顯示ASCII中16進位制對應的字元,只能用16進位制數字直接顯示

使用 b 字首定義

In [27]: s = b'abc'                                                                                 

In [28]: s                                                                                          
Out[28]: b'abc'

string.encode()

In [30]: x = 'abc'.encode()       # 效果和 b'abc' 是相同的                                                                  

In [31]: x                                                                                          
Out[31]: b'abc'

bytes(string,encoding[,errors])

In [32]: bytes('abc','gbk')                                                                         
Out[32]: b'abc'

bytes(bytes_or_buffer)

從一個位元組序列或者buffer複製出一個新的不可變的bytes物件


In [33]: s1 = b'xxx'                                                                                

In [34]: s1                                                                                         
Out[34]: b'xxx'

In [35]: s2 = bytes(s1)        # 記憶體拷貝                                                                     

In [36]: s2                                                                                         
Out[36]: b'xxx'

檢驗一下對前面的理解

下面的結果是什麼?

s3 = b'\x41\x42\x43'
s3.decode()

5.2 bytes操作

bytes和str型別類似,都是不可變型別,所以方法很多都一樣。只不過bytes的方法,輸入是bytes,輸出是bytes

replace() 位元組的替換

b'abcdef'.replace(b'f',b'k')
b'abc'.find(b'b')
--------------------------------------------------------------------------------------
>>> b'abcdef'.replace(b'f',b'k')
'abcdek'

find() 位元組的查詢

找到返回索引值,否則返回 -1

b'abc'.find(b'b')
--------------------------------------------------------------------------------------
>>> b'abc'.find(b'a')
0
>>> b'abc'.find(b'b')
1
>>> b'abc'.find(b'c')
2
>>> b'abc'.find(b'd')
-1    # 找不到返回 -1

bytes.fromhex(string) 返回的是bytes,string是16進位制字串表示法

類方法,從16進位制字串構建bytes

string必須是2個字元的16進位制的形式,'6162 6a 6b',空格將被忽略

bytes.fromhex('6162 09 41   42   43')
--------------------------------------------------------------------------------------
In [41]: bytes.fromhex('6162 09 41   42   43')                                                                                                                    
Out[41]: b'ab\tABC'
# 其實這裡我們可以想到,一個大的數字可以轉變為多個位元組(bytes序列) 
# 同時多個位元組也可以用來描述一個較大的數字

hex() 和 bytes.fromhex(string)是相反的,返回的是字串

返回16進製表示法表示的字串,相當於 直接取出來了記憶體中的資料,並顯示

'abc'.encode().hex()
--------------------------------------------------------------------------------------
print('abc'.encode().hex()) -> 616263

In [60]: bytes.fromhex('616163')                                                                    
Out[60]: b'aac'

In [61]: b'abc'.hex()                                                                               
Out[61]: '616263'

索引

返回該位元組對應的數,int型別

b'abcdef'[2] 
--------------------------------------------------------------------------------------  
In [62]: b'abcdef'[2]     # ASCII 表中 c 對應的十進位制數就是 99                                                                          
Out[62]: 99

In [63]: str(b'abcdef'[2])                                                                          
Out[63]: '99'

6 bytearray

6.1 bytearray定義

bytearray()       # 空bytearray
bytearray(int)    # 指定位元組的bytearray,被 0 填充
bytearray(iterable_of_ints) -> bytearray  # [0, 255]的int組成的可嗲帶物件
bytearray(string, encoding [,errors]) -> bytearray   # 近似string.encode(),不過返回可變物件
bytearray(bytes_or_buffer)   # 從一個位元組序列或這buffer複製出一個新的可變的bytearray物件

注意:
b 字首定義的型別是bytes型別,是不可變
bytearray 字首定義的型別是bytearray型別,是可變

6.2 bytearray操作

bytearray 的操作方法和byte型別的操作方法相同

replace() 替換

bytearray(b'abcedf').replace(b'f',b'k')
--------------------------------------------------------------------------------------

In [64]: bytearray(b'abcedf').replace(b'f',b'k')                                                    
Out[64]: bytearray(b'abcedk')

bytearray.fromhex(string)

類方法,string必須是2個字元的16進位制的形式,'6162 6a 6b',空格將被忽略

bytearray.fromhex('6162 09 41 4231')  
--------------------------------------------------------------------------------------
In [69]: bytearray.fromhex('6162 09 41 4231')                                                       
Out[69]: bytearray(b'ab\tAB1')

hex()

返回十六進位制表示的字串

bytearray('abc'.encode()).hex()
--------------------------------------------------------------------------------------
print(bytearray('abc'.encode()).hex()) -> 616263

索引

返回該位元組對應的數,int型別

bytearray(b'abcdef')[2]
--------------------------------------------------------------------------------------
In [70]: bytearray(b'abcdef')[2]                                                                    
Out[70]: 99     # ASCII 表中 c 對應的十進位制數就是 99

append()

b.append(item)
尾部追加一個元素

In [71]: b = bytearray()                                                                            

In [72]: b.append(97)                                                                               

In [73]: b                                                                                          
Out[73]: bytearray(b'a')
In [77]: b.append(98)  

In [78]: b                                                                                          
Out[78]: bytearray(b'ab')

insert()

在指定的索引位置插入元素
b.insert(index, item)


In [79]: b.insert(1,99)         # 在索引為1的位置插入 99 (b'c')                                                                    

In [80]: b                                                                                          
Out[80]: bytearray(b'acb')

extend(iterable_of_ints)

b.extend(iterable_of_ints)
將一個可迭代的整數集合追加到當前bytearray


In [100]: b = bytearray()                                                                           

In [101]: b                                                                                         
Out[101]: bytearray(b'')

In [102]: b.extend(range(65,67))                                                                    

In [103]: b                                                                                         
Out[103]: bytearray(b'AB')

In [104]: b.extend(range(97,110))                                                                   

In [105]: b                                                                                         
Out[105]: bytearray(b'ABabcdefghijklm')

pop(index=-1)

從指定的縮影上移除元素,預設是從尾部移除

# 預設是移除末尾的元素
In [106]: b                                                                                         
Out[106]: bytearray(b'ABabcdefghijklm')

In [107]: b.pop()                                                                                   
Out[107]: 109

In [108]: b                                                                                         
Out[108]: bytearray(b'ABabcdefghijkl')  # 最後的m不見了

# 移除指定索引的元素
In [110]: b                                                                                         
Out[110]: bytearray(b'ABabcdefghijkl')


In [118]: b'ABabcdefghijkl'.hex()                                                                   
Out[118]: '41426162636465666768696a6b6c'

In [111]: b.pop(-2)                                                                                 
Out[111]: 107

In [112]: b                                                                                         
Out[112]: bytearray(b'ABabcdefghijl')   # k(\x6b  == 107)沒有了

In [113]: b.pop(0)                                                                                  
Out[113]: 65

In [114]: b                                                                                         
Out[114]: bytearray(b'Babcdefghijl')  # A(\x61 == 65)沒有了

remove(velue)

找到第一個value,並移除,找不到直接報異常 ValueErrror

b.remove(66)

注意:
上述方法都需要使用int型別,數值在[0,255]

reverse()

反轉bytearray,注意此操作是就地修改

In [120]: b                                                                                         
Out[120]: bytearray(b'Babcdefghijl')

In [121]:                                                                                           

In [121]: b.reverse()                                                                               

In [122]: b                                                                                         
Out[122]: bytearray(b'ljihgfedcbaB')

clear()

清空bytearray

In [126]: b                                                                                         
Out[126]: bytearray(b'ljihgfedcbaB')

In [127]: b.clear()                                                                                 

In [128]: b                                                                                         
Out[128]: bytearray(b'')

7. int 和 bytes 互轉

int.from_bytes(bytes, byteorder)

將一個位元組陣列表示成整數

In [131]: i = int.from_bytes(b'abc','big')    # big 指定是大頭位元組序,也就是 ---> 這樣的方向                                                 
In [132]: i                                                                                         
Out[132]: 6382179  # 十進位制表示的

In [133]: hex(i)                                                                                    
Out[133]: '0x616263   # 十六進位制表示的

int.to_bytes(length,byteorder)

byteorder: 位元組序
將一個整數表達成一個指定長度的位元組陣列

i = int.from_bytes(b'abc','big')
print(i,hex(i))
--------------------------------------------------------------------------------------
6382179 0x616263

print(i.to_bytes(3,'big'))
--------------------------------------------------------------------------------------
b'abc'

8. 思考題

記憶體中有一個數字。請問踏實什麼型別的?

我不知道,那要看你怎麼理解它,你要是把他當作是整形,就是int,
如果當作是字串,就要去查表解碼為字串,
如果你要是當他是 bytes理解,它就是一個個位元組

9. 總結

當我們開啟一段記憶體後,看到的是二進位制的數字,只有給定了資料型別後我們才知道他們表示的是什麼,
離開了資料型別,他們除了是0和1之外什麼都不是。
所以,資料一點要有型別。沒有型別我們將無法理解。

本文連結:https://www.cnblogs.com/shichangming/p/10230564.html

相關文章