使用插槽时,为什么 dir(type) 没有 __dict__ 属性?
When using slots, why does dir(type) have no __dict__ attribute?
我正在尝试了解插槽。因此,我编写了一个包含两个 类 的小脚本,一个使用插槽,一个不使用插槽。
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
当我在 A
类型和 A
类型的对象上使用 dir()
时,属性 __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']
如果我使用类型 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']
dir(C("test"))
的结果列表中没有属性 __dict__
,正如预期的那样,但 dir(C)
也没有属性 __dict__
。
当我可以调用 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}
由于您未在此处覆盖 __dir__
,因此在此处的每种情况下,它将在 MRO 中解析为 type.__dir__(A)
或 type.__dir__(C)
。所以我们看一下__dir__
类型的默认实现,这里在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;
}
碱基相同(object,)
,所以__dict__
中有你的答案:
>>> "__dict__" in A.__dict__
True
>>> "__dict__" in C.__dict__
False
因此,没有插槽的类型实现了一个 __dict__
描述符,但是实现了插槽的类型没有实现 - 你只是从上面得到一个 __dict__
实现:
>>> inspect.getattr_static(A, "__dict__")
<attribute '__dict__' of 'A' objects>
>>> inspect.getattr_static(C, "__dict__")
<attribute '__dict__' of 'type' objects>
我正在尝试了解插槽。因此,我编写了一个包含两个 类 的小脚本,一个使用插槽,一个不使用插槽。
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
当我在 A
类型和 A
类型的对象上使用 dir()
时,属性 __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']
如果我使用类型 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']
dir(C("test"))
的结果列表中没有属性 __dict__
,正如预期的那样,但 dir(C)
也没有属性 __dict__
。
当我可以调用 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}
由于您未在此处覆盖 __dir__
,因此在此处的每种情况下,它将在 MRO 中解析为 type.__dir__(A)
或 type.__dir__(C)
。所以我们看一下__dir__
类型的默认实现,这里在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;
}
碱基相同(object,)
,所以__dict__
中有你的答案:
>>> "__dict__" in A.__dict__
True
>>> "__dict__" in C.__dict__
False
因此,没有插槽的类型实现了一个 __dict__
描述符,但是实现了插槽的类型没有实现 - 你只是从上面得到一个 __dict__
实现:
>>> inspect.getattr_static(A, "__dict__")
<attribute '__dict__' of 'A' objects>
>>> inspect.getattr_static(C, "__dict__")
<attribute '__dict__' of 'type' objects>