Re: wx.Colour - not hashable in Phoenix/Py3

Robin Dunn <[email protected]>
Newsgroups gmane.comp.python.wxpython.devel
Message-ID <[email protected]>
Werner wrote:
> Hi,
>
> On 11/27/2014 15:26, Amaury Forgeot d'Arc wrote:
>> 2014-11-27 14:38 GMT+01:00 Werner <[email protected]
>> <mailto:[email protected]>>:
>>
>>     Hi,
>>
>>     On 11/18/2014 15:11, Werner wrote:
>>
>>         I am working on making ObjectListView comptable with Py3 and
>>         Phoenix and get an error in the tests.
>>
>>         case.py (c:\Python34\Lib\unittest): 57
>>                     yield
>>         case.py (c:\Python34\Lib\unittest): 574
>>                             testMethod()
>>         test_ObjectListView.py (d:\devTools\ObjectListView\test): 320
>>                     self.objectListView.oddRowsBackColor in
>>         set(bkgdColours))
>>         testNoAlternateColours
>>         Exception: TypeError: unhashable type: 'Colour'
>>
>>
>>         This test passes with Py2.7 and Phoenix, so it looks like a
>>         Py3 issue.  Anyone has a type on how to fix this?
>>
>>     It looks like the '__hash__' method is not defined in Phoenix
>>     under Py3.4.
>>     c = wx.Colour()
>>     c.__hash__ < returns None
>>
>>     In Py2.7 I get:
>>     c = wx.Colour()
>>     c.__hash__
>>     <method-wrapper '__hash__' of Colour object at 0x0222AD68>
>>
>>
>> But is it correct?
>> For example, can you check whether hash(wx.Colour(1,2,3)) ==
>> hash(wx.Colour(1,2,3)) ?
> In py2.7:
> hash(wx.Colour(1,2,3)) == hash(wx.Colour(1,2,3))
> True
>
> But in py3.4:
> c = wx.Colour()
> c.__hash__
> hash(wx.Colour(1,2,3)) == hash(wx.Colour(1,2,3))
> Traceback (most recent call last):
>    File "<string>", line 1, in <fragment>
> builtins.TypeError: unhashable type: 'Colour'
>
> I guess something with the sip magic is not working correctly in Py3.x.
>
> Hope above will help Robin to pin point it when he gets to this.
>

 From the docs for both Python2 and Python3:
"""
An object is hashable if it has a hash value which never changes during 
its lifetime (it needs a __hash__() method), and can be compared to 
other objects (it needs an __eq__() method). Hashable objects which 
compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, 
because these data structures use the hash value internally.

All of Python’s immutable built-in objects are hashable, while non 
mutable containers (such as lists or dictionaries) are not. Objects 
which are instances of user-defined classes are hashable by default; 
they all compare unequal (except with themselves), and their hash value 
is derived from their id().
"""

SIP doesn't add a default __hash__ in either build, it just relies on 
the default Python behavior.  In Python2 that seems to be a hash value 
derived from the object's ID.  In other words, you could think of it 
like this:

   class HashableColour(wx.Colour):
       def __hash__(self):
           return do_something(id(self))

Based on the above text I would have expected the same from Python3, but 
perhaps the definition of "user-defined classes" was changed to not 
include extension types.  Or maybe that doc needs updating.

Either way, I prefer the Python3 way because basing a default hash value 
on the id() means that you must use the same instance of the key to 
fetch the value again, you can't simply use a new key with the same 
value.  For example, in Python2:

  >>> c1 = wx.Colour(1,2,3)
  >>> c2 = wx.Colour(1,2,3)
  >>>
  >>> d = {c1: 'one', c2: 'two'}
  >>> d[c1]
  'one'
  >>> d[c2]
  'two'
  >>> d[wx.Colour(1,2,3)]
  Traceback (most recent call last):
    File "<input>", line 1, in <module>
  KeyError: wx.Colour(1, 2, 3, 255)
  >>>

In Python3 Python makes you actually think about what makes sense for 
your class's hash values, it doesn't just give you some mindless 
substandard thing for free.  For wx.Colour I might choose something like:

   class HashableColour(wx.Colour):
       def __hash__(self):
           return self.GetRGBA()

or maybe even:

           return hash(self.Get()) # the hash of the tuple of color 
components

But I suppose the real question is whether we should be adding our own 
__hash__ methods to at least some of the wrapped wxPython classes.  I'll 
give that some thought.


-- 
Robin Dunn
Software Craftsman
http://wxPython.org

-- 
You received this message because you are subscribed to the Google Groups "wxPython-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.