Что такое объекты словарного представления? - PullRequest
144 голосов
/ 22 января 2012

В Python 2.7 у нас есть доступные методы просмотра словаря .

Теперь я знаю плюсы и минусы следующего:

  • dict.items()values, keys): возвращает список, чтобы вы могли фактически сохранить результат, а
  • dict.iteritems() (и т. п.): возвращает генератор, поэтому вы можете выполнять итерации по каждомуЗначение генерируется один за другим.

Для чего dict.viewitems() (и т.п.)?Каковы их преимущества?Как это работает?Что такое представление в конце концов?

Я прочитал, что представление всегда отражает изменения из словаря.Но как это ведет себя с точки зрения перфом и памяти?Какие плюсы и минусы?

Ответы [ 5 ]

145 голосов
/ 22 января 2012

Представления словаря - это, по сути, их название: представления просто похожи на окно для ключей и значений (или элементов) словаря.Вот выдержка из официальной документации для Python 3:

>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()

>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> keys  # No eggs anymore!
dict_keys(['sausage', 'bacon', 'spam'])

>>> values  # No eggs value (2) anymore!
dict_values([1, 1, 500])

(эквивалент Python 2 использует dishes.viewkeys() и dishes.viewvalues().)

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

Одним из преимуществ является то, что смотрит на, скажем,ключи используют только небольшой и фиксированный объем памяти и требуют небольшой фиксированный объем процессорного времени , так как не создается список ключей (Python 2, с другойстороны, часто излишне создающие новый список, как цитирует Раджендран Т, который занимает память и время в количестве, пропорциональном длине списка).Чтобы продолжить аналогию с окном, если вы хотите увидеть пейзаж за стеной, вы просто делаете в нем отверстие (вы строите окно);Копирование ключей в список будет соответствовать рисованию копии ландшафта на вашей стене - копия занимает время, пространство и не обновляется сама.

Подводя итог, можно сказать, что виды - это просто ... виды (окна)в вашем словаре, которые показывают содержимое словаря даже после его изменения.Они предлагают функции, которые отличаются от функций списков: список ключей содержит копию ключей словаря в данный момент времени, в то время как представление является динамическим и его получение намного быстрее, поскольку оно недолжны быть скопированы любые данные (ключи или значения) для создания.

20 голосов
/ 17 мая 2013

Как вы упомянули, dict.items() возвращает копию списка словаря пар (ключ, значение), который является расточительным, а dict.iteritems() возвращает итератор для пар словаря (ключ, значение).

Теперь возьмем следующий пример, чтобы увидеть разницу между интегратором dict и представлением dict

>>> d = {"x":5, "y":3}
>>> iter = d.iteritems()
>>> del d["x"]
>>> for i in iter: print i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Принимая во внимание, что представление просто показывает вам, что в диктанте. Не важно, изменилось ли оно:

>>> d = {"x":5, "y":3}
>>> v = d.viewitems()
>>> v
dict_items([('y', 3), ('x', 5)])
>>> del d["x"]
>>> v
dict_items([('y', 3)])

Представление - это просто то, как словарь выглядит сейчас. После удаления записи .items() был бы устаревшим, а .iteritems() выдал бы ошибку.

16 голосов
/ 22 января 2012

Просто читая документы, я получаю такое впечатление:

  1. Представления "псевдо-подобны", так как они не поддерживают индексацию, поэтому вы можете сделать с ними тестдля членства и итерации по ним (поскольку ключи являются хэшируемыми и уникальными, представления ключей и элементов более «похожи на наборы», так как они не содержат дубликатов).
  2. Вы можете хранить их и использовать их нескольковремя, как версии списка.
  3. Поскольку они отражают базовый словарь, любое изменение в словаре изменит представление и почти наверняка изменит порядок итерации .Поэтому, в отличие от версий списка, они не являются «стабильными».
  4. Поскольку они отражают базовый словарь, они почти наверняка являются небольшими прокси-объектами;копирование ключей / значений / элементов потребовало бы, чтобы они как-то смотрели исходный словарь и копировали его несколько раз, когда происходят изменения, что было бы абсурдной реализацией.Так что я ожидал бы очень небольшую нагрузку на память, но доступ был бы немного медленнее, чем непосредственно к словарю.

Так что я предполагаю, что ключевой вариант использования - если вы держите словарь вокруг себя и многократно повторяетеего ключи / предметы / значения с изменениями между ними.Вместо этого вы можете просто использовать вид, превратив for k, v in mydict.iteritems(): в for k, v in myview:.Но если вы просто перебираете словарь один раз, я думаю, что iter-версии все еще предпочтительнее.

16 голосов
/ 22 января 2012

Методы представления возвращают список (не копия списка, по сравнению с .keys(), .items() и .values()), поэтому он более легкий, но отражает текущее содержимое словаря.

С Python 3.0 - методы dict возвращают представления - почему?

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

Если вы просто хотите перебрать ключи, тогда создайте новый список не обязательно. И если вам действительно нужно это как отдельный список (как скопировать), то вы можете легко создать этот список из представления.

5 голосов
/ 06 октября 2017

Представления позволяют получить доступ к базовой структуре данных, не копируя ее. Помимо того, что он динамичен, а не создает список, одним из наиболее полезных примеров является in test. Скажем, вы хотите проверить, есть ли значение в поле dict или нет (будь то ключ или значение).

Первый вариант - создать список ключей, используя dict.keys(), это работает, но, очевидно, потребляет больше памяти. Если диктат очень большой? Это было бы расточительно.

С помощью views вы можете выполнять итерацию фактической структуры данных без промежуточного списка.

Давайте использовать примеры. У меня есть диктант с 1000 ключами случайных строк и цифр, и k - это ключ, который я хочу найти

large_d = { .. 'NBBDC': '0RMLH', 'E01AS': 'UAZIQ', 'G0SSL': '6117Y', 'LYBZ7': 'VC8JQ' .. }

>>> len(large_d)
1000

# this is one option; It creates the keys() list every time, it's here just for the example
timeit.timeit('k in large_d.keys()', setup='from __main__ import large_d, k', number=1000000)
13.748743600954867


# now let's create the list first; only then check for containment
>>> list_keys = large_d.keys()
>>> timeit.timeit('k in list_keys', setup='from __main__ import large_d, k, list_keys', number=1000000)
8.874809793833492


# this saves us ~5 seconds. Great!
# let's try the views now
>>> timeit.timeit('k in large_d.viewkeys()', setup='from __main__ import large_d, k', number=1000000)
0.08828549011070663

# How about saving another 8.5 seconds?

Как видите, итерация объекта view значительно повышает производительность, уменьшая при этом нагрузку на память. Вы должны использовать их, когда вам нужно выполнить Set подобные операции.

Примечание : я работаю на Python 2.7

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...