The easiest way is to use string slices. Since the lowest byte is on the far right and the highest is on the left, we can utilise negative indexes.
def sub_bytes(i, start=0, end=0):
i_str = hex(i)[2:] # skip 0x part
i_sub = i_str[-end * 2: len(i_str) - start * 2] # get the bytes we need
return int(i_sub or '0', 16) # convert to back int
len(i_str)
is here for better start=0 handling
Let's try with your value
In [2]: value = 0x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
In [3]: sub_bytes(value, 0, 3)
Out[3]: 11259375
In [4]: hex(sub_bytes(value, 0, 3))
Out[4]: '0xabcdef'
In [6]: hex(sub_bytes(value, 10, 20))
Out[6]: '0x90abcdef1234567890ab'
In [7]: hex(sub_bytes(value, 45))
Out[7]: '0x123456'
If a requested slice is empty or out of range I return 0x0 here, but you may raise IndexError
if you like.
UPDATE
In Python 3.2+ there are to_bytes
and from_bytes
defined on int
that are more efficient and more handy for this case
import math
def slice_bytes(value, a=None, b=None, byteorder='little'):
size = math.ceil(value.bit_length() / 8)
value_bytes = value.to_bytes(size, byteorder)
return int.from_bytes(value_bytes[a: b], byteorder)
And after some performance testing on a number 7 ** 7 ** 7
which has 288998 bytes, I found slice_bytes
to be faster than the direct approach by Karl. sub_bytes
is apparently slower.