使用槽时,为什么 dir(type) 没有 __dict__ 属性?

Mic*_*fer 8 python python-3.6

我正在尝试了解插槽。因此,我编写了一个包含两个类的小脚本,一个使用插槽,一个不使用插槽。

class A:
    def __init__(self, name):
        self.name = name

    def getName(self):
        return self.name

class C:
    __slots__ = "name"

    def __init__(self, name):
        self.name = name

    def getName(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)

dir()当我在类型A为 on 的对象上使用on 类型时A,该属性__dict__将按预期出现在结果列表中。

dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getName']

dir(A("test"))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'getName', 'name']
Run Code Online (Sandbox Code Playgroud)

如果我使用类型C我得到

print(dir(C))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'classAttributeC', 'getName', 'name']

print(dir(C("test")))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'classAttributeC', 'getName', 'name']
Run Code Online (Sandbox Code Playgroud)

__dict__正如预期的那样,的结果列表中没有 的属性dir(C("test")),但 的 也没有__dict__属性dir(C)C.__dict__当我可以调用并获得以下输出时,为什么结果列表中没有该属性?

{'__module__': '__main__', 'classAttributeC': 9999, '__slots__': 'name', '__init__': <function C.__init__ at 0x7ff26b9ab730>, 'getName': <function C.getName at 0x7ff26b9ab7b8>, 'name': <member 'name' of 'C' objects>, '__doc__': None}
Run Code Online (Sandbox Code Playgroud)

wim*_*wim 7

由于您没有__dir__在此处覆盖,因此在每种情况下,它将在 MRO 中解析为type.__dir__(A)type.__dir__(C)。所以我们看看__dir__for 类型的默认实现,在这里Objects/typeobject.c

/* __dir__ for type objects: returns __dict__ and __bases__.
   We deliberately don't suck up its __class__, as methods belonging to the
   metaclass would probably be more confusing than helpful.
*/
static PyObject *
type___dir___impl(PyTypeObject *self)
{
    PyObject *result = NULL;
    PyObject *dict = PyDict_New();

    if (dict != NULL && merge_class_dict(dict, (PyObject *)self) == 0)
        result = PyDict_Keys(dict);

    Py_XDECREF(dict);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

基础是相同的(object,),所以你的答案在__dict__

>>> "__dict__" in A.__dict__
True
>>> "__dict__" in C.__dict__
False
Run Code Online (Sandbox Code Playgroud)

因此,没有插槽的类型实现__dict__描述符,但实现插槽的类型则不会 - 并且您只需__dict__从上面获得一个实现:

>>> inspect.getattr_static(A, "__dict__")
<attribute '__dict__' of 'A' objects>
>>> inspect.getattr_static(C, "__dict__")
<attribute '__dict__' of 'type' objects>
Run Code Online (Sandbox Code Playgroud)