[Python-3000] Iterators for dict keys, values, and items == annoying :)

Nick Coghlan ncoghlan at gmail.com
Thu Mar 30 12:23:56 CEST 2006


Robert Brewer wrote:
> Nick Coghlan wrote:
>> There are three big use cases:
>>
>>    dict.keys
>>    dict.values
>>    dict.items
>>
>> Currently these all return lists, which may be expensive in 
>> terms of copying. They all have iter* variants which while
>> memory efficient, are far less convenient to work with.
> 
> I'm still wondering what "far less convenient" means. Is it simply the 4
> extra key presses? I find the iter* variants to be a great solution.

An iterator has some serious limitations as a view of a container:

1. Can only iterate once
2. Can't check number of items
3. Truth value testing doesn't work
4. Containment tests don't work
5. String representation is well-nigh useless
6. Value-based comparison doesn't work

The source object supports all of these things, but the iterator doesn't. This 
is why iteritems and friends are poor substitutes for their list based 
equivalents in many situations.

Consider, however, the following view-based approach:

   from itertools import izip

   class _containerview(object):
       """Default behaviour for container views"""
       def __init__(self, container):
           self.container = container
       def __len__(self):
           return len(self.container)
       def __iter__(self):
           return iter(self.container)
       def __contains__(self, val):
           return val in self.container
       def __eq__(self, other):
           # Check they're the same type
           if type(self) != type(other):
               return False
           # Check they're the same size
           if len(self) != len(other):
               return False
           # Check they have the same elements
           for this, that in izip(self, other):
               if this != that:
                   return False
           return True
       def __ne__(self, other):
           return not self.__eq__(other)
       def __str__(self):
           type_name = type(self).__name__
           details = ", ".join(self)
           return "%s([%s])" % (type_name, details)


   class keyview(_containerview):
       """Convenient view of dictionary keys"""
       # The default behaviour is always right

   class valueview(_containerview):
       """Convenient view of dictionary values"""
       def __iter__(self):
           return self.container.itervalues()
       def __contains__(self, val):
           for item in self:
               if item == val:
                   return True
           return False

   class itemview(_containerview):
       """Convenient view of dictionary items"""
       def __iter__(self):
           return self.container.iteritems()
       def __contains__(self, item):
           if not isinstance(item, tuple):
               return False
           if len(item) != 2:
               return False
           key, val = item
           try:
               stored_val = self.container[key]
           except AttributeError:
               return False
           return stored_val == val

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-3000 mailing list