[Python-3000] A plus for naked unbound methods
Nick Coghlan
ncoghlan at gmail.com
Tue Oct 7 12:10:19 CEST 2008
(added Michael to the CC list)
It isn't object that has grown an __lt__ method, but type. The extra
check Michael actually wants is a way to make sure that the method isn't
coming from the object's metaclass, and the only reliable way to do that
is the way collections.Hashable does it when looking for __hash__:
iterate through the MRO looking for that method name in the class
dictionaries.
E.g.
def defines_method(obj, method_name):
try:
mro = obj.__mro__
except AttributeError:
return False # Not a type
for cls in mro:
if cls is object and not obj is object:
break # Methods inherited from object don't count
if method_name in cls.__dict__:
return True
return False # Didn't find it
>>> class X(object):
... def __repr__(self): print "My Repr"
...
>>> class Y(X):
... def __str__(self): print "My Str"
...
>>> defines_method(object, "__repr__")
True
>>> defines_method(object, "__str__")
True
>>> defines_method(object, "__cmp__")
False
>>> defines_method(X, "__repr__")
True
>>> defines_method(X, "__str__")
False
>>> defines_method(X, "__cmp__")
False
>>> defines_method(Y, "__repr__")
True
>>> defines_method(Y, "__str__")
True
>>> defines_method(Y, "__cmp__")
False
Terry Reedy wrote:
> I strongly suspect that the same is true of every method that a user
> class inherits from a builtin class. Still, the clp OP is specifically
> interested in object as the base of his inheritance networks.
Your suspicion would be incorrect. What is actually happening is that
the behaviour of the returned method varies depending on whether or not
the object returned comes from the class itself (which will compare
equal with itself even when retrieved from a subclass), or a bound
method from the metaclass (which will not compare equal when retrieved
from a subclass, since it is bound to a different instance of the
metaclass).
In the case of the comparison methods, they're being retrieved from type
rather than object. This difference is made clear when you attempt to
invoke the retrieved method:
>>> object.__cmp__(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected 1 arguments, got 2
>>> object.__cmp__(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type.__cmp__(x,y) requires y to be a 'type', not a 'int'
>>> object.__cmp__(object)
0
>>> object.__hash__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'object' object needs an argument
>>> object.__hash__(object)
135575008
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://www.boredomandlaziness.org
More information about the Python-3000
mailing list