I want to concatenate the first byte of a bytes string to the end of the string:
a = b'\x14\xf6'
a += a[0]
I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to int
When I type bytes(a[0]) I get:
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
And bytes({a[0]}) gives the correct b'\x14'.
Why do I need {} ?
-
1What are you trying to achieve?Jasper– Jasper2015年01月24日 22:03:46 +00:00Commented Jan 24, 2015 at 22:03
-
Could You see my post: [stackoverflow.com/questions/54682735/… ? I have problem with concatenate bytes. Each run of my script gives different results.Darek– Darek2019年02月14日 18:35:17 +00:00Commented Feb 14, 2019 at 18:35
-
@jasper, it should not matter. In its pure form this is good question. Its a problem many intermediate Python programmers, or those coming from other languages might face.Andrew S– Andrew S2023年09月17日 23:13:04 +00:00Commented Sep 17, 2023 at 23:13
4 Answers 4
Bytes don't work quite like strings. When you index with a single value (rather than a slice), you get an integer, rather than a length-one bytes instance. In your case, a[0] is 20 (hex 0x14).
A similar issue happens with the bytes constructor. If you pass a single integer in as the argument (rather than an iterable), you get a bytes instance that consists of that many null bytes ("\x00"). This explains why bytes(a[0]) gives you twenty null bytes. The version with the curly brackets works because it creates a set (which is iterable).
To do what you want, I suggest slicing a[0:1] rather than indexing with a single value. This will give you a bytes instance that you can concatenate onto your existing value.
a += a[0:1]
Comments
If you want to change your byte sequence, you should use a bytearray. It is mutable and has the .append method:
>>> a = bytearray(b'\x14\xf6')
>>> a.append(a[0])
>>> a
bytearray(b'\x14\xf6\x14')
What happens in your approach: when you do
a += a[0]
you are trying to add an integer to a bytes object. That doesn't make sense, since you are trying to add different types.
If you do
bytes(a[0])
you get a bytes object of length 20, as the documentation describes:
If [the argument] is an integer, the array will have that size and will be initialized with null bytes.
If you use curly braces, you are creating a set, and a different option in the constructor is chosen:
If it is an iterable, it must be an iterable of integers in the range 0 <= x < 256, which are used as the initial contents of the array.
Comments
bytes is a sequence type. Its individual elements are integers. You can't do a + a[0] for the same reason you can't do a + a[0] if a is a list. You can only concatenate a sequence with another sequence.
bytes(a[0]) gives you that because a[0] is an integer, and as documented doing bytes(someInteger) gives you a sequence of that many zero bytes (e.g,, bytes(3) gives you 3 zero bytes).
{a[0]} is a set. When you do bytes({a[0]}) you convert the contents of that set into a bytes object. This is not a great way to do it in general, because sets are unordered, so if you try to do it with more than one byte in there you may not get what you expect.
The easiest way to do what you want is a + a[:1]. You could also do a + bytes([a[0]]). There is no shortcut for creating a single-element bytes object; you have to either use a slice or make a length-one sequence of that byte.
Comments
Try this
values = [0x49, 0x7A]
concat = (values[0] << 8) + values[1]
print(hex(concat))
you should get 0x497A