Let's say I have a simple class:
class Foobar(object):
pass
If I use dir(Foobar)
, I'll get the following output:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Even though it does not appear in the output of dir()
, I can access __name__
:
Foobar.__name__
and get Foobar
.
Why does Python behave that way?
dir
is not guaranteed to return all possible attributes. From the docs:
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.
Answers on a recent dupe of this question have lead me to want to elaborate on this answer a little bit more. First, the accepted answer is correct. dir
simply calls the __dir__
hook method and the default __dir__
hook method usually just returns the keys of the object's __dict__
.
Second, __name__
isn't in object.__dict__
and it doesn't get put in the __dict__
of subclasses either. If it isn't in __dict__
, where is it and how does it get looked up?
As I understand the source code, there are a number of descriptors which are set by type
during class creation. One of these descriptors is __name__
. The __name__
getter calls type_name and the setter calls type_set_name. These getters/setters actually get/set the name in the tp_name
slot of the type object instance (i.e. the class). Since this is actually a special slot on the type object, it doesn't actually live in the class __dict__
and therefore it doesn't get reported by vars
or dir
.
Note that dir
for type object instances (i.e. classes) specifically does not add members from the from the __class__
attribute because "methods belonging to the metaclass would probably be more confusing than helpful".
So, let's put this all together.
object
doesn't have a __name__
attribute but type
does.type
's __name__
attribute is actually a descriptor. object
's metaclass is type
, when object.__name__
is requested, type
's __name__
descriptor is invoked.name
descriptor looks up the name in the type->tp_name
slot. The type->tp_name
slot is populated by type.__new__
when the class is created.object.__dir__
is specifically written to not report properties on the class's metaclass since the python devs believe that would do more harm than good.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With