user1971598
user1971598

Reputation:

Where is this protocol defined?

Say we do:

class thing(object):
    pass

and then I do >>> thing.__eq__, then I get <method-wrapper '__eq__' of type object at 0x0E8B68D0>. But if we do '__eq__' in dir(thing), I get an NameError exception saying that __eq__ is not defined, but if its not defined, then how did I get a method wrapper return, clearly its defined, but if dir can't see it, where is it defined?

Upvotes: 0

Views: 146

Answers (3)

unutbu
unutbu

Reputation: 880399

dir does not list all attributes:

The docs say:

The resulting list is not necessarily complete... The default dir() mechanism behaves differently with different types of objects, as it attempts to produce the most relevant, rather than complete, information...

Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.


Also, I assume that you tested '__eq__' in dir(thing) -- note the quotation marks -- since dir returns a list of strings.


ジョージ shows a way to list all attributes based on code from the rlcompleter module:

import rlcompleter

def get_object_attrs(obj):
    """
    based on code from the rlcompleter module
    See https://stackoverflow.com/a/10313703/190597 (ジョージ)
    """
    ret = dir(obj)
    ## if "__builtins__" in ret:
    ##    ret.remove("__builtins__")
    if hasattr(obj, '__class__'):
        ret.append('__class__')
        ret.extend(rlcompleter.get_class_members(obj.__class__))
        ret = list(set(ret))
    return ret

class Thing(object):
    pass

print(get_object_attrs(Thing))

prints

['__module__', '__format__', '__itemsize__', '__str__', '__reduce__', '__weakrefoffset__', '__dict__', '__sizeof__', '__weakref__', '__lt__', '__init__', '__setattr__', '__reduce_ex__', '__subclasses__', '__new__', '__abstractmethods__', '__class__', '__mro__', '__base__', '__bases__', '__dictoffset__', '__call__', '__doc__', '__ne__', '__getattribute__', '__instancecheck__', '__subclasscheck__', '__subclasshook__', '__gt__', '__name__', '__eq__', 'mro', '__basicsize__', '__flags__', '__delattr__', '__le__', '__repr__', '__hash__', '__ge__']

From which we can obtain a list of attributes in Thing not listed by dir:

>>> print(set(get_object_attrs(Thing)) - set(dir(Thing)))

set(['__ne__', '__abstractmethods__', '__subclasses__', '__eq__', '__instancecheck__', '__base__', '__flags__', '__mro__', '__le__', '__basicsize__', '__bases__', '__dictoffset__', '__weakrefoffset__', '__call__', '__name__', '__lt__', '__subclasscheck__', '__gt__', '__itemsize__', '__ge__', 'mro'])

get_class_members(cls) collects attributes from cls and all the bases of cls.

Thus, to get a more complete list of attributes, you must add to dir the attributes of the object's class, and all the attributes of the object's class's bases.

Upvotes: 1

Luca Sbardella
Luca Sbardella

Reputation: 1124

The reason is how Python 2 handle __eq__. Check this thread for further information.

In python 3, things have changed (no more __cmp__ method) and '__eq__' is in the list of method names returned by dir(thing).

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1123620

dir(thing) returns a list of method names, all strings. Test with the actual string:

'__eq__' in dir(thing) 

This will still return False as dir() only lists a summary of the most important methods. You'd have to additionally list everything on the metaclass of thing as well, which in this case is type:

>>> '__eq__' in dir(type(thing))
True

Quoting from the documentation of dir():

Note: Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

Emphasis mine.

__eq__ is the fallback implementation here; type() defines a reasonable default (falling back to an identity test, == implemented as is) and as long as your custom class doesn't implement a custom version, that is not interesting and listing it would only needlessly clutter the result of dir().

Upvotes: 2

Related Questions