在代码中兼容地使用字符串和类字节对象在 Python 2 和 Python 2 中运行3 [英] Using strings and byte-like objects compatibly in code to run in both Python 2 & 3
问题描述
我正在尝试修改下面显示的代码,该代码在 Python 2.7.x 中有效,因此它在 Python 3.x 中也可以保持不变.但是,我遇到了以下问题,我无法在第一个函数 bin_to_float()
中解决,如下面的输出所示:
I'm trying to modify the code shown far below, which works in Python 2.7.x, so it will also work unchanged in Python 3.x. However I'm encountering the following problem I can't solve in the first function, bin_to_float()
as shown by the output below:
float_to_bin(0.000000): '0'
Traceback (most recent call last):
File "binary-to-a-float-number.py", line 36, in <module>
float = bin_to_float(binary)
File "binary-to-a-float-number.py", line 9, in bin_to_float
return struct.unpack('>d', bf)[0]
TypeError: a bytes-like object is required, not 'str'
我试图通过在调用 struct.unpack()
之前添加一个 bf = bytes(bf)
来解决这个问题,但这样做产生了它自己的 类型错误
:
I tried to fix that by adding a bf = bytes(bf)
right before the call to struct.unpack()
, but doing so produced its own TypeError
:
TypeError: string argument without an encoding
所以我的问题是有可能解决这个问题并实现我的目标吗?如果是这样,如何?最好是在两种版本的 Python 中都可以使用的方式.
So my questions are is it possible to fix this issue and achieve my goal? And if so, how? Preferably in a way that would work in both versions of Python.
以下是适用于 Python 2 的代码:
Here's the code that works in Python 2:
import struct
def bin_to_float(b):
""" Convert binary string to a float. """
bf = int_to_bytes(int(b, 2), 8) # 8 bytes needed for IEEE 754 binary64
return struct.unpack('>d', bf)[0]
def int_to_bytes(n, minlen=0): # helper function
""" Int/long to byte string. """
nbits = n.bit_length() + (1 if n < 0 else 0) # plus one for any sign bit
nbytes = (nbits+7) // 8 # number of whole bytes
bytes = []
for _ in range(nbytes):
bytes.append(chr(n & 0xff))
n >>= 8
if minlen > 0 and len(bytes) < minlen: # zero pad?
bytes.extend((minlen-len(bytes)) * '0')
return ''.join(reversed(bytes)) # high bytes at beginning
# tests
def float_to_bin(f):
""" Convert a float into a binary string. """
ba = struct.pack('>d', f)
ba = bytearray(ba)
s = ''.join('{:08b}'.format(b) for b in ba)
s = s.lstrip('0') # strip leading zeros
return s if s else '0' # but leave at least one
for f in 0.0, 1.0, -14.0, 12.546, 3.141593:
binary = float_to_bin(f)
print('float_to_bin(%f): %r' % (f, binary))
float = bin_to_float(binary)
print('bin_to_float(%r): %f' % (binary, float))
print('')
推荐答案
我的方法与 @metatoaster 的答案不同.我只是修改了 int_to_bytes
以使用并返回一个 bytearray
:
I had a different approach from @metatoaster's answer. I just modified int_to_bytes
to use and return a bytearray
:
def int_to_bytes(n, minlen=0): # helper function
""" Int/long to byte string. """
nbits = n.bit_length() + (1 if n < 0 else 0) # plus one for any sign bit
nbytes = (nbits+7) // 8 # number of whole bytes
b = bytearray()
for _ in range(nbytes):
b.append(n & 0xff)
n >>= 8
if minlen > 0 and len(b) < minlen: # zero pad?
b.extend([0] * (minlen-len(b)))
return bytearray(reversed(b)) # high bytes at beginning
这似乎在 Python 2.7.11 和 Python 3.5.1 下无需任何其他修改即可工作.
This seems to work without any other modifications under both Python 2.7.11 and Python 3.5.1.
请注意,我用 0
而不是 '0'
进行零填充.我没有做太多测试,但这肯定是你的意思吗?
Note that I zero padded with 0
instead of '0'
. I didn't do much testing, but surely that's what you meant?
这篇关于在代码中兼容地使用字符串和类字节对象在 Python 2 和 Python 2 中运行3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!