tags:

views:

351

answers:

2

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?

In particular, I am using Python 3.0

+1  A: 

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)
kaizer.se
When I do that, I do not get the update method
Casebash
Plus I cannot call super (using Python 3.0)
Casebash
@Casebash: Please include the Python 3.0 information in the question, not a comment to an answer.
S.Lott
+4  A: 

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
Alex Martelli
It can be generalized using `key(item)` instead of `item.lower()` everywhere -> `KeySet("Aa", key=operator.methodcaller('lower'))`.
J.F. Sebastian
Why do you subclass from `Set` and not `MutableSet`? Anyone but me that think it is very confusing that the collections module is a mix of "real" collections (deque) and ABCs?
kaizer.se
It is worth noting that `Set` is not the same as `set`
Casebash
@JF and kaizer, silly typo of mine -- I mentioned the Set / MutableSet difference in the text then used the former in the code, fixed now, tx. Yes Casebash, Python is case-sensitive (also sets.Set is different from collections.Set in Py 2.6, since they're in different modules and namespaces). @kaizer, yeah, maybe we should have put the ABCs in a different module (but abc.py being taken for the lower-level ABC infrastructure, no other module name emerged as a convincing consensus).
Alex Martelli
@JF, excellent idea -- just such a parameterization has proven very useful in sort, min, max, ... and along a different axis in defaultdict.
Alex Martelli
For future reference, there is a "KeyedSet" recipe here building on MutableSet. http://code.activestate.com/recipes/576932/
kaizer.se
@kaizer.se, nice, tx for the pointer.
Alex Martelli