Home > front end >  What should be modified in a working Python 2 struct example to work in Python 3?
What should be modified in a working Python 2 struct example to work in Python 3?

Time:04-16

While learning about struct and by just testing an example provided as one of the answers given for question Python base64 encoding a list, I get a Python 3 related error which I don't know how to handle.

Test code:

import struct
import base64

l = [1, 2, 3, 4, 5]
y = struct.pack('<{}i'.format(len(l)), *l)
z = base64.b64encode(y)

# ... whatever further processing ...

y = base64.b64decode(z)
l = list(struct.unpack('<{}i'.format(len(y)/4), y))

which gives:

l = list(struct.unpack('<{}i'.format(len(y)/4), y))
struct.error: bad char in struct format

What should be modified to be Python 3 compatible ?

This is merely for exercise & learning; running Python 3.7 on Linux or 3.10 on Windows.

CodePudding user response:

/ always returns a floating-point value in Python 3, where in Python 2 it returned an int if both arguments were ints. Use // instead.

l = list(struct.unpack('<{}i'.format(len(y) // 4), y))

Since you are using Python 3.7, you can use f-strings instead to simplify this.

l = list(struct.unpack(f'<{len(y) // 4}i', y))

(To this day, I still wonder why something like '<*i' isn't supported to just extract as many values as possible from the byte string argument.)

CodePudding user response:

You should change the "true division" operator / to "floor division" (sometimes called "integer division") //:

l = list(struct.unpack('<{}i'.format(len(y)//4), y))

This is because in Python 2, division / between ints give an integer back, with the division rounded down (in the case of a non-zero remainder). In Python 3, division / between ints results in a float, even in the case of the remainder being zero.

The floor division // does the same thing as / in Python 2. Note however that // is also available in Python 2, so the code still works in Python 2 after changing / to //.

If you're interested in the thought process behind this change, check out PEP 238.

  • Related