<p>agf接受的答案并不是将like与like进行比较。之后:</p>
<pre><code>print timeit("d[0] = d.get(0, []) + [1]", "d = {1: []}", number = 10000)
</code></pre>
<p><code>d[0]</code>包含一个包含10000个项的列表,而在之后:</p>
<pre><code>print timeit("d.setdefault(0, []) + [1]", "d = {1: []}", number = 10000)
</code></pre>
<p><code>d[0]</code>只是<code>[]</code>。i、 e.<code>d.setdefault</code>版本从不修改存储在<code>d</code>中的列表。代码实际上应该是:</p>
<pre><code>print timeit("d.setdefault(0, []).append(1)", "d = {1: []}", number = 10000)
</code></pre>
<p>而且事实上比错误的<code>setdefault</code>示例更快。</p>
<p>这里的区别实际上是因为当您使用连接进行追加时,每次都会复制整个列表(并且一旦有10000个元素开始变得可测量)。使用<code>append</code>列表更新按O(1)摊销,即有效的恒定时间。</p>
<p>最后,在最初的问题中还有两个未考虑的选项:<code>defaultdict</code>,或者只是测试字典,看看它是否已经包含了密钥。</p>
<p>所以,假设<code>d3, d4 = defaultdict(list), {}</code></p>
<pre><code># variant 1 (0.39)
d1[key] = d1.get(key, []) + [val]
# variant 2 (0.003)
d2.setdefault(key, []).append(val)
# variant 3 (0.0017)
d3[key].append(val)
# variant 4 (0.002)
if key in d4:
d4[key].append(val)
else:
d4[key] = [val]
</code></pre>
<p>到目前为止,variant 1是最慢的,因为它每次都会复制列表,variant 2是第二慢的,variant 3是最快的,但如果您需要2.5以上的Python,它就不起作用,variant 4只是比variant 3慢一点。</p>
<p>如果可以的话,我会说使用variant 3,使用variant 4作为那些<code>defaultdict</code>不完全适合的地方的选项。避免两种原始变体。</p>