Reputation:
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
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
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
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