栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

为什么在python 3中实例的__dict__这么小?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为什么在python 3中实例的__dict__这么小?

简而言之

实例

__dict__
的实现方式与用
dict
或创建的“普通”词典的实现方式不同
{}
。实例的字典 共享
键和哈希,并为不同的部分(值)保留一个单独的数组。
sys.getsizeof
仅在计算实例字典的大小时才计算这些值。

还有一点

从Python 3.3开始,CPython中的字典以以下两种形式之一实现:

  • 组合字典字典的 所有值都与每个条目的键和哈希值一起存储。(struct的
    me_value
    成员
    PyDictKeyEntry
    )。据我所知,这种形式被用于与创建字典
    dict
    {}
    和模块命名空间。
  • 分裂表 :该值被存储 分别 在阵列,而密钥和散列共享(存储在值
    ma_values
    PyDictObject

实例字典 始终 以拆分表形式(“密钥共享字典”)实现,该字典表允许给定类的实例为其共享密钥(和散列),

__dict__
并且仅在相应值上有所不同。

所有这些都在PEP
412-密钥共享字典中进行了描述
。拆分字典的实现位于Python中,

3.3
因此该
3
系列的早期版本以及Python
2.x
都没有此实现。

__sizeof__
for字典的实现考虑到了这一事实,并且在计算拆分字典的大小时仅考虑与values数组对应的大小。

值得庆幸的是,自我解释:

Py_ssize_t size, res;size = DK_SIZE(mp->ma_keys);res = _PyObject_SIZE(Py_TYPE(mp));if (mp->ma_values)             res += size * sizeof(PyObject*);if (mp->ma_keys->dk_refcnt == 1)         res += sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry);return res;

据我所知, 仅针对实例的名称空间创建 拆分表字典,使用

dict()
{}
(如PEP中所述) 始终会 导致组合字典没有这些好处。


顺便说一句,因为它很有趣,所以我们总是可以打破这种优化。我目前发现了两种当前的方法,一种愚蠢的方法,或者是一种更为明智的情况:

  1. 傻:
    >>> f = Foo(20, 30)

    getsizeof(vars(f))
    96
    vars(f).update({1:1}) # add a non-string key
    getsizeof(vars(f))
    288

拆分表仅支持字符串键,添加非字符串键(这实际上是 意义)会破坏该规则,CPython将拆分表变成一个合并的表,从而失去了所有内存。

  1. 可能发生的情况:
    >>> f1, f2 = Foo(20, 30), Foo(30, 40)

    for i, j in enumerate([f1, f2]):
    … setattr(j, ‘i’+str(i), i)
    … print(getsizeof(vars(j)))
    96
    288

在类的实例中插入不同的键最终将导致拆分表被合并。这并不仅仅适用于已经创建的实例。从该类创建的所有 后续 实例将具有组合字典,而不是拆分字典。

    # after running previous snippet>>> getsizeof(vars(Foo(100, 200)))288

当然,除了娱乐之外,没有其他理由是故意这样做的。


如果有人想知道,Python
3.6的字典实现不会改变这一事实。前面提到的两种形式的字典仍然可以使用(它们的实现

dict.__sizeof__
也作了更改,因此从中返回的值应该有所区别)被进一步压缩
getsizeof



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/624898.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号