Question

I want to create a custom set that will automatically convert objects into a different form for storage in the set (see Using a Python Dictionary as a key non-nested) for background.

If I override add, remove, __contains__, __str__, update, __iter__, will that be sufficient to make the other operations behave properly, or do I need to override anything else?

Was it helpful?

Solution

Working from collections's abstract classes, as @kaizer.se suggests, is the appropriate solution in 2.6 (not sure why you want to call super -- what functionality are you trying to delegate that can't best done by containment rather than inheritance?!).

It's true that you don't get update -- by providing the abstract methods, you do get __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__ __sub__, __xor__, and isdisjoint (from collections.Set) plus clear, pop, remove, __ior__, __iand__, __ixor__, and __isub__ (from collections.MutableSet), which is far more than you'd get from subclassing set (where you'd have to override every method of interest). You'll just have to provide other set methods you desire.

Note that the abstract base classes like collections.Set are a pretty different beast from concrete classes, including builtins such as set and (in 2.6) good old sets.Set, deprecated but still around (removed in Python 3). ABCs are meant to inherit from (and can then synthesize some methods from you once you implement all the abstract methods, as you must) and secondarily to "register" classes with so they look as if they inherited from them even when they don't (to make isinstance more useable and useful).

Here's a working example for Python 3.1 and 2.6 (no good reason to use 3.0, as 3.1 only has advantages over it, no disadvantage):

import collections

class LowercasingSet(collections.MutableSet):
  def __init__(self, initvalue=()):
    self._theset = set()
    for x in initvalue: self.add(x)
  def add(self, item):
    self._theset.add(item.lower())
  def discard(self, item):
    self._theset.discard(item.lower())
  def __iter__(self):
    return iter(self._theset)
  def __len__(self):
    return len(self._theset)
  def __contains__(self, item):
    try:
      return item.lower() in self._theset
    except AttributeError:
      return False

OTHER TIPS

In Python 2.6:

import collections
print collections.MutableSet.__abstractmethods__
# prints:
# frozenset(['discard', 'add', '__iter__', '__len__', '__contains__'])

subclass collections.MutableSet and override the methods in the list above.

the update method itself is very easy, given that the bare minimum above is implemented

def update(self, iterable):
    for x in iterable:
        self.add(x)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top