简单说明
没有。但在内部,所有 Python 对象(使用 __slots__ 或 Python 内置函数定义的对象除外)都使用字典进行动态属性访问。
正如您在下面的示例中看到的,使用__slots__ 使该类型不存储内部字典,从而阻止为该类型动态设置方法、字段或其他信息。但是,类型的大小会因此而减小。
In [7]: class A:
...: __slots__ = ('fields')
...: def __init__(self):
...: self.fields = 1
...:
In [9]: dir(A)
Out[9]:
['__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__',
'fields']
如果您查看 CPython 源代码 code,您还会看到大多数内置类型也没有存储为字典:
#ifndef Py_LIMITED_API
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
#endif
基本原理
要理解为什么所有允许动态设置变量、方法和其他信息的类在内部使用字典来存储这些信息,我们需要考虑一下字典非常擅长:O(1) 信息访问与O(1) 插入和删除.由于解释器不知道类可能具有哪些属性,如果该属性是变量、方法等,直到运行时,这需要在运行时使用某种绑定到类的容器。在其他语言中,如 C++,这是使用函数指针数组(通常,尽管不保证)或虚拟表来实现的,允许您动态更改类的预定义方法集。但是,由于方法名称已经被硬编码,这不允许动态地向类添加或删除方法。除了 hashmap 或二叉搜索树之外的任何方法都可能无法有效地允许动态类型。
tldr
大多数情况下,是的。最理想的是,没有。使用__slots__ 来最小化你的类的大小。