I'd like to write a simple wrapper for the python list
type that forces it to start indexing at 1
instead of 0
. I've got a a fairly complex program based on some discrete probability distributions of duration data, with integer-length buckets, but I don't have any durations of less than 1. Anyway, it would greatly simplify a some significant portions of my code to be able to seamlessly index starting at 1. I was using a dict
at first but I found several properties of them to be too cumbersome.
I've never written a wrapper for a Python class before, much less a built-in type, but I feel like what I want to do is fairly simple. At the bare minimum, I should be able to do stuff like this:
>>> p = one_list([1,2,3,4,5])
>>> for i in range(1,6):
print i, p[i]
1 1
2 2
3 3
4 4
5 5
>>> len(p)
5
However it would be good if I could overwrite some of the other relevant built-in methods of the list
class as well, such as index
.
>>> len(p)
5
>>> p.index(p[-1])
5
Please share your tips as to how I might go about doing something like this. I was considering whether or not to just do it with a custom class, but that seems like it might be overkill. I also welcome any recommendations as to useful methods to overwrite.
Edit: Afterword
I'd just like to note that it was not worth the trouble to do this, and the reason I've accepted the answer below is not because I tried to implement it in the way he describes, but because he helped me realize that lists are good enough on their own.
Here's a basic implementation to get you started. I thought it would be nice to generalize it, so you can have lists with indices starting at any integer you like. This led me to discover
__slots__
, so thank you for asking this question!You may find you want to implement
__getslice__
,__setslice__
,__delslice__
too, not to mentionpop
andinsert
.Here's a complete (I think) implementation of a 1-based list, correctly handling slicing (including extended slices), indexing, popping, etc. It's slightly more tricky to get this right than you might think, especially the slicing and the negative indexes. In fact I'm still not 100% sure it works exactly as it should, so caveat coder.
senderle's
ExtraItemList
is going to have better performance, though, because it doesn't need to adjust the indices constantly nor does it have an extra layer of (non-C!) method calls between you and the data. Wish I'd thought of that approach; maybe I could profitably combine it with mine...Ok, well, you seem very determined. As I said above, you have to override
__getitem__
,__setitem__
, and__delitem__
. Actually you'll also have to override__getslice__
,__setslice__
,__delslice__
(otherwise slicing starts at 0 as usual). Then__add__
,__mul__
,__iadd__
,__imul__
to returnWonkyList
s as well (otherwise concatenation won't work the way you'd want). You'll have to overrideindex
because it will return a wrong value (I tested it). Alsoinsert
,remove
, andpop
. Here's something to get you started:Tested:
Here are some ways it will fail until you override all the necessary methods:
Or you could try something else. Have you considered, for example...
That seems to take care of the issues you list, and it still behaves in a basically list-like manner, even if the initializer is a little weird. Though to be honest, looking at the examples you gave, I'm starting to feel like even this is an ugly solution -- none of the functions you gave show the advantage of starting indexing from 1, they just show the bad effects of adding an extra item to the beginning of the list. Based on those examples, you should just use a regular list.
Perhaps the best approach would be to write custom
get
andset
methods that use the desired offset. That way the lists would behave normally, but you'd have an alternative interface when needed.