views:

42

answers:

2

I need a custom __reverse__ function for my class that I am deploying on App Engine, so it needs to work with Python 2.5. Is there a __future__ import or a workaround I could use?

Subclassing list won't work, as I need my class to be a subclass of dict.

EDIT:

Using OrderedDict will not solve the problems, because the dict keys are not the same the same as the list items.

This is the object I'm trying to create:

  1. My object needs to provide the same attributes as a list, i.e. support iter(obj) and reverse(obj).

  2. The elements must be instances of a special third party class.

  3. Each elements is associated with a key.

  4. Internally, need to access these objects using their keys. That's why I'd put them in a mapping.

I've revised my implementation to be a list subclass instead of a dict subclass, so here's what I have now:

class Foo(list):

   pat = {}

   def __init__(self):
       for app in APPS:  # these are strings
           obj = SpecialClass(app)
           self.append(obj)
           self.pat[app] = obj

   def __getitem__(self, item):

       # Use object as a list
       if isinstance(item, int):
           return super(Foo, self).__getitem__(item)

       # Use object as a dict
       if item not in self.pat:
           # Never raise a KeyError
           self.pat[item] = SpecialClass(None)
       return self.pat[item]

   def __setitem__(self, item, value):
       if isinstance(item, int):
           return self.pat.__setitem__(item, value)
       return super(Foo).__setitem__(item, value)

EDIT 2:

Now that my class is a subclass of list, my problem is resolved.

+2  A: 

__reversed__ isn't supported in 2.5, so your only option if you really need to customize the reversed order of your collection, is to modify the places that you call reversed to use something else.

But I'm curious: if you are subclassing dict, then the order of items is arbitrary anyway, so what does reversed mean in this case?

Ned Batchelder
To answer your question: I am keeping two collections in one object: a sequence (actually a `list`) and a mapping (which is the `dict` I'm subclassing, so I'm using it as `self`). A third party library then uses this object (which is essentially a list mock), and it expects a list. So, I have a custom `__iter__` method that iterates over the sequence collection (`pat = []; __iter__ = lambda self: iter(self.pat)`), but I can't handle `reverse(my_object)` with that. That said, perhaps I should subclass `list`, and keep my mapped data in an attribute, and have custom `__{get,set}item__` methods?
Attila Oláh
Do the list and dict contain the same keys? Could you use an OrderedDict?
Daenyth
@Daenyth No, but the dict contains the same **values** as the list items.
Attila Oláh
Ok, subclassing `list` instead of `dict` solved the issue, thanks for the suggestion.
Attila Oláh
+1  A: 

Creating a custom __reversed__ is only possible since 2.6, so you can't simply implement that and have reversed working in 2.5. In 2.5 and below, you can however make your custom class still working with reversed by implementing the sequence protocol (i.e. implement both __len__ and __getitem__).

A different possibility would be to replace the built-in function reversed with a custom function that treats your custom class differently. This could work like this:

originalReversed = reversed
def myReversed ( seq ):
    if isinstance( seq, MyCustomClass ):
        # do something special
    else:
        return originalReversed( seq )
reversed = myReversed

However, I wouldn't recommend that as it changes the normal behaviour of built-in functions (obviously) and might confuse other users.. So you should rather implement the sequnce protocol to make reversed working.

poke