Принятый ответ от agf не похож на лайк.После:
print timeit("d[0] = d.get(0, []) + [1]", "d = {1: []}", number = 10000)
d[0]
содержит список из 10000 элементов, тогда как после:
print timeit("d.setdefault(0, []) + [1]", "d = {1: []}", number = 10000)
d[0]
означает просто []
.то есть версия d.setdefault
никогда не изменяет список, хранящийся в d
.На самом деле код должен быть:
print timeit("d.setdefault(0, []).append(1)", "d = {1: []}", number = 10000)
и на самом деле он быстрее, чем ошибочный пример setdefault
.
Разница здесь на самом деле в том, что когда вы добавляете с помощью конкатенации, весь списоккопируется каждый раз (и когда у вас есть 10 000 элементов, которые начинают измериться. При использовании append
обновления списка амортизируются O (1), то есть фактически постоянным временем.
Наконец, есть еще два варианта:рассматривается в первоначальном вопросе: defaultdict
или просто тестирование словаря, чтобы увидеть, содержит ли он уже ключ.
Итак, если предположить, что d3, d4 = defaultdict(list), {}
# 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]
вариант 1, безусловно, являетсясамый медленный, потому что он копирует список каждый раз, вариант 2 - второй самый медленный, вариант 3 - самый быстрый, но он не будет работать, если вам нужен Python старше 2.5, а вариант 4 лишь немного медленнее, чем вариант 3.
Я бы сказал, используйте вариант 3, если можете, с вариантом 4 в качестве опции для тех случайных мест, где defaultdict
не совсем подходит. Избегайте обоих ваших илиоригинальные варианты.