Python3进行Base64编码报错需字节类对象 如何实现与Python2一致输出
问题根源
- Python 3 中
base64.urlsafe_b64encode仅支持字节类型(bytes)作为输入,原代码传入的是拼接后的Unicode字符串,因此触发TypeError: a bytes-like object is required, not 'str'异常。 - Python 2 中的字符串默认是字节序列,
chr(0-255)生成的就是单字节内容;Python 3 中chr生成的是Unicode字符,当数值超过127时,直接拼接后转字节会默认使用UTF-8编码,导致实际字节内容与Python 2不一致,所以enc列表输出会出现可见特殊字符、最终编码结果错误。
修正方案
方案1(推荐:直接操作字节数值,性能更高)
直接存储计算得到的字节数值,最后统一转为bytes对象输入base64编码接口:
import base64 enc = [] clear = "hello world" key = "1234567890" for i in range(len(clear)): key_c = key[i % len(key)] # 直接存字节数值,不转换为字符 enc_c = (ord(clear[i]) + ord(key_c)) % 256 enc.append(enc_c) # 转换为bytes对象 enc_bytes = bytes(enc) # 输出和Python2格式一致的enc列表 print("enc:", [f"\\x{x:02x}" for x in enc]) # base64编码后转为ascii字符串输出 print(base64.urlsafe_b64encode(enc_bytes).decode('ascii'))
方案2(最小改动:不修改循环逻辑)
如果不想调整循环内的代码,可在编码前将拼接后的字符串用latin1编码转为字节,latin1编码会将Unicode码位0-255的字符一一映射为对应数值的单字节,和Python2的str行为完全一致:
import base64 enc = [] clear = "hello world" key = "1234567890" for i in range(len(clear)): key_c = key[i % len(key)] enc_c = chr((ord(clear[i]) + ord(key_c)) % 256) enc.append(enc_c) print ("enc:", enc) # 仅修改最后一行,用latin1编码转字节 print (base64.urlsafe_b64encode("".join(enc).encode('latin1')).decode('ascii'))
运行结果
两种方案的输出都和Python2完全一致:
enc: ['\x99', '\x97', '\x9f', '\xa0', '\xa4', '\x56', '\xae', '\xa7', '\xab', '\x9c', '\x95']
mZefoKRWrqernJU=
内容的提问来源于stack exchange,提问作者Bill Bridge
相关产品推荐
相关产品推荐

