Recently, I became interested in the same thing. I was looking for an answer more in line with "Regarding the fact that the Python implementation causes mro / __mro__ not display in dir ? And what can I trust dir for display?" than just "How does Python documentation justify not including mro in dir ?" I donβt like it when my expectation of behavior in a programming language does not correspond to its actual behavior, because it means that my understanding of the language is wrong - unless it is an error, for example urllib2.escape . So I stretched out a bit until I understood the answer.
The adolfopa line mentioned in the documentation in the comments above is good for explaining directory behavior.
"If the object is an object of a type or class, the list contains the names of its attributes and recursively the attributes of its bases."
What does it mean? dir recursively collects attributes from the __dict__ class and each of its __dict__ superclasses.
set(dir(object)) == set(dict(object.__dict__).keys() #True class A(object): ... class B(object): ... class C(B): ... class D(C,A): ... set(dir(D)) == set(D.__dict__.keys()) + set(C.__dict__.keys()) \ + set(B.__dict__.keys()) + set(A.__dict__.keys()) \ + set(object.__dict__.keys()) #True
The reason dir(object) does not display __mro__ / mro is because they are not attributes of the object. They are type attributes. Each class that does not define its own __metaclass__ is an instance of type . Most subclasses of type metaclasses. Instances of such metaclasses are also type instances. MyClass.__mro__ same as type.__getattribute__(MyClass,'__mro__') .
The way Python implements classes necessarily creates a slight anomaly in how dir works.
Typically, dir(MyClass) == dir(MyClass(*requiredparameters)) #True .
However, dir(type) == dir(type(*requiredparameters)) #False , but the only way that could be otherwise would be that type.__dict__ and dir were the same. This, of course, is not the purpose of dir .
But wait! dir is created by a recursive sum, why can't we just change its last fragment so that dir(object) no longer just object.__dict__.keys() , but rather becomes object.__dict__.keys() + type.__dict__.keys() . So it would have mro / __mro__ and all the other attributes that the class object has? Ah, but these will be the attributes of the class object, not the class. Well what's the difference?
Consider
list.__mro__ #(<type 'list'>, <type 'object'>)
While
[].__mro__ # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # AttributeError: 'list' object has no attribute '__mro__'
Now we are in a good place to answer that we can count on dir to list and that we can count on dir to not list. The simple answer is the one we have already reviewed. It lists all the keys of the __dict__ class __dict__ plus all the keys in each of its __dict__ superclasses, recursively. For an instance, it also includes the entire parameter in the __dict__ instance. To fill in the negative space, it does not list anything that is defined in __getattr__ or anything in __getattribute__ , unless it is also in __dict__ . It also does not list type / metatype attributes.
Another thing I feel I have to point out is: Dan's answer, which is the accepted answer at the time I am writing this, contains information that is inaccurate or at least misleading.
Attributes of inline objects cannot be set, so in a sense, type.__mro__ is read-only, but only in the same way that list.append is or type.mro , for that matter.
MyClass.__mro__ = "Hello world!" does not cause an error. It just does not affect the resolution order of the method defined in type . Thus, it may not have the effect that you expected if you were trying to change this behavior. (What he is doing is causing MyClass(*requiredparameters).__mro__ "Hello World!" , Which should have been what you would expect, since that is how class attributes are defined in python.) You can also override __mro__ for create a metaclass. If you do not override it, it is inherited, like everything else that you do not override. (If you create a metaclass that is not a subclass of the type and which is not a function that returns an instance of the type, you probably already know for sure that you are doing well enough so that you donβt worry about it, but __mro__ will not be inherited from the time you unclassify type )
According to the docs (describing super behavior):
The __mro__ attribute of type enumerates the search order of the method used by both getattr () and super (). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
Therefore, a direct change to __mro__ should behave as you expected, in much the same way as when modifying mro . However, it is usually easier to get the desired behavior by overriding the function. (Think about what you need to do to properly handle subclasses.)