Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了

前言

数据类型转换是个很基础的操作,很多语言中都要做这些转换,例如前一段时间刚刚总结了《C/C++中string和int相互转换的常用方法》,python 自从分离出 python3 版本之后,strbytes 两个类型弄蒙了一大票人,在这两种类型的转换上我可是花了不少时间,记住一点,别随随便便使用 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'> 1010

str -> 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 中 intstrbytes 类型的变量实际上都是一个 “类” 的对象,而 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字节数组,其他的类型还有:

参数含义
>大端序
<小端序
Buint8类型
bint8类型
Huint16类型
hint16类型
Iuint32类型
iint32类型
Luint64类型
lint64类型
sascii码,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 = 0
    str_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 + 4
        else:
            result_list.append(ord(str_content[pos]))
            pos = pos + 1
    return 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形式,这时就要手工处理了。

转化表格

上面的转化方式和解释穿插在一起有些乱,这里总结一个表格,便于今后拿来就用

源类型目标类型方式结果
intstrstr(10)'{0}'.format(10)10 => '10'
intstr(16进制)hex(10)10 => '0xa'
intstr(2进制)bin(10).replace('0b','')10 => '1010'
strintint('10')'10' => 10
str(16进制)intint('0xa', 16)'0xa' => 10
str(2进制)intint('1010', 2)'1010' => 10
intbytesnum.to_bytes(length=4, byteorder='little', signed=False)4665 => b'9\x12\x00\x00'
intbytesstruct.pack("<I", 4665)4665 => b'9\x12\x00\x00'
bytesintint.from_bytes(b'9\x12\x00\x00', byteorder='little', signed=False)b'9\x12\x00\x00' => 4665
bytesintstruct.unpack("<I", b'9\x12\x00\x00')b'9\x12\x00\x00' => 4665
int[]bytesbytes([57, 18, 0, 0])[57, 18, 0, 0] => b'9\x12\x00\x00'
bytesint[][x for x in b'9\x12\x00\x00']b'9\x12\x00\x00' => [57, 18, 0, 0]
strbytes'美好'.encode('utf-8')'美好' => b'\xe7\xbe\x8e\xe5\xa5\xbd'
strbytesbytes('美好', 'utf-8')'美好' => b'\xe7\xbe\x8e\xe5\xa5\xbd'
bytesstrb'\xe7\xbe\x8e\xe5\xa5\xbd'.decode('utf-8')b'\xe7\xbe\x8e\xe5\xa5\xbd' => '美好'
bytesbytes(无\x)binascii.b2a_hex(b'\xe7\xbe\x8eqaq')b'\xe7\xbe\x8eqaq' => b'e7be8e716171'
bytesbytes(有\x)binascii.a2b_hex(b'e7be8e716171')b'e7be8e716171' => b'\xe7\xbe\x8eqaq'
bytesstr(hex)b'\xe7\xbe\x8eqaq'.hex()b'\xe7\xbe\x8eqaq' => 'e7be8e716171'
str(hex)bytesbytes.fromhex('e7be8e716171')'e7be8e716171' => b'\xe7\xbe\x8eqaq'

总结

  • Python3 对字符串和二进制数据流做了明确的区分,不会以任意隐式的方式混用 strbytes
  • bytes 类型是一种比特流,它的存在形式是 01010001110 的形式,需要解码成字符才容易被人理解
  • struct 模块中的 pack()unpack() 可以实现任意类型和 bytes 之间的转换
  • binascii.b2a_hexbinascii.a2b_hex 可以实现16进制 bytes 的不同形式转换,不过转换前后长度发生了变化

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

初识不知曲中意,再闻已是曲中人

  • 44
    点赞
  • 153
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论
### 回答1: 可以使用Python内置的hex()函数将bytes类型转换为16进制。具体方法如下: 1. 将bytes类型转换为十六进制字符串: hex_str = bytes_obj.hex() 其bytes_obj是bytes类型的对象。 2. 将十六进制字符串转换为整数: int_val = int(hex_str, 16) 其,16表示字符串解析为十六进制数。 3. 将整数转换为十六进制字符串: hex_val = hex(int_val) 最终得到的hex_val就是bytes类型转换为十六进制后的结果。 ### 回答2: Pythonbytes类型是一个字节序列,可以存储二进制数据,例如图像、音频、视频等。在实际开发,经常需要将bytes类型转换为16进制字符串,这样可以方便地查看和处理二进制数据。 Python提供了两种将bytes类型转换为16进制字符串的方法,分别是使用binascii模块和使用字符串encode()方法。 1. 使用binascii模块 binascii模块是Python标准库的一个模块,提供了许多二进制数据和十六进制字符串之间的转换功能。使用binascii模块将bytes类型转换为16进制字符串的方法如下: ```python import binascii bytes_data = b'\x12\x34\x56\x78' hex_data = binascii.hexlify(bytes_data).decode('utf-8') print(hex_data) ``` 上述代码,首先导入binascii模块,然后定义一个bytes类型的数据bytes_data。接下来使用binascii的hexlify()函数将bytes_data转换为16进制字符串,并使用decode()方法将结果转换为utf-8编码的字符串。最后将结果打印出来即可。 2. 使用字符串encode()方法 除了使用binascii模块,Python还提供了另一种将bytes类型转换为16进制字符串的方法,即使用字符串encode()方法。使用encode()方法将bytes类型转换为16进制字符串的方法如下: ```python bytes_data = b'\x12\x34\x56\x78' hex_data = ''.join('{:02X}'.format(b) for b in bytes_data) print(hex_data) ``` 上述代码,首先定义一个bytes类型的数据bytes_data。接下来使用''.join()方法以及格式化字符串bytes_data的每个字节转换为2位的16进制字符串。最后将结果打印出来即可。 无论是使用binascii模块还是使用字符串encode()方法,都可以将bytes类型转换为16进制字符串,根据具体需要选择合适的方法即可。 ### 回答3: Pythonbytes类型是一个包含8位字节序列的不可变序列,常用来表示二进制数据。由于计算机所有数据在存储时都是以二进制形式存储的,因此bytes类型的数据处理非常重要。其bytes类型的数据可以转换成16进制的形式,以便于后续的加密、校验等操作。下面通过示例来说明如何将bytes类型的数据转换为16进制。 首先,我们可以使用binascii模块的hexlify()和unhexlify()函数来进行转换。 将bytes数据转换为16进制形式A: import binascii s = b'Hello World!' h = binascii.hexlify(s) print(h) 输出: b’48656c6c6f20576f726c6421’ 将16进制数据转换为bytes形式B: import binascii h = b'48656c6c6f20576f726c6421' s = binascii.unhexlify(h) print(s) 输出: b'Hello World!' 以上是使用binascii模块的方法,我们还可以使用Python自带的字节序列的转换函数 bytes.hex() 和 bytes.fromhex() 来进行转换。 将bytes数据转换为16进制形式C: s = b'Hello World!' h = s.hex() print(h) 输出: ‘48656c6c6f20576f726c6421’ 将16进制数据转换为bytes形式D: h = '48656c6c6f20576f726c6421' s = bytes.fromhex(h) print(s) 输出: b'Hello World!' 需要注意的是,C和D两种方法只适用于Python3,Python2没有hex()和fromhex()函数。 总结: 以上是Pythonbytes类型转换为16进制的几种常用方法,不同的方法具有不同的适用场景,需要根据实际情况选择合适的转换方式。同时,需要注意Python2与Python3的差异,避免在使用造成不必要的麻烦。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlbertS

常来“玩”啊~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值