Splitting a 16 bit int into two 8 bit ints in python

You say you're using these numbers as output, which suggests that they're going to be converted into strings at some point down the line. With that in mind, I'd suggest you take a look at the struct module, which is designed for precisely this sort of thing (packing numbers into strings of binary data). As a bonus, you get built-in error checking for the case where x is greater than 65535 (so that if something is horribly wonky in your program, you'll get an exception). For example,

s = struct.pack('>H', x)

is the equivalent of

if x > 65535:
    raise struct.error(...)
c, f = convert(x)
s = chr(c) + chr(f) # big-endian (network) byte ordering

If you need the other byte ordering, you can write

s = struct.pack('<H', x)

If you have a whole bunch of numbers to convert at once, struct.pack can do them in bunches:

x = [10333, 10475, 3021, ...] # for example
s = struct.pack('>' + 'H' * len(x), *x)

In python, bit-fiddling doesn't have any particular advantage, so I would go with:

c, f= divmod(your_number, 256)

EDIT: To make your intention even more obvious to the powers-of-two-challenged source viewer (if such a beast exists), you can replace the plain 256 with much more colourful alternatives, like 1<<8, 2**8, 0x100 or 0400 (that is 0o400 for Python 3). The constant folding done by the peephole optimizer since Python 2.5 ensures that any of them is exactly the same like using 256 (I'm obviously talking about the former two alternatives, which are expressions that evaluate to 256; the latter two are the constant 256).

$ python
Python 2.6.4 (r264:75706, Dec  7 2009, 18:45:15)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dis
>>> dis.dis(compile("c, f= divmod(your_number, 1<<8)", "", "exec"))
  1           0 LOAD_NAME                0 (divmod)
              3 LOAD_NAME                1 (your_number)
              6 LOAD_CONST               3 (256)
              9 CALL_FUNCTION            2
             12 UNPACK_SEQUENCE          2
             15 STORE_NAME               2 (c)
             18 STORE_NAME               3 (f)
             21 LOAD_CONST               2 (None)
             24 RETURN_VALUE

You should be consistent, if the intent of the operations is arithmetical, use modulo and division, if it's just for raw bit manipulation, use shift and mask.


I would do

c = (x >> 8) & 0xff
f = x & 0xff

It is safer, see e.g.

>>> (10303 >> 8) & 0xff
40
>>> (1030333333 >> 8) & 0xff
163
>>> (1030333333 >> 8) 
4024739

Since in python you can't control if the number is or not a 16bit, you have to force it into an at most 16-bit value. This is not needed if you're sure to have a 16-bit value, but this way the function is more general and allows you to be interested only in 16-bit values, no matter what the container contains.

Tags:

Python

Math