【发布时间】:2018-06-16 04:47:20
【问题描述】:
我是 Python 新手。我最近对语法“[list] * k”感到困惑。我想了解 Python 是如何实际执行它的。 示例:
>>> l = [1, 2] * 10
>>> l
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
假设 len(list) = n,当 Python 解释它时,我以我有限的知识有以下猜测。
它使用 list.extend(list) 方法。 因此它将占用 O(n * k) 空间并使用 O(n * k) 时间。
它只复制原始列表的引用并复制它的 k 个副本。 因此它将占用 O(k) 空间并使用 O(k) 时间。
如果我的第二个猜测是这样的话,下面的陈述为什么以及如何工作?
>>> l[3] = 100
>>> l
[1, 2, 1, 100, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
强烈欢迎任何官方设计文档、源代码和 PEP 参考!
跟进,
@JoshLee 和@MSeifert 提供的源码链接对理解内部机制很有帮助。请参阅list_repeat
以下代码sn-p确认空间复杂度为O(n * k)。
size = Py_SIZE(a) * n;
以下代码 sn-p 确认时间复杂度为 O(n * k)。
p = np->ob_item;
items = a->ob_item;
for (i = 0; i < n; i++) {
for (j = 0; j < Py_SIZE(a); j++) {
*p = items[j];
Py_INCREF(*p);
p++;
}
}
【问题讨论】:
-
wiki.python.org/moin/TimeComplexity 说是 O(nk)
-
你的第一个猜测是对的。
-
如果您的第二个猜测是正确的,那么
l[3]=100不可能工作,除非引用被懒惰地转换为副本。 (请记住,Python 列表不存储实际项目,它存储对项目的引用数组)。请注意,虽然时间复杂度为 O(nk),但复制是以 C 速度进行的,因此它比使用简单的 Pythonfor循环一次复制一项要快得多。 -
(cont) 这种速度差异是如此之大,以至于对于小型列表(例如,在几百个项目以下),您可以有效地将简单的复制和扩展操作视为原子 O(1) 操作使用显式 Python 循环一一执行此类操作。有关此主题的更多信息以及计时数据,请参阅 here。
-
这是list_repeat的cpython代码。
标签: python algorithm list syntax