dsets
index
/home/beni/hacks/python/dsets.py

A dictionary extended with set operations.
 
It has long been observed that sets can be emulated as dictionaries with dummy
values (see `dict.fromkeys()`).  The common operations, like `dict.update()`
match directly.  This module is simply a ''backport'' of the other goodies
added in the ``sets`` module to dictionaries.
 
The main issue with applying set operations are collisions: given two values
(which can be different) for the same key in two DSets, which value should we
use?  Choosing either one would be wrong in most applications, so the user is
allowed to provide his own function for reconciling them.  He has to provide
them per call - experience showed that the desired operation chages frequently
even when invoking the same method.
 
 
Values do not participate in the comparison of elements, to maintain
compatibility with sets.  If you want them to participate, make them part of
the key.
 
This means that generally, the operations don't have to be commutative (unlike
with sets).  To emphasize this, the __magic__ operator overloading methods are
not provided - only the named methods are (they would also present a problem
of how to indicate the collision handler).
 
Other objects that are not mappings (e.g. lists or sets) are treated as
mappings from their items to `None`.

 
Classes
       
exceptions.Exception
UnhandledCollisionError
__builtin__.dict(__builtin__.object)
DSet

 
class DSet(__builtin__.dict)
    An extension of a dictionary with some of the methods of `sets.Set`.
 
Most methods take an optional last argument, `collision`, that should be a
function of two arguments that is called upon key collision, when the key
should also be present in the result, so that it's unclear which value to
use.  Note that no checks whether the values are equal is made (think
about a collision hadnler that sums the values to understand why).  If the
argument is not provided, an exception is raised upon a collision.
 
 
Method resolution order:
DSet
__builtin__.dict
__builtin__.object

Methods defined here:
__copy__ = copy(self)
__repr__(self)
add(self, key, value=None, collision=<function collision_unhandler>)
Add a key to a DSet.
 
>>> d = DSet()
>>> d.add(1)
>>> d.add(2, 3)
>>> d == {1: None, 2: 3}
True
>>> d.add(2, 4, collision=second)
>>> d == {1: None, 2: 4}
True
copy(self)
Return a shallow copy.
difference(self, other)
Return new DSet with all items in `self` but not in `other`.
 
>>> DSet({1: 2, 3: 4}).difference({1: 0}) == {3: 4}
True
difference_update(self, other)
Remove all keys in `other` from this dictset.
 
>>> d = DSet({1: 2, 3: 4})
>>> d.difference_update([3, 5])
>>> d == {1: 2}
True
discard(self, key)
Remove a key from a set if it is a member.
 
>>> d = DSet({1: 2, 3: 4})
>>> d.discard(3)
>>> d.discard(5)
>>> d == {1: 2}
True
intersection(self, other, collision=<function collision_unhandler>)
Return new DSet with all items of `self` that are also in `other`.
 
>>> DSet({1: 2, 3: 4}).intersection({1: 0}, collision=first) == {1: 2}
True
intersection_update(self, other, collision=<function collision_unhandler>)
Retain only items whose keys are in `other`.
 
>>> d = DSet({1: 2, 3: 4})
>>> d.intersection_update([3, 5], collision=first)
>>> d == {3: 4}
True
issubset(self, other)
Check whether `other` contains all keys of `self`.
 
>>> DSet({1: 2, 3: 4}).issubset({1: 0, 2: 0, 3: 0})
True
>>> DSet({1: 2, 3: 4}).issubset({1: 0})
False
issuperset(self, other)
Check whether `self` contains all keys of `other`.
 
>>> DSet({1: 2, 3: 4}).issuperset({1: 0, 2: 0, 3: 0})
False
>>> DSet({1: 2, 3: 4}).issuperset({1: 0})
True
pop(self)
Remove and return an arbitrary key.
 
>>> d = DSet({1: 2, 3: 4})
>>> keys = [d.pop(), d.pop()]
>>> keys.sort()
>>> keys
[1, 3]
>>> d == {}
True
symmetric_difference(self, other)
Return new DSet with items from `self` or `other` but not both.
 
>>> DSet({1: 2, 3: 4}).symmetric_difference({1: 0, 5: 6}) == {3: 4, 5: 6}
True
>>> DSet({1: 2, 3: 4}).symmetric_difference([1, 5]) == {3: 4, 5: None}
True
symmetric_difference_update(self, other)
Make self into the symmetric difference of `self` and `other`.
 
>>> s = DSet({1: 2, 3: 4})
>>> s.symmetric_difference_update([1, 5])
>>> s == {3: 4, 5: None}
True
union(self, other, collision=<function collision_unhandler>)
Return new DSet with all items from `self` and from `other`.
 
>>> DSet({1: 2, 3: 4}).union({3: 0, 5: 6}, collision=first) == {1: 2, 3: 4, 5: 6}
True
union_update(self, other, collision=<function collision_unhandler>)
Add all itmes of `other` that are not in `self`.
 
Note that when a key is present in both, this method prefers the
values of `self`, unlike `update()`.
 
>>> s = DSet({1: 2, 3: 4})
>>> s.union_update({3: 0, 5: 6}, collision=first)
>>> s == {1: 2, 3: 4, 5: 6}
True

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'DSet' objects>
list of weak references to the object (if defined)

Methods inherited from __builtin__.dict:
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
__contains__(...)
x.__contains__(y) <==> y in x
__delitem__(...)
x.__delitem__(y) <==> del x[y]
__eq__(...)
x.__eq__(y) <==> x==y
__ge__(...)
x.__ge__(y) <==> x>=y
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__gt__(...)
x.__gt__(y) <==> x>y
__hash__(...)
x.__hash__() <==> hash(x)
__init__(...)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
__iter__(...)
x.__iter__() <==> iter(x)
__le__(...)
x.__le__(y) <==> x<=y
__len__(...)
x.__len__() <==> len(x)
__lt__(...)
x.__lt__(y) <==> x<y
__ne__(...)
x.__ne__(y) <==> x!=y
__setitem__(...)
x.__setitem__(i, y) <==> x[i]=y
clear(...)
D.clear() -> None.  Remove all items from D.
get(...)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
has_key(...)
D.has_key(k) -> True if D has a key k, else False
items(...)
D.items() -> list of D's (key, value) pairs, as 2-tuples
iteritems(...)
D.iteritems() -> an iterator over the (key, value) items of D
iterkeys(...)
D.iterkeys() -> an iterator over the keys of D
itervalues(...)
D.itervalues() -> an iterator over the values of D
keys(...)
D.keys() -> list of D's keys
popitem(...)
D.popitem() -> (k, v), remove and return some (key, value) pair as a
2-tuple; but raise KeyError if D is empty
remove = __delitem__(...)
x.__delitem__(y) <==> del x[y]
setdefault(...)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
update(...)
D.update(E) -> None.  Update D from E: for k in E.keys(): D[k] = E[k]
values(...)
D.values() -> list of D's values

Data and other attributes inherited from __builtin__.dict:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
fromkeys = <built-in method fromkeys of type object>
dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.
v defaults to None.

 
class UnhandledCollisionError(exceptions.Exception)
    Raised by default when keys in two DSets collide.
 
  Methods inherited from exceptions.Exception:
__getitem__(...)
__init__(...)
__str__(...)

 
Functions
       
collision_unhandler(this, other)
Raise an `UnhandledCollisionError` upon a collision.
first(a, b)
Resolve collisions by returning the first value.
second(a, b)
Resolve collisions by returning the second value.

 
Data
        __author__ = 'Beni Cherniavsky <cben@users.sf.net>'
__license__ = 'LGPL <http://www.gnu.org/copyleft/lesser.html>'
__url__ = 'http://cben-hacks.sf.net/python/'

 
Author
        Beni Cherniavsky <cben@users.sf.net>