Why is dictionary.keys() a list and not a set?

Christoph Zwerschke cito at online.de
Thu Nov 24 18:52:02 EST 2005


Mike Meyer wrote:

 > Well, I just made a suggestion. You found the problem - you want to do
 > the PR, or should I?

Please go ahead if you have the time. By the way, the doco may be also 
inexact about the keys of dictionaries.

> # Untested code
> class Hash(object):
>    def __new__(cls, obj):
>       if hasattr(obj, '__hash__'):
>          return obj
>       self.__obj = obj
>       return object.__new__()
>    def __getattr__(self, name):
>        return getattr(self.__obj, name)
>    def __setattr(self, name, value):
>        setattr(self.__obj, name, value)
>    def __hash__(self):
>        return id(self.__obj)

This will not work since even lists seem to have a __hash__ attribute. 
Also, you will get an infinite recursion when trying to access 
self.__obj. But principally, it should work. Ad hoc solution:

class HashProxy:
     def __init__(self, obj):
         self.__obj = obj
     def __getattr__(self, name):
         return getattr(self.__obj, name)
     def __setattr(self, name, value):
         setattr(self.__obj, name, value)
     def __hash__(self):
         return id(self.__obj)

def Hash(obj):
     try:
         hash(obj)
     except TypeError:
         return HashProxy(obj)
     else:
         return obj

 > If you need to turn a list of arbitrary, possibly unhashable, objects
 > into a set, is there a problem with the above?

Well, first you don't get the real unhashable objects, but proxied 
objects. This will lead to problems if you want to check the type in the 
following - you will always get the same type. Second, as you have 
already mentioned, the elements of the sets will not be guaranteed to be 
different anymore (only different in terms of identity (is), but they 
still may be equal (==)). This would not be what you expect from a set.

-- Christoph



More information about the Python-list mailing list