[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