Consider this:
>>> import math
>>> dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'hypot', 'isinf', 'isnan', 'ldexp', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
__dict__ is not listed but I can still do
>>> math.__dict__
Same thing with
>>> class MyClass(object):
def __init__(self, var1, var2):
self.a = var1
self.b = var2
def __call__(self, arg):
print " The arg passed is ", arg
>>> dir(MyClass)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
__bases__ and __base__ is not listed but I can still do:
>>> MyClass.__bases__
(<type 'object'>,)
>>> MyClass.__base__
<type 'object'>
Question:
How can I know or tell in advance all the attributes reachable from a python object? In this case how can I tell that math module has __dict__ and MyClass has __base__ and __bases__ ?
If you’re looking for something completely general, there is no way to do it, because attribute lookup is dynamic. As the docs say:
The key word there is “attempt”. Down below:
Effectively, all it can do is look at the
__dict__of the object, its type, and any base classes of the type. (And then it subtracts out a few things—e.g., attributes of the type of the type are skipped to avoid exposing metaclass attributes, which you usually don’t care about). If you want the exact details, read the documentation linked above.Meanwhile, if the object has
__getattr__/__setattr__/__delattr__, or__getattribute__, or C-API equivalents of the above, it may have all kinds of attributes that aren’t in any dictionary, maybe even an infinite set of them. For example:This will print out
a. But how coulddirpossibly know thatc.aexists? Even if it could interpret my code, it would have to print out a list of all possible strings, which you obviously don’t want.There are also special attribute names that are handled in fancy ways under the covers by the interpreter.
Also, any object can define a
__dir__method to return whatever it wants.If you’re looking for something specific, you can probably do that. For example, if you’re just trying to get the attributes without subtracting out metaclass attributes, that’s just
dir(x) + dir(type(x)), or, maybe better,dir(x) + [a for a in dir(type(x)) if a not in dir(x)](to remove duplicates).But if you want to know all attributes for an object, well, you can’t.