On Apr 25, 7:03 am, Kirk Strauser <[EMAIL PROTECTED]> wrote: > I want to subclass list so that each value in it is calculated at call > time. I had initially thought I could do that by defining my own > __getitem__, but 1) apparently that's deprecated (although I can't > find that; got a link?), and 2) it doesn't work. > > For example: > > >>> class Foo(list): > > ... def __getitem__(self, index): > ... return 5 > ...>>> a = Foo([1, 2, 3, 4, 5]) > >>> print a > [1, 2, 3, 4, 5] > >>> print a[2:4] > [3, 4] > >>> print a[3] > > 5 > > I first expected that to instead behave like: > > >>> print a > [5, 5, 5, 5, 5] > >>> print a[2:4] > > [5, 5] > > Is there a "right" way to do this? > -- > Kirk Strauser
The built in types are very optimized. You can't make any assumptions about how overriding methods on them will affect other method calls. >From the docs: __getitem__( self, key) Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the __getitem__() method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised. Note: for loops expect that an IndexError will be raised for illegal indexes to allow proper detection of the end of the sequence. What that basicly says is that it affects what is returned by a[x]. >>> class Foo(list): ... def __getitem__(self, index): ... return 5 ... >>> a = Foo([1, 2, 3, 4, 5]) >>> print a # a.__str__ called [1, 2, 3, 4, 5] >>> print a[2:4] # a.__getslice__ called [3, 4] >>> print a[3] # a.__getitem__ called 5 The _right_ way? Well, it depends on what you really want to do. If you really want to calculate the value at call time but have it behave exactly as a list in every way, then you will have to override pretty much any method that deals with the values normally stored in the list object. That means any method that either returns values stored in the object, accepts as a parameter values stored in the object or uses the values stored in the object in any way. Methods that return values stored in the object: __getitem__ __getslice__ pop Methods that accept as a parameter values stored in the object: __contains__ count remove index Methods that use values stored in the object in some way: __add__ __eq__ __ge__ __gt__ __iadd__ __imul__ __le__ __lt__ __mul__ __ne__ __reduce__ __reduce_ex__? I'm not sure about this one, I think it is for pickling __repr__ __reversed__ __rmul__ __str__ __iter__ sort reverse I know that Py3.0 is going to implement Abstract Base Classes. I don't know if that is going to clean up this behavior or not. So, you can either write a lot of code or restrict the way you use lists to a limited amount of functionality. There is a third option, which is to calculate the values when storing. This might be a little easier, but if you want to ensure that values returned by all methods are the same type as your class you are back to overriding a lot of methods. Matt -- http://mail.python.org/mailman/listinfo/python-list