Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding set methods in Python

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?

like image 359
Casebash Avatar asked Jan 01 '26 18:01

Casebash


2 Answers

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
like image 136
Alex Martelli Avatar answered Jan 03 '26 07:01

Alex Martelli


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)
like image 31
u0b34a0f6ae Avatar answered Jan 03 '26 06:01

u0b34a0f6ae



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!