Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了
文章目錄
- 前言
- 數據類型轉化
- int -> str
- 使用 str() 函數
- 使用 format() 函數
- 使用 hex() 轉換成16進制形式
- 使用 bin() 轉換成2進制形式
- str -> int
- 使用 int() 進行各進制數字轉換
- 什么是bytes
- int -> bytes
- 使用 to_bytes() 轉換成定長bytes
- 使用 bytes() 函數把int數組轉成bytes
- 使用 struct.pack() 函數把數字轉化成bytes
- bytes -> int
- 使用 from_bytes() 把 bytes 轉化成int
- 使用 struct.unpack() 把 bytes 轉化成int
- str 和 bytes
- 使用 encode() 函數完成 str -> bytes
- 使用 decode() 函數完成 bytes -> str
- 假如使用了 str() 函數
- 轉化表格
- 總結
前言
數據類型轉換是個很基礎的操作,很多語言中都要做這些轉換,例如前一段時間剛剛總結了《C/C++中string和int相互轉換的常用方法》,python 自從分離出 python3 版本之后,str 和 bytes 兩個類型弄蒙了一大票人,在這兩種類型的轉換上我可是花了不少時間,記住一點,別隨隨便便使用 str() 函數,很多數據使用 str() 變成字符串之后再想恢復可就難了。
本文所有示例均在 Python 3.7.5 上測試,Python2 已經被我拋棄了,我來試著把常見的轉換都放到一起,把踩過的坑拿來開心一下,如果有些常用的類型轉換這里沒有的話,也歡迎小伙伴們提出來,我將持續補充,好了,可以開始了。
數據類型轉化
數字中除了整數,還有浮點數、復數等,但是 int 是最常見的類型,所有轉換中的數字只涉及 int 數字類型。
int -> str
使用 str() 函數
num = 10 val = str(10) print(type(val), val)#<class 'str'> 10使用 format() 函數
num = 10 val = '{0}'.format(num) print(type(val), val)#<class 'str'> 10使用 hex() 轉換成16進制形式
num = 10 val = hex(num) print(type(val), val)#<class 'str'> 0xa使用 bin() 轉換成2進制形式
num = 10 val = bin(num).replace('0b','') print(type(val), val)#<class 'str'> 1010str -> int
這個轉換比較專一,只使用 int() 函數就可以了,這個函數實際上有兩個參數,第二個參數表示進制,默認是10進制,你可以改成2進制或者16進制,甚至是3進制、5進制等等
使用 int() 進行各進制數字轉換
val = int('10') print(type(val), val)val = int('0xa', 16) print(type(val), val) val = int('a', 16) print(type(val), val)val = int('0b1010', 2) print(type(val), val) val = int('1010', 2) print(type(val), val)val = int('101', 3) print(type(val), val)val = int('60', 5) print(type(val), val)# 結果均為 <class 'int'> 10使用 int() 函數的時候要主要注意一點,如果提供的字符串不能轉換成指定進制的數字,那么會報異常,就像下面這樣,所以在使用這個函數的時候最好放到 try 語句中。
val = int('128', 2)''' Traceback (most recent call last):File "D:\python\convert\convert.py", line 41, in <module>val = int('128', 2) ValueError: invalid literal for int() with base 2: '128' [Finished in 0.1s with exit code 1] '''什么是bytes
在列舉 bytes 相關的轉化前,我們來先認識一下這個類型,在 Python3 中 int、str、bytes 類型的變量實際上都是一個 “類” 的對象,而 bytes 相比 str 而言更接近底層數據,也更接近存儲的形式,它其實是一個字節的數組,類似于 C 語言中的 char [],每個字節是一個范圍在 0-255 的數字。
bytes 其實就是這樣一連串的數字,計算機世界所有的信息都可以用這樣一串數字表示,一幅畫,一首歌,一部電影等等,如果對編碼感興趣可以看看這篇《簡單聊聊01世界中編碼和解碼這對磨人的小妖兒》,現在清楚bytes是什么了,我們可以看看和它相關的轉化了。
int -> bytes
使用 to_bytes() 轉換成定長bytes
num = 4665 val = num.to_bytes(length=4, byteorder='little', signed=False) print(type(val), val)#<class 'bytes'> b'9\x12\x00\x00'這段代碼就是把數字 4665 轉化成定長的4個字節,字節序為小端,我們來簡單看一下是怎么轉換的:
上面我們提到 bytes 類型一串 0-255 范圍的數字,4665 肯定超出了這個范圍,可以先轉化成256進制,就變成了 <18><57>,也就是 4665 = 18 * 256 + 57,我們發現兩個字節就能存儲這個數字,一個18,一個57,要想組成4個字節的數組需要補充兩個空位,也就是補充兩個0,這時就涉及到一個排列順序,是 [0,0,18,57] 還是 [57, 18, 0, 0] 呢,這就是函數參數中的字節序 byteorder,little 表示小端,big 表示大端,這里選擇的小端 [57, 18, 0, 0] 的排列。
看到這里可能會迷糊,好像和結果不一樣啊,其實這只是一個表示問題,57 的 ASCII 碼對應這個字符 ‘9’,18 表示成16進制就是 ‘0x12’,這里寫成 b’9\x12\x00\x00’ 只是便于識別而已,實際上內存存儲的就是 [57, 18, 0, 0] 這一串數字對應的二進制編碼 ‘00111001 00010010 00000000 00000000’。
使用 bytes() 函數把int數組轉成bytes
參考上面的生成的數組,可以通過數組生成相同的結果
num_array = [57, 18, 0, 0] val = bytes(num_array) print(type(val), val)#<class 'bytes'> b'9\x12\x00\x00'使用 struct.pack() 函數把數字轉化成bytes
num = 4665 val = struct.pack("<I", num) print(type(val), val)#<class 'bytes'> b'9\x12\x00\x00'這里的 "<I" 表示將一個整數轉化成小端字節序的4字節數組,其他的類型還有:
| > | 大端序 |
| < | 小端序 |
| B | uint8類型 |
| b | int8類型 |
| H | uint16類型 |
| h | int16類型 |
| I | uint32類型 |
| i | int32類型 |
| L | uint64類型 |
| l | int64類型 |
| s | ascii碼,s前帶數字表示個數 |
bytes -> int
明白了上面的轉化過程,從 bytes 轉化到 int 只需要反著來就行了
使用 from_bytes() 把 bytes 轉化成int
bys = b'9\x12\x00\x00' val = int.from_bytes(bys, byteorder='little', signed=False) print(type(val), val)#<class 'int'> 4665使用 struct.unpack() 把 bytes 轉化成int
bys = b'9\x12\x00\x00' val = struct.unpack("<I", bys) print(type(val), val)#<class 'tuple'> (4665,)str 和 bytes
前面的這些轉化還算清晰,到了字符串str 和字節串 bytes,就開始進入了混沌的狀態,這里會出現各種編碼,各種亂碼,各種報錯,牢記一點 str 到 bytes 是編碼過程,需要使用 encode() 函數, bytes 到 str 是解碼過程,需要使用 decode() 函數,請勿使用 str 函數,否則后果自負。
使用 encode() 函數完成 str -> bytes
s = '大漠孤煙直qaq' val = s.encode('utf-8') print(type(val), val)# <class 'bytes'> b'\xe5\xa4\xa7\xe6\xbc\xa0\xe5\xad\xa4\xe7\x83\x9f\xe7\x9b\xb4qaq'使用 decode() 函數完成 bytes -> str
bys = b'\xe5\xa4\xa7\xe6\xbc\xa0\xe5\xad\xa4\xe7\x83\x9f\xe7\x9b\xb4qaq' val = bys.decode('utf-8') print(type(val), val)# <class 'str'> 大漠孤煙直qaq假如使用了 str() 函數
從上面來看字符串和字節串的轉化蠻簡單的,甚至比整數的轉化都要簡單,但是你如果把一個 bytes 變量用 str() 轉化成字符串,你就得手動來處理了,這個函數寫過n次了,暫時還沒找到好的處理辦法。
bys = b'\xe5\xa4\xa7\xe6\xbc\xa0\xe5\xad\xa4\xe7\x83\x9f\xe7\x9b\xb4qaq' s = str(bys) print(type(s), s) #<class 'str'> b'\xe5\xa4\xa7\xe6\xbc\xa0\xe5\xad\xa4\xe7\x83\x9f\xe7\x9b\xb4qaq'def str2bytes(str_content):result_list = [];pos = 0str_content = str_content.replace("\\n", "\n").replace("\\t", "\t").replace("\\r", "\r")content_len = len(str_content)while pos < content_len:if str_content[pos] == '\\' and pos + 3 < content_len and str_content[pos + 1] == 'x':sub_str = str_content[pos + 2: pos + 4]result_list.append(int(sub_str, 16))pos = pos + 4else:result_list.append(ord(str_content[pos]))pos = pos + 1return bytes(result_list)val = str2bytes(s[2:-1]) print(type(val), val)# <class 'bytes'> b'\xe5\xa4\xa7\xe6\xbc\xa0\xe5\xad\xa4\xe7\x83\x9f\xe7\x9b\xb4qaq'什么時候會遇到這種情況,就是有些數據是以 bytes 的形式給的,但是經過中間人復制轉發變成了字節流形式的字符串,格式還不統一,有些已經翻譯成了字符,有些還保留了0x或者\x形式,這時就要手工處理了。
轉化表格
上面的轉化方式和解釋穿插在一起有些亂,這里總結一個表格,便于今后拿來就用
| int | str | str(10)、'{0}'.format(10) | 10 => '10' |
| int | str(16進制) | hex(10) | 10 => '0xa' |
| int | str(2進制) | bin(10).replace('0b','') | 10 => '1010' |
| str | int | int('10') | '10' => 10 |
| str(16進制) | int | int('0xa', 16) | '0xa' => 10 |
| str(2進制) | int | int('1010', 2) | '1010' => 10 |
| int | bytes | num.to_bytes(length=4, byteorder='little', signed=False) | 4665 => b'9\x12\x00\x00' |
| int | bytes | struct.pack("<I", 4665) | 4665 => b'9\x12\x00\x00' |
| bytes | int | int.from_bytes(b'9\x12\x00\x00', byteorder='little', signed=False) | b'9\x12\x00\x00' => 4665 |
| bytes | int | struct.unpack("<I", b'9\x12\x00\x00') | b'9\x12\x00\x00' => 4665 |
| int[] | bytes | bytes([57, 18, 0, 0]) | [57, 18, 0, 0] => b'9\x12\x00\x00' |
| bytes | int[] | [x for x in b'9\x12\x00\x00'] | b'9\x12\x00\x00' => [57, 18, 0, 0] |
| str | bytes | '美好'.encode('utf-8') | '美好' => b'\xe7\xbe\x8e\xe5\xa5\xbd' |
| str | bytes | bytes('美好', 'utf-8') | '美好' => b'\xe7\xbe\x8e\xe5\xa5\xbd' |
| bytes | str | b'\xe7\xbe\x8e\xe5\xa5\xbd'.decode('utf-8') | b'\xe7\xbe\x8e\xe5\xa5\xbd' => '美好' |
| bytes | bytes(無\x) | binascii.b2a_hex(b'\xe7\xbe\x8eqaq') | b'\xe7\xbe\x8eqaq' => b'e7be8e716171' |
| bytes | bytes(有\x) | binascii.a2b_hex(b'e7be8e716171') | b'e7be8e716171' => b'\xe7\xbe\x8eqaq' |
| bytes | str(hex) | b'\xe7\xbe\x8eqaq'.hex() | b'\xe7\xbe\x8eqaq' => 'e7be8e716171' |
| str(hex) | bytes | bytes.fromhex('e7be8e716171') | 'e7be8e716171' => b'\xe7\xbe\x8eqaq' |
總結
- Python3 對字符串和二進制數據流做了明確的區分,不會以任意隱式的方式混用 str 和 bytes
- bytes 類型是一種比特流,它的存在形式是 01010001110 的形式,需要解碼成字符才容易被人理解
- struct 模塊中的 pack() 和 unpack() 可以實現任意類型和 bytes 之間的轉換
- binascii.b2a_hex 和 binascii.a2b_hex 可以實現16進制 bytes 的不同形式轉換,不過轉換前后長度發生了變化
==>> 反爬鏈接,請勿點擊,原地爆炸,概不負責!<<==
初識不知曲中意,再聞已是曲中人
總結
以上是生活随笔為你收集整理的Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 震撼!世界从10亿光年到0.1飞米(ZT
- 下一篇: 替代 Elasticsearch,TDe