Answer to original question- does 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.
How to get attributes with an overridden __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.)
How to get methods
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()
.
Modified PyPy 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.