Для словаря Python ли iterkeys предлагают какие-либо преимущества перед viewkeys?

В Python 2.7 словари имеют как метод iterkeys, так и метод viewkeys (и аналогичные пары для значений и элементов), предоставляя два разных способа лениво перебирать ключи словаря. Метод viewkeys обеспечивает основную функцию iterkeys, при этом iter(d.viewkeys()) эффективно эквивалентен d.iterkeys(). Кроме того, объекты, возвращаемые viewkeys, имеют удобные функции, подобные множеству. Таким образом, есть веские основания утверждать viewkeys более iterkeys.

Как насчет другого направления? Помимо совместимости с более ранними версиями Python, есть ли способы, в которых iterkeys было бы предпочтительнее viewkeys? Будет ли что-то потеряно, просто используя viewkeys?

Ответ 1

Нет, нет преимущества iterkeys над viewkeys, таким же образом, что нет никакого преимущества для keys по любому из них. iterkeys поддерживается только для совместимости. Действительно, в Python 3, viewkeys является единственным поведением, которое все еще существует, и оно было переименовано в keys - метод viewkeys на самом деле является backport поведения Python 3.

Ответ 2

Словарь обновляет словаря, как и словарь, в то время как итератор не обязательно делает это.

Это означает, что если вы работаете с представлением, измените словарь, а затем снова работайте с представлением, представление изменится, чтобы отразить новое состояние словаря.

Они обеспечивают динамический просмотр записей словарей, что означает, что при изменении словаря представление отражает эти изменения. Источник

Пример:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> del test[1]
>>> test[5] = 6
>>> list(a)
[3, 5]
>>> b
dict_keys([3, 5])

Когда будут внесены изменения в размер, будет выбрано исключение:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> test[5] = 6
>>> list(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> b
dict_keys([1, 3, 5])

Также стоит отметить, что вы можете перебирать только одно ключевое слово:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> list(a)
[1, 3]
>>> list(a)
[]
>>> b = test.viewkeys()
>>> b
dict_keys([1, 3])
>>> b
dict_keys([1, 3])

Ответ 3

Функционально, как вы заметили, взгляды лучше. Совместимость - они хуже.

Некоторые показатели производительности, взятые из Python 2.7.2 на 64-разрядной машине Ubuntu:

>>> from timeit import timeit

Работа с пустым словарем:

>>> emptydict = {}
>>> timeit(lambda: emptydict.viewkeys())
0.24384498596191406
>>> timeit(lambda: list(emptydict.viewkeys()))
0.4636681079864502
>>> timeit(lambda: emptydict.iterkeys())
0.23939013481140137
>>> timeit(lambda: list(emptydict.iterkeys()))
1.0098130702972412

Построение представления немного дороже, но потребление представления значительно быстрее, чем итератор (бит в два раза быстрее).

Работа с тысячным элементом словаря:

>>> fulldict = {i: i for i in xrange(1000)}
>>> timeit(lambda: fulldict.viewkeys())
0.24295306205749512
>>> timeit(lambda: list(fulldict.viewkeys()))
13.447425842285156
>>> timeit(lambda: fulldict.iterkeys())
0.23759889602661133
>>> timeit(lambda: list(fulldict.iterkeys()))
15.45390510559082

Те же результаты, хотя и менее выраженные; построение обзора очень немного дороже, но потребление его довольно определенно быстрее (на 15% быстрее).

Для справедливого сравнения с list(dict.viewkeys()) и list(dict.iterkeys()), dict.keys() является отчетливым:

>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778

Резюме: это компромисс; улучшенная функциональность (которую вы редко используете) и производительность (что будет очень редко быть достаточно значительным, чтобы вас беспокоить), если вы заботитесь о таких вопросах производительности, вы, вероятно, уже находитесь в регионе, где вам нужно работать с numpy/scipy ) против лучшей совместимости и использования памяти мышц.

Лично, если уже в зависимости от функциональности с 2,7 или если я полностью контролирую среду выполнения, я бы избегал словарных представлений в коде Python 2. Даже в этих случаях мои пальцы все еще хотят набрать iter вместо view, поэтому я даю им!

Ответ 4

Как видно из названия (и ), методы viewkeys(), viewvalues() и viewitems() возвращают представление о текущих элементах словаря, что означает что если словарь изменяется, то и вид; просмотров lazy. В общем случае вид ключей задан, и представления элементов только заданы, если значения хешируются.

В каких случаях лучше использовать стандартные методы keys(), values() и items()? Вы упомянули очень важную: обратную совместимость. Кроме того, когда вам нужно иметь простой список всех ключей, значений или элементов (а не как набор, а не итератор), когда вам нужно изменить возвращенный список без изменения оригинального словаря и когда вам нужен снимок словарные ключи, значения или элементы в момент времени, независимо от любых последующих модификаций по словарю.

А как насчет iterkeys(), itervalues() и iteritems()? Они являются подходящей альтернативой, когда вам нужен однократный, постоянный пробел, ленивый снимок итератора содержимого словаря, который скажет вам, изменился ли словарь во время итерации (через RuntimeError), также они очень важны для обратной совместимости.