Doing a bitwise operation on bytes
Asked Answered
E

3

30

I got two objects, a and b, each containing a single byte in a bytes object.

I am trying to do a bitwise operation on this to get the two most significant bits (big-endian, so to the left).

a = sock.recv(1)
b = b'\xc0'
c = a & b

However, it angrily spits a TypeError in my face.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'bytes' and 'bytes'

Is there any way I can perform an AND operation on the two bytes without having to think of the host system's endianness?

Englut answered 23/3, 2014 at 16:47 Comment(3)
bytes is defined as an immutable sequence of integers, meaning it's a list-like (basically a const char[]). Doing a bitwise & on a list-like wouldn't really be sensical.Colombi
When each bytes object only contains a single byte, then endianness is meaningless.Coif
If you have a large byte string, it will be more efficient to use c = (int.from_bytes(a, 'big') & int.from_bytes(b, 'big')).to_bytes(max(len(a), len(b)), 'big').Swann
C
25

A bytes sequence is an immutable sequence of integers (like a tuple of numbers). Unfortunately, bitwise operations are not defined on them—regardless of how much sense it would make to have them on a sequence of bytes.

So you will have to go the manual route and run the operation on the bytes individually. As you only have a single byte each, it’s really simple to do so though. For the same reason you also don’t need to care about endianness, as that’s only applicable when talking about multiple bytes.

So, you could do it like this:

>>> a, b = b'\x12', b'\x34'
>>> bytes([a[0] & b[0]])
b'\x10'
Coif answered 23/3, 2014 at 16:59 Comment(3)
Although you should at least add my comment about why just doing a & b fails.Colombi
@Colombi No, why? You already said it. And actually, I don’t agree with the language design here. I don’t see why bitwise operations are not provided for bytes objects…Coif
So that people just looking at the answer in the future see the full explanation :p And while I agree about it being weird, it's probably because of endianness I would imagine. And likely for consistency with other list-likes since it would probably be considered un-pythonic for a an operation like & to work on one kind of built-in list but not another. Basically, having & work on a bytes-array is making some implicit assumptions, and Python doesn't dig implisit. There is probably some module somewhere that will do the boilerplate operation to make & work explicitly for bytes.Colombi
F
6

A more general answer

def andbytes(abytes, bbytes):
    return bytes([a & b for a, b in zip(abytes[::-1], bbytes[::-1])][::-1])

Though IMO pyhon bytes objects should aready do this....

Foothold answered 28/11, 2019 at 14:50 Comment(2)
` bytes(map lambda a,b: a & b, abytes, bbytes)`Proofread
Why reverse the inputs and outputs with [::-1]? You could remove the reversals and get the same effect.Footlight
B
5

If you have a large byte string, it will be more efficient to use

c = (int.from_bytes(a, 'big') & int.from_bytes(b, 'big')).to_bytes(max(len(a), len(b)), 'big')

thanks, @Eryk Sun

Bough answered 22/7, 2020 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.