Python对象是否在内部存储为字典?

3
我可以这样创建一个Python对象。
class Test:
   pass

t1 = Test()
t1.var = "value"
t1.num = 100

并且可以使用下面的代码查看对象的字典

print(t1.__dict__)
# prints
{'var': 'value', 'num': 100}

这是否意味着Python对象在内部被存储为字典?

这似乎是特定于类实例的;并不是所有对象。 - Ma0
这次我没有找到重复项。所以很可能这是一个好的重复项。 - user202729
1个回答

1

简单解释

不是。但是在内部,所有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++)中,这通过使用函数指针数组(通常,但不保证),或虚拟表来实现,允许您动态地将预定义的一组方法更改为类。然而,由于方法名已经硬编码,这不允许动态添加或删除方法到类。除哈希映射或二叉搜索树之外的任何方法都可能无法有效地允许动态类型。

tldr

大多数情况下是可以的。但最好使用__slots__来最小化类的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接