I have data like data = [[t1, t2, ...], [v1, v2, ...]]
. I want to wrap this in a class so I can call data.t
instead of having to use data[0]
.
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
else:
raise ValueError("not valid key '{}'".format(key))
def __setitem__(self, key, value):
if key == 0:
self.t = value
elif key == 1:
self.v = value
else:
raise ValueError("not valid key '{}'".format(key))
The reason for the __getitem__
and __setitem__
overloading is for backwards compability so that data[0]
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/oml.py in __getitem__(self, key)
52 return self.val
53 else:
---> 54 raise ValueError("not valid key '{}'".format(key))
55
56 def __setitem__(self, key, value):
ValueError: not valid key '2'
How can I make my class work properly with the argument unpacking operator?
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 https://docs.python.org/3/reference/datamodel.html#object.getitem which explicitly states
Note:
for
loops expect that anIndexError
will be raised for illegal indexes to allow proper detection of the end of the sequence.
https://docs.python.org/2/library/functions.html#iter states that this is called the "sequence protocol".