开发者

Why does cls.__name__ not appear in dir()?

开发者 https://www.devze.com 2023-03-28 23:25 出处:网络
Let\'s say I have a simple class: class Foobar(object): pass If I use dir(Foobar)开发者_JS百科, I\'ll get the following output:

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 but type does.
  • type's __name__ attribute is actually a descriptor.
  • Since object's metaclass is type, when object.__name__ is requested, type's __name__ descriptor is invoked.
  • The 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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消