Reputation: 3570
I'm learning Python and haven't yet learned completely about how arg arrays are handled in function calls. That's what my question is about: I'm passing a slice from a tuple into a function expecting the function will see multiple arguments, but it's just seeing one. It's not clear to me if this is a normal pattern that I need to work with in the called function, or if I should be doing something differently.
In my project, I'm parsing a binary file format (OpenType font file). The format is a complex tree of many different struct types: some structs are comprised of basic binary types supported by struct.unpack
, but some have members that are themselves complex structs. So, I'm creating a pattern for handling these in which struct.unpack
is called with a format string for the entire complex struct, and then slices of the returned values are passed to the member struct types to interpret.
For example, for a given table type—let's call it Foo
, the combined format string would be '>HHH2H'
. The method in Foo
that handles parsing for that type knows that this is divided into two members, a uint16 followed by a struct. (So, the format string was a combination of ">H"
and ">HH2H"
.) The call to struct.unpack
returned a tuple of 5 elements. A slice of four of those elements will get passed to a method in the member type for it to interpret.
Here's this bit of code for one particular case:
vals = struct.unpack(
PaintFormat1._packedFormat,
fileBytes[:PaintFormat1._packedSize]
)
color = ColorIndex.interpretUnpackedValues(vals[1:])
PaintFormat1._packedFormat
is the format string for the entire complex structure, '>HHH2H'
. fileBytes
is a byte sequence that starts at the start of the PaintFormat1
structure.
Now, I've defined the ColorIndex.interpretUnpackedValues
method with a signature as follows:
def interpretUnpackedValues(*vals):
assert len(vals) == ColorIndex._numUnpackedValues
ColorIndex._numUnpackedValues
is the expected number of arguments. The problem is that vals[1:]
(from the calling context) is getting passed as a tuple, not as elements of the tuple. So, for instance, in one call the arguments received are ((17, 0, 0, 0),)
, not (17, 0, 0, 0)
. Thus, len(vals)
is 1, and the assert is tripped.
Another way to put this: I was expecting to write the assert using len(vals)
, not len(vals[0])
. And then to access the individual values as vals[0]
, vals[1]
, etc., not vals[0][0]
, vals[0][1]
...
How do I call so that multiple arguments are passed rather than a single tuple?
Or should I re-write the function definition to expect a single tuple and access member elements within that function?
(This will be a recurring pattern I use in many places, so I want to understand and keep the code as simple and readable as possible.)
Upvotes: 1
Views: 160
Reputation: 6056
You can use *
operator to unpack your arguments:
ColorIndex.interpretUnpackedValues(*vals[1:])
Upvotes: 2