The "\" is an artifact of printing the bytes object (just like the b). The data does not contain any "\x". The bytes object is trying to find a way to print each byte. If a byte has the same integer value as a printable ascii character, the character is used in the output.
Output:
>>> x = b"These are all visible"
>>> x
b'These are all visible'
Common escape sequences are used too.
Output:
>>> x = b"This\thas\rescape\nsequences"
>>> x
b'This\thas\rescape\nsequences'
For other characters the value is displayed as a hexidecimal number.
Output:
>>> x = bytes((1, 2, 3, 4))
>>> x
b'\x01\x02\x03\x04'
And here is a fun mixture:
>>> x = bytes((1, 9, 65, 66, 2))
>>> x
b'\x01\tAB\x02'
1 is displayed as the hex number \x01. 9 shows up as a tab (\t). 65 and 66 are the are the decimal values for ascii characters A and B. 2 is displayed as the hex number \x02.
Python is not great about working with bits. To be fair, no languages are great when working with bits. In your example (from the screenshot) I think data will have 15 bytes (15 bytes * 8 bits / byte = 120 bits). You can unpack you bytes into a list of 0 and 1 (not bits, but int objects 0 and 1).
data = bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
print("data as bytes", data)
print("data[0]", data[0])
bits = []
for byte in data:
for x in (128, 64, 32, 16, 8, 4, 2, 1):
bits.append(int(bool(byte & x)))
print(bits)
Output:
data as bytes b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
data[0] 1
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1]
Notice the first 2 bytes are 00000001 and 00000010, the bits for 1 and 2.
Another way you could do this is convert the bytes to an int, that convert the int to a binary str.
data = bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
print("data as bytes", data)
big_int = int.from_bytes(data, "big")
print("Converted to int", big_int, hex(big_int))
bit_str = bin(big_int)
print("As binary str", bit_str)
Output:
data as bytes b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
Converted to int 5233100606242806050955395731361295 0x102030405060708090a0b0c0d0e0f
As binary str 0b10000001000000011000001000000010100000110000001110000100000001001000010100000101100001100000011010000111000001111
There's a little confusion here because leading zeros are not displayed in hex or binary representation. Since the bit str is just a string, we can pad with leading zeros.
data = bytes((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
print("data as bytes", data)
big_int = int.from_bytes(data, "big")
bit_str = f"{big_int:0120b}"
print(bit_str)
Output:
data as bytes b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
000000010000001000000011000001000000010100000110000001110000100000001001000010100000101100001100000011010000111000001111
There is also a function in numpy that will convert an array of bytes to an array of 0 and 1.
import numpy as np
data = np.array((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), np.uint8)
bits = np.unpackbits(data)
print(data)
print(bits)
Output:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
[0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0
0 0 1 0 1 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 1 1
0 0 0 0 0 1 1 1 1]