pingul pingul - 1 year ago 65
Python Question

How to overload * argument unpacking operator?

I have data like

data = [[t1, t2, ...], [v1, v2, ...]]
. I want to wrap this in a class so I can call
instead of having to use

I tried to do this with the following:

class Variable:
def __init__(self, data):
self.t = data[0]
self.v = data[1]

def __getitem__(self, key):
if key == 0:
return self.t
elif key == 1:
return self.v
raise ValueError("not valid key '{}'".format(key))

def __setitem__(self, key, value):
if key == 0:
self.t = value
elif key == 1:
self.v = value
raise ValueError("not valid key '{}'".format(key))

The reason for the
overloading is for backwards compability so that
still works. This works for most things, however I run into problems with the following call:

func_that_takes_two_arguments(*data) # unpacking data

The error I get is

/Users/pingul/Workspace/lhcfill/ in __getitem__(self, key)
52 return self.val
53 else:
---> 54 raise ValueError("not valid key '{}'".format(key))
56 def __setitem__(self, key, value):
ValueError: not valid key '2'

How can I make my class work properly with the argument unpacking operator?

Answer Source

The * operator works by iterating over the object. This iteration can well be performed with only implementing __getitem__(), but your implementation is faulty. Instead if raising ValueError, you should throw IndexError which signals the end of the iteration.

See also which explicitly states

Note: for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence. states that this is called the "sequence protocol".

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download