Если вам нужно обновить словарь вместо , вам придется перебирать ключи, чтобы ваш был хорошим и удобочитаемым методом.Это также быстрее, чем альтернативные методы обновления вашего словаря или даже создания нового словаря с теми же ключами!
Вы можете отбросить вызов items()
, если вас не интересуют значения.Просто зацикливайтесь прямо над словарем, чтобы получить ключи:
for k in z:
z[k] = ""
Альтернатива - использовать dict.fromkeys()
для создания нового пустого словаря.Чтобы обновить существующий dict на месте (чтобы другие ссылки на тот же словарь увидели изменения), вы можете вызвать z.update()
, передавая в новом словаре:
# set all values to an empty string, in place
z.update(dict.fromkeys(z, ""))
Недостатком будетВозможно, вам понадобится добавить комментарий, чтобы объяснить, чего должна достичь эта линия.Это также медленнее , потому что новый объект создается только для обновления существующего объекта.Кроме того, вы хотите осторожно , используя dict.fromkeys()
, поскольку вторым аргументом является единственное значение, которое повторно используется для всех ключей.Это имеет значение, если вы должны использовать изменяемое значение, такое как список.Если вам нужен только новый словарь, вы должны набрать z.update()
и просто присвоить результат dict.fromkeys()
непосредственно z
.
Предполагая, что вам нужно обновления на месте , быстрое сравнение различий в производительности:
>>> from timeit import Timer
>>> testdict = {i: i for i in range(10 ** 6)}
>>> def explicit_loop(d):
... d = d.copy()
... for k in d:
... d[k] = ""
...
>>> def dict_fromkeys(d):
... d = d.copy()
... d.update(dict.fromkeys(d, ""))
...
>>> def base_copy(d):
... d = d.copy()
...
>>> count, total = Timer("f(t)", "from __main__ import base_copy as f, testdict as t").autorange()
>>> base_copy_time = total / count
>>> for f in (explicit_loop, dict_fromkeys):
... count, total = Timer("f(t)", f"from __main__ import {f.__name__} as f, testdict as t").autorange()
... print(f"{f.__name__:>15}: {((total / count) - base_copy_time) * 1000:.2f} milliseconds")
...
explicit_loop: 43.15 milliseconds
dict_fromkeys: 68.66 milliseconds
Обратите внимание, что для обеспечения точного теста входной словарь необходимо копировать каждый раз, поэтому существует base_copy
тест для настройки времени.
Вы можете видеть, что явный цикл по z
явно выиграл.Но даже если вам не необходимо обновить словарь на месте, использование dict.fromkeys()
медленнее, чем обновление z
на месте!
Обновление на месте ненеобходимо динамически изменять размер словаря, чтобы соответствовать произвольному количеству ключей, и не нужно создавать новый объект:
>>> def dict_fromkeys_no_update(d):
... d = d.copy() # to keep comparisons fair, copy only needed for the loop case
... d = dict.fromkeys(d, "")
...
>>> for f in (explicit_loop, dict_fromkeys_no_update):
... count, total = Timer("f(t)", f"from __main__ import {f.__name__} as f, testdict as t").autorange()
... print(f"{f.__name__:>25}: {((total / count) - base_copy_time) * 1000:.2f} milliseconds")
...
explicit_loop: 41.27 milliseconds
dict_fromkeys_no_update: 54.78 milliseconds
Итак, нужен ли вам новый словарь или обновление на месте, простопростой цикл Python над существующими ключами словаря является здесь бесспорным победителем.