how do I write a scliceable class?

Diez B. Roggisch deets at nospam.web.de
Sat Feb 13 08:23:15 EST 2010


Am 13.02.10 13:51, schrieb Ernest Adrogué:
> Hello everybody,
>
> I'm designing a container class that supports slicing.
> The problem is that I don't really know how to do it.
>
> class MyClass(object):
> 	def __init__(self, input_data):
> 		self._data = transform_input(input_data)
> 	def __getitem__(self, key):
> 		if isinstance(key, slice):
> 			# return a slice of self
> 			pass
> 		else:
> 			# return a scalar value
> 			return self._data[key]
>
> The question is how to return a slice of self.
> First I need to create a new instance... but how? I can't
> use MyClass(self._data[key]) because the __init__ method
> expects a different kind of input data.
>
> Another option is
>
> out = MyClass.__new__(MyClass)
> out._data = self._data[key]
> return out
>
> But then the __init__ method is not called, which is
> undesirable because subclasses of this class might need
> to set some custom settings in their __init__ method.

I'd say you can't have your cake and eat it. Either let the constructors 
work with data to produce whatever state the instance really contains. 
If that's the case, go with your second solution. Potentially, you need 
to make self._data[key] some method-call that might be overridden, 
something along the lines of __getstate__, to make sure subclasses 
return all data that is relevant to them.

But if you really have child-class code that needs to be run on *every* 
object construction, then you should make input_data optional, and pass 
the transformed input in for the slice-creation, bypassing the 
transform_input.

The only other solution I can think of is to return a 
MyClassSlice-instance, which is just a view to MyClass instances, and 
restricts e.g. key-spaces.


class MyClassSlice(object):

     def __init__(self, state, slice):
         self.state = state
         self.slice = slice


     def __getitem__(self, key):
         if isinstance(key, slice):
            # create subslice & return that
            return MyClassSlice(self.state, merged_slice(key, self.slice))
         elif self.key_in_slice(key):
            return self._state[key]
         raise IndexError

     def key_in_slice(self, key):
         # this of course depends on your key-domain.


Diez



More information about the Python-list mailing list