Official docs says:
If the object has a method named
__dir__()
, this method will be called and must return the list of attributes. This allows objects that implement a custom__getattr__()
or__getattribute__()
function to customize the waydir()
reports their attributes.
If custom __dir__
implemented, results, returning by another function, inspect.getmembers()
, also affected.
For example:
class С(object):
__slots__ = ['atr']
def __dir__(self):
return ['nothing']
def method(self):
pass
def __init__(self):
self.atr = 'string'
c = C()
print dir(f) #If we try this - well get ['nothing'] returned by custom __dir__()
print inspect.getmembers(f) #Here we get []
print f.__dict__ #And here - exception will be raised because of __slots__
How in this case list of names of object might be getted?
inspect.getmembers()
use __dir__()
like dir()
does?Here's the source code for inspect.getmembers()
so we can see what it's really doing:
def getmembers(object, predicate=None):
"""Return all members of an object as (name, value) pairs sorted by name.
Optionally, only return members that satisfy a given predicate."""
results = []
for key in dir(object):
try:
value = getattr(object, key)
except AttributeError:
continue
if not predicate or predicate(value):
results.append((key, value))
results.sort()
return results
From this we see that it is using dir()
and just filtering the results a bit.
__dir__()
?According to this answer, it isn't possible to always get a complete list of attributes, but we can still definitely get them in some cases/get enough to be useful.
From the docs:
If the object does not provide
__dir__()
, the function tries its best to gather information from the object’s__dict__
attribute, if defined, and from its type object. The resulting list is not necessarily complete, and may be inaccurate when the object has a custom__getattr__()
.
So if you are not using __slots__
, you could look at your object's __dict__
(and it's type object's) to get basically the same info that dir()
would normally give you. So, just like with dir()
, you would have to use a more rigorous method to get metaclass methods.
If you are using __slots__
, then getting class attributes is, in a way, a bit more simple. Yes, there's no dict, but there is __slots__
itself, which contains the names of all of the attributes. For example, adding print c.__slots__
to your example code yields ['atr']
. (Again, a more rigorous approach is needed to get the attributes of superclasses as well.)
You might need a different solution depending on the use case, but if you just want to find out the methods easily, you can simply use the builtin help()
.
dir()
Here's an alternative to some of the above: To get a version of dir()
that ignores user-defined __dir__
methods, you could just take PyPy's implementation of dir()
and delete the parts that reference __dir__
methods.