Werner wrote:
Hi,
2014-11-27 14:38 GMT+01:00 Werner <wernerfbd@gmx.ch
<mailto:wernerfbd@gmx.ch>>:
Hi,
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.
···
On 11/27/2014 15:26, Amaury Forgeot d'Arc wrote:
On 11/18/2014 15:11, Werner wrote:
--
Robin Dunn
Software Craftsman