[Python-Dev] Getting values stored inside sets

Hrvoje Niksic hrvoje.niksic at avl.com
Fri Apr 3 14:07:02 CEST 2009

I've stumbled upon an oddity using sets.  It's trivial to test if a 
value is in the set, but it appears to be impossible to retrieve a 
stored value, other than by iterating over the whole set.  Let me 
describe a concrete use case.

Imagine a set of objects identified by some piece of information, such 
as a "key" slot (guaranteed to be constant for any particular element). 
  The object could look like this:

class Element(object):
     def __init__(self, key):
         self.key = key
     def __eq__(self, other):
         return self.key == other
     def __hash__(self):
         return hash(self.key)
     # ...

Now imagine a set "s" of such objects.  I can add them to the set:

 >>> s = set()
 >>> s.add(Element('foo'))
 >>> s.add(Element('bar'))

I can test membership using the keys:

 >>> 'foo' in s
 >>> 'blah' in s

But I can't seem to find a way to retrieve the element corresponding to 
'foo', at least not without iterating over the entire set.  Is this an 
oversight or an intentional feature?  Or am I just missing an obvious 
way to do this?

I know I can work around this by changing the set of elements to a dict 
that maps key -> element, but this feels unsatisfactory.  It's 
redundant, as the element already contains all the necessary 
information, and the set already knows how to use it, and the set must 
remember the original elements anyway, to be able to iterate over them, 
so why not allow one to retrieve them?  Secondly, the data structure I 
need conceptually *is* a set of elements, so it feels wrong to 
pigeonhole it into a dict.

This wasn't an isolated case, we stumbled on this several times while 
trying to use sets.  In comparison, STL sets don't have this limitation.

If this is not possible, I would like to propose either that set's 
__getitem__ translates key to value, so that s['foo'] would return the 
first element, or, if this is considered ugly, an equivalent method, 
such as s.get('foo').

More information about the Python-Dev mailing list