Why does cls.__name__ not appear in dir()?
Let's say I have a simple class:
class Foobar(object):
pass
If I use dir(Foobar)
开发者_JS百科, 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 buttype
does.type
's__name__
attribute is actually a descriptor.- Since
object
's metaclass istype
, whenobject.__name__
is requested,type
's__name__
descriptor is invoked. - The
name
descriptor looks up the name in thetype->tp_name
slot. Thetype->tp_name
slot is populated bytype.__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.
According to the python documentation about the dir() method, you can implement a __dir__() method on your object that returns the list of the items you want to see when calling a dir on your object.
The __name__ member is part of some special attributes of python objects, and as says the documentation :
Some of these are not reported by the dir() built-in function.
I've encountered this problem when writing pytests. Although, people explain why, no work-around was suggested. The only work-around I found was to move .py files to another directory and then import them.
精彩评论