This snippet implements a pointed set, that is to say an ordinary set of elements with a distinguished element called the basepoint of the set. For example the seven days of the week could be stored in a pointed set, the basepoint being monday because today is monday. It is a very simple structure but use cases are easily found.
Pointed Set type
#!/usr/bin/env python
# -*-coding: utf8-*-
# Author: Gribouillis for the python forum at www.daniweb.com
# Date: 2014 May 26
# License: Public Domain
# Use this code freely
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from collections import MutableSet
__version__ = '0.0.2'
if repr(set([0])).startswith('{'): # python 3
def _set_repr(aset):
s = repr(aset)
return 'set([{}])'.format(s[1:-1])
else: # python 2
_set_repr = repr
class PointedSet(MutableSet):
"""PointedSet(iterable) --> new PointedSet instance.
It is an error if @iterable is empty.
This class implements a non empty ordinary set with a distinguished element
called the basepoint. This element can be read and written through the attribute
self.basepoint
The selected element always belong to the set. Failing operations, such as
attempts to empty the set or define an invalid basepoint may raise KeyError
or TypeError.
The class implements the MutableSet abstract interface defined in module
collections.
The "pointed set" terminology is borrowed from mathematics. See for example
https://en.wikipedia.org/wiki/Pointed_set
>>> s = PointedSet(range(10))
>>> s # doctest: +ELLIPSIS
PointedSet([...])
>>> len(s)
10
>>> 0 <= s.basepoint < 10
True
>>> s &= range(5)
>>> s # doctest: +ELLIPSIS
PointedSet([...])
>>> sorted(s)
[0, 1, 2, 3, 4]
>>> s.basepoint = 3
>>> s.basepoint
3
>>> s.basepoint = 7
Traceback (most recent call last):
...
KeyError: 7
>>> s.basepoint
3
>>> s -= range(4)
>>> s.basepoint
4
>>> s
PointedSet([4])
>>> s.pop()
Traceback (most recent call last):
...
TypeError: discard would empty PointedSet
"""
__slots__ = ('_aggregate', '_basepoint')
def __init__(self, iterable):
self._aggregate = set(iterable)
try:
self._basepoint = next(iter(self._aggregate))
except StopIteration:
raise TypeError('PointedSet initialized from empty iterable')
@property
def basepoint(self):
return self._basepoint
@basepoint.setter
def basepoint(self, item):
if item in self._aggregate:
self._basepoint = item
else:
raise KeyError(item)
def __contains__(self, item):
return item in self._aggregate
def __iter__(self):
return iter(self._aggregate)
def __len__(self):
return len(self._aggregate)
def add(self, item):
self._aggregate.add(item)
def discard(self, item):
if item in self._aggregate:
if len(self._aggregate) == 1:
raise TypeError('discard would empty PointedSet')
else:
self._aggregate.discard(item)
if self._basepoint not in self._aggregate:
self._basepoint = next(iter(self._aggregate))
def __repr__(self):
r = repr(self._aggregate)
return "PointedS{}".format(_set_repr(self._aggregate)[1:])
if __name__ == "__main__":
import doctest
doctest.testmod()
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.