I\'m implementing an object that is almost identical to a set, but requires an extra instance variable, so I am subclassing the built-in set object. What is the best way to
I think that the recommended way to do this is not to subclass directly from the built-in set
, but rather to make use of the Abstract Base Class Set available in collections.abc.
Using the ABC Set gives you some methods for free as a mix-in so you can have a minimal Set class by defining only __contains__()
, __len__()
and __iter__()
. If you want some of the nicer set methods like intersection()
and difference()
, you probably do have to wrap them.
Here's my attempt (this one happens to be a frozenset-like, but you can inherit from MutableSet
to get a mutable version):
from collections.abc import Set, Hashable
class CustomSet(Set, Hashable):
"""An example of a custom frozenset-like object using
Abstract Base Classes.
"""
__hash__ = Set._hash
wrapped_methods = ('difference',
'intersection',
'symetric_difference',
'union',
'copy')
def __repr__(self):
return "CustomSet({0})".format(list(self._set))
def __new__(cls, iterable=None):
selfobj = super(CustomSet, cls).__new__(CustomSet)
selfobj._set = frozenset() if iterable is None else frozenset(iterable)
for method_name in cls.wrapped_methods:
setattr(selfobj, method_name, cls._wrap_method(method_name, selfobj))
return selfobj
@classmethod
def _wrap_method(cls, method_name, obj):
def method(*args, **kwargs):
result = getattr(obj._set, method_name)(*args, **kwargs)
return CustomSet(result)
return method
def __getattr__(self, attr):
"""Make sure that we get things like issuperset() that aren't provided
by the mix-in, but don't need to return a new set."""
return getattr(self._set, attr)
def __contains__(self, item):
return item in self._set
def __len__(self):
return len(self._set)
def __iter__(self):
return iter(self._set)