Issue
This is pertaining to python 2.x
In the following class, if we subclass "object", I understand the methods are inherited in the derived class Foo which includes __hash__
(can see this by printing dir(Foo() )
Hence calling hash(Foo()) calls the magic method __hash__
and gives us a hash value.
However, if we don't subclass "object", resulting in dir(Foo()) not listing out the __hash__
method, so then why do we still get a hash value in python2?
I believe in python3 this problem has been addressed since the methods from the "object*" class are inherited by default.
#class Foo(object) Works since __hash__ is available in the base class
class Foo: #Why does this work?
def __init__(self):
self.x = None
a = Foo()
print dir(a) # No __hash__ magic method
print hash(a)
# Expecting an error like non-hashable or __hash__ not implemented
# or something similar
Solution
Old-style classes are weird. Officially, instances of old-style classes aren't wholly instances of their class, they're all instances of type instance
. The instance
type defines __hash__
(tp_hash
is the C level slot that's equivalent to __hash__
for C defined types), so even though it's not defined on your instance directly, nor on the class that created it, it finds __hash__
on the instance
type itself through weird and terrible magic (actually, the magic is in how it manages to use your class's features at all, given that its type is instance
).
You can see this in the interactive interpreter:
>>> class Foo: pass
>>> Foo().__hash__ # Same basic error for Foo.__hash__ too
AttributeError Traceback (most recent call last)
...
----> 1 Foo().__hash__
AttributeError: Foo instance has no attribute '__hash__'
>>> type(Foo())
<type 'instance'>
>>> type(Foo()).__hash__
<slot wrapper '__hash__' of 'instance' objects>
This works even though the instance itself can't see __hash__
because "special methods" (those documented special methods that begin and end with double underscores) are looked up on the type, not the instance, so __hash__
is found on instance
itself. At the C level, hash(x)
is doing the equivalent of type(x).__hash__(x)
(it's a little more complicated because it won't use the default __hash__
implementation if __eq__
has a custom definition, but that's the general idea).
Answered By - ShadowRanger
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.