You can use the struct module to convert between integers and representation as bytes. In your case, to convert from a Python integer to two bytes and back, you'd use:
>>> import struct
>>> struct.pack('>H', 12345)
'09'
>>> struct.unpack('>H', '09')
(12345,)
The first argument to struct.pack and struct.unpack represent how you want you data to be formatted. Here, I ask for it to be in big-ending mode by using the > prefix (you can use < for little-endian, or = for native) and then I say there is a single unsigned short (16-bits integer) represented by the H.
Other possibilities are b for a signed byte, B for an unsigned byte, h for a signed short (16-bits), i for a signed 32-bits integer, I for an unsigned 32-bits integer. You can get the complete list by looking at the documentation of the struct module.
Coming from a primarily C++ background.
Is there anyway to get around bytes() restriction of only allowing single byte data? I have a single, 2 byte number in my list of single byte numbers that I need serialized in order to send through serial.Serial.write(). I'm not sure how to approach this exactly given pythons inherency to obscure addresses and such unlike a language like C++/C.
And this is all assuming I'm interpreting the error messages properly. Thanks
You can use the struct module to convert between integers and representation as bytes. In your case, to convert from a Python integer to two bytes and back, you'd use:
>>> import struct
>>> struct.pack('>H', 12345)
'09'
>>> struct.unpack('>H', '09')
(12345,)
The first argument to struct.pack and struct.unpack represent how you want you data to be formatted. Here, I ask for it to be in big-ending mode by using the > prefix (you can use < for little-endian, or = for native) and then I say there is a single unsigned short (16-bits integer) represented by the H.
Other possibilities are b for a signed byte, B for an unsigned byte, h for a signed short (16-bits), i for a signed 32-bits integer, I for an unsigned 32-bits integer. You can get the complete list by looking at the documentation of the struct module.
For example, using Big Endian encoding:
int.from_bytes(my_bytes, byteorder='big')
python - Convert int to 2 bytes of Big-Endian - Stack Overflow
Python 2,3 Convert Integer to "bytes" Cleanly - Stack Overflow
network programming - How to change one byte int to two bytes in Python? - Stack Overflow
Convert an integer to a 2 byte Hex value in Python - Stack Overflow
Answer 1:
To convert a string to a sequence of bytes in either Python 2 or Python 3, you use the string's encode method. If you don't supply an encoding parameter 'ascii' is used, which will always be good enough for numeric digits.
s = str(n).encode()
- Python 2: http://ideone.com/Y05zVY
- Python 3: http://ideone.com/XqFyOj
In Python 2 str(n) already produces bytes; the encode will do a double conversion as this string is implicitly converted to Unicode and back again to bytes. It's unnecessary work, but it's harmless and is completely compatible with Python 3.
Answer 2:
Above is the answer to the question that was actually asked, which was to produce a string of ASCII bytes in human-readable form. But since people keep coming here trying to get the answer to a different question, I'll answer that question too. If you want to convert 10 to b'10' use the answer above, but if you want to convert 10 to b'\x0a\x00\x00\x00' then keep reading.
The struct module was specifically provided for converting between various types and their binary representation as a sequence of bytes. The conversion from a type to bytes is done with struct.pack. There's a format parameter fmt that determines which conversion it should perform. For a 4-byte integer, that would be i for signed numbers or I for unsigned numbers. For more possibilities see the format character table, and see the byte order, size, and alignment table for options when the output is more than a single byte.
import struct
s = struct.pack('<i', 5) # b'\x05\x00\x00\x00'
You can use the struct's pack:
In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'
The ">" is the byte-order (big-endian) and the "I" is the format character. So you can be specific if you want to do something else:
In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'
In [13]: struct.pack("B", 1)
Out[13]: '\x01'
This works the same on both python 2 and python 3.
Note: the inverse operation (bytes to int) can be done with unpack.
I want to write a number to a binary file in two bytes. Any tips on how to do this? I guess I can manually do some math to figure out what each byte of the short would be, but I'm wondering if there's a better way. I'm new to python.
Thanks all.
You have to do similar to calculation on paper.
You have to loop and get modulo 256, and divide by 256, and repeat it on result.
def int_to_bytes(val):
data = []
while val > 0:
b = val % 256
val = val // 256
data.insert(0, b)
return bytes(data)
print( int_to_bytes(127) ) # b'\x7f'
print( int_to_bytes(3000) ) # b'\x0b\xb8'
print( int_to_bytes(985983) ) # b'\x0f\x0b\x7f'
print( int_to_bytes(184553088) ) # b'\x0b\x00\x0e\x80'
EDIT:
Similar code you can use to convert to other systems, 8, 2, etc.
Using 2 instead of 256 you can get bits
def int_to_bits(val):
data = []
while val > 0:
b = val % 2
val = val // 2
char = chr(ord('0') + b)
data.insert(0, char)
return ''.join(data)
print( int_to_bits(127) ) # 1111111
print( int_to_bits(3000) ) # 101110111000
print( int_to_bits(985983) ) # 11110000101101111111
print( int_to_bits(184553088) ) # 1011000000000000111010000000
And exactly the same for 8
def int_to_octals(val):
data = []
while val > 0:
b = val % 8
val = val // 8
char = chr(ord('0') + b)
data.insert(0, char)
return ''.join(data)
print( int_to_octals(127) ) # 177
print( int_to_octals(3000) ) # 5670
print( int_to_octals(985983) ) # 3605577
print( int_to_octals(184553088) ) # 1300007200
For values bigger than 10 it can be simpler to use list with digits
digit = '0123456789ABCDEF'
char = digit[b]
def int_to_hexs(val):
digit = '0123456789ABCDEF'
data = []
while val > 0:
b = val % 16
val = val // 16
char = digit[b]
data.insert(0, char)
return ''.join(data)
print( int_to_hexs(127) ) # 7F
print( int_to_hexs(3000) ) # BB8
print( int_to_hexs(985983) ) # F0B7F
print( int_to_hexs(184553088) ) # B000E80
As you mentioned above :
def int_to_2bytes(b):
if b > 0 or b < 65335: # if b > 0 and b <= 65335: (corrected)
return bytes([b//256, b-(b//256*256)])
This can be rewritten as:
def int_to_2bytes(b):
if b > 0 and b < 256**2:
return bytes([(b//256**1)-(b//256**2*256),
(b//256**0)-(b//256**1*256)])
For int_to4bytes :
def int_to_4bytes(b):
if b > 0 and b < 256**4:
return bytes([(b//256**3)-(b//256**4*256),
(b//256**2)-(b//256**3*256),
(b//256**1)-(b//256**2*256),
(b//256**0)-(b//256**1*256)])
Following the same pattern, for int_to_nbytes :
def int_to_nbytes(b, n):
if b > 0 and b < 256**n:
return bytes([b//256**(n-1-i) - b//256**(n-i)*256 for i in range(n)])
print(int_to_nbytes(3000, 4)) # b'\x00\x00\x0b\xb8'
print(int_to_nbytes(3000, 8)) # b'\x00\x00\x00\x00\x00\x00\x0b\xb8'