RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1595862
Accepted
kristal
kristal
Asked:2024-10-06 20:58:00 +0000 UTC2024-10-06 20:58:00 +0000 UTC 2024-10-06 20:58:00 +0000 UTC

为什么相同的列表在创建不同时权重不同?

  • 772

我最近遇到了这个问题:

sys.getsizeof([0] * 3)  # 80
sys.getsizeof([0, 0, 0])  # 120
sys.getsizeof([0 for i in range(3)])  # 88

检查过Python 3.10.4。需要澄清的是,这种行为并不是所有版本的 Python 的特征,而只是大约3.9.19到3.10.14(但这并不精确)。

真正的问题是这里发生了什么以及为什么相同的列表权重不同?

import sys

list_1 = [0] * 3
list_2 = [0, 0, 0]
list_3 = [0 for i in range(3)]

print(list_1)  # > [0, 0, 0]
print(list_2)  # > [0, 0, 0]
print(list_3)  # > [0, 0, 0]

print(list_1 == list_2 and list_2 == list_3 and list_3 == list_1)  # > True

print(sys.getsizeof(list_1))  # > 80
print(sys.getsizeof(list_2))  # > 120
print(sys.getsizeof(list_3))  # > 88

假设第一个数组在复制后在内存中存储对同一对象的三个引用是合乎逻辑的,并且解释器以某种方式对此进行了优化。但其他数组不也会发生同样的情况吗?毕竟,Python 缓存的是从 -5 到 256 的数字,这意味着对缓存的数字 0 的三个相同引用应该存储在其他列表中。但是,问题来了:为什么对相同数字的三个引用与三个相同。引用不同的数字?同时小于列表 2 和 3 中的数字?

list_4 = list(range(3))
print(list_4)  # > [0, 1, 2]
print(sys.getsizeof(list_4))  # > 80
python
  • 1 1 个回答
  • 78 Views

1 个回答

  • Voted
  1. Best Answer
    Stanislav Volodarskiy
    2024-10-07T04:44:15Z2024-10-07T04:44:15Z
    • [0] * <константа>- 建立一个精确订购尺寸的列表。

    • [0, 0, 0, ...]- 通过一次调用构建一个列表list.extend,该列表分配具有性能裕度的空间。

    • [0 for i in range(<константа)]list.append- 通过循环调用来构建列表。再次强调,为了性能的考虑,空间分配时留有余量。但该库存的计算方式略有不同。

    详细信息如下。

    [0] * <константа>

    该表达式[0] * <константа>始终编译相同的内容并导致调用BINARY_MULTIPLY:

    n 尺寸 代码 汇编器
    ... ... ... ...
    4 88
    [0] * 4
      2 0 LOAD_CONST 1 (0) 
    2 BUILD_LIST 1
    4 LOAD_CONST 2 (4)
    6 BINARY_MULTIPLY
    ... ... ... ...

    BINARY_MULTIPLY冒险来了,它选择一个恰好符合所需大小(n)的列表并用零填充它。也就是说,列表大小始终为56 + 8n。 list_repeat

    n 0 1 2 3 4 5 6 7 8 9 10
    尺寸 56 64 72 80 88 96 104 112 120 128 136

    文字[0, 0, 0, ...]

    根据零的数量,文字的编译方式有所不同:

    n 尺寸 代码 汇编器
    0 56
    []
      2 0 构建列表 0
    1 64
    [0]
      2 0 LOAD_CONST 1 (0) 
    2 BUILD_LIST 1
    2 72
    [0, 0]
      2 0 LOAD_CONST 1 (0) 
    2 LOAD_CONST 1 (0)
    4 BUILD_LIST 2
    3 120
    [0,0,0]
      2 0 BUILD_LIST 0 
    2 LOAD_CONST 1 ((0, 0, 0))
    4 LIST_EXTEND 1
    4 120
    [0,0,0,0]
      2 0 BUILD_LIST 0 
    2 LOAD_CONST 1 ((0, 0, 0, 0))
    4 LIST_EXTEND 1
    5 120
    [0, 0, 0, 0, 0]
      2 0 BUILD_LIST 0 
    2 LOAD_CONST 1 ((0, 0, 0, 0, 0))
    4 LIST_EXTEND 1
    ... ... ... ...

    [],[0]并由构建精确列表的[0, 0]调用进行处理。BUILD_LIST在其他情况下,编译器存储一个带有零的元组(不是列表(!))并LIST_EXTEND在空列表上调用它。

    LIST_EXTEND- 通用程序。如果您在循环中调用它并将数据以小块的形式添加到列表中,那么它应该会很快。可以证明,如果它准确地为元素分配空间,则在大型列表上添加将开始减慢。因此列表的增长与它的大小大致成正比。内部令人困惑的代码list_resize是造成奇怪尖峰的原因。注意152后面的120:

    n 0 1 2 3 4 5 6 7 8 9 10
    尺寸 56 64 72 120 120 120 152 120 120 152 152

    [0 for i in range(<константа)]

    编译器平等对待所有常量。例如[0 for i in range(4)]:

      2           0 LOAD_CONST               1 (<code object  at 0x7f71c70b7260, file "", line 2>)
                  2 LOAD_CONST               2 ('comprehension_4..')
                  4 MAKE_FUNCTION            0
                  6 LOAD_GLOBAL              0 (range)
                  8 LOAD_CONST               3 (4)
                 10 CALL_FUNCTION            1
                 12 GET_ITER
                 14 CALL_FUNCTION            1
                 16 RETURN_VALUE
    
    Disassembly of <code object  at 0x7f71c70b7260, file "", line 2>:
      2           0 BUILD_LIST               0
                  2 LOAD_FAST                0 (.0)
            >>    4 FOR_ITER                 4 (to 14)
                  6 STORE_FAST               1 (i)
                  8 LOAD_CONST               0 (0)
                 10 LIST_APPEND              2
                 12 JUMP_ABSOLUTE            2 (to 4)
            >>   14
    

    创建一个空列表并用零 ( LIST_APPEND) 填充。列表的大小不是预先计算的;列表是在这个过程中不断增长的。它再次突飞猛进地增长,否则就会出现刹车。再次,令人困惑的代码list_resize。但这里调用了其他参数并导致尺寸略有不同:

    n 0 1 2 3 4 5 6 7 8 9 10
    尺寸 56 88 88 88 88 120 120 120 120 184 184

    注意:就性能而言,此选项是最差的:列表的多次重新分配,Python 中的显式循环。只是一场噩梦!

    • 7

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5