Tarick Welling
Tarick Welling

Reputation: 3265

How to convert bytes byte by byte to signed int

I have a bytes element. My word size is 1, a single byte. The contents can be b'\xff\xff\x01' meaning [-1, -1, 1].

I want to convert it to the int representation from the bytes form. Logically my attempt is:

ints = [int.from_bytes(j, byteorder='little', signed=True) for j in b'\xff\xff\x01']

TypeError: cannot convert 'int' object to bytes

However this does not work as the for j in bytes() converts a bytes element directly into an int j. This is however an unsigned conversion, I need signed. How do I convert my bytes, byte by byte, into a signed integer.

Upvotes: 3

Views: 2095

Answers (4)

realSamy
realSamy

Reputation: 209

I don't know if it still helps! I saw your comment just now :)

ints = [int.from_bytes(bytes([j]), byteorder='little', signed=True) for j in b'\xff\xff\x01']

Upvotes: 0

Karl Knechtel
Karl Knechtel

Reputation: 61635

Another way, using Numpy:

>>> import numpy as np
>>> np.frombuffer(b'\xff\xff\x01', dtype=np.int8)
array([-1, -1,  1], dtype=int8)

Upvotes: 1

Karl Knechtel
Karl Knechtel

Reputation: 61635

However this does not work as the for j in bytes() converts a bytes element directly into an int j.

As you've noticed, the bytes is already an iterable over integer values. If we have a lot of data, it would be more memory efficient to keep the bytes as is, and convert values on demand. We can simply do the math to convert the unsigned interpretation of a byte to the corresponding signed representation:

def signed_byte(b):
    return b - 256 if b >= 128 else b

And wrap the indexing process:

def get_signed(data, index):
    return signed_byte(data[index])

If we want or need to do all the conversion ahead of time, that feeds directly into the list comprehension:

ints = [signed_byte(b) for b in b'\xff\xff\x01']

On the other hand, we can reframe the question: to get a bytes object from the original data as a subsequence (like how it worked in 2.x), we can use a 1-element slice instead; or we can wrap the int value into a new bytes. The former will be tricky to adapt to the original code, but the latter is trivial:

ints = [int.from_bytes(bytes([b]), byteorder='little', signed=True) for b in b'\xff\xff\x01']

Upvotes: 3

Tarick Welling
Tarick Welling

Reputation: 3265

This solution is idiotic but at least it works.

data = b'\xff\xff\x01'
result = list(struct.unpack('b' * len(data), data))

Upvotes: 0

Related Questions