Что представляют собой объекты просмотра словаря Python?

В python 2.7 мы получили доступные методы просмотра словарей .

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

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

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

Я читал, что представление всегда отражает изменения в словаре. Но как он ведет себя с точки зрения перфорации и памяти? Что такое про и недостатки?

Ответ 1

Словарь выглядит по существу тем, что говорит их имя: виды просто похожи на окно на клавиши и значения (или элементы) словаря. Вот выдержка из официальной документации для 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 часто излишне создает новый список, цитируемый Rajendran T, который занимает память и время в размере, пропорциональном длине списка). Чтобы продолжить аналогию с окном, если вы хотите увидеть пейзаж за стеной, вы просто открываете его (вы строите окно); копирование ключей в список соответствовало бы, вместо того, чтобы покрасить копию пейзажа на стене - копия занимает время, пространство и не обновляется сама.

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

Ответ 2

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

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

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

Ответ 3

Как вы упоминали 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

В то время как представление просто показывает вам, что в dict. Его не волнует, изменилось ли оно:

>>> 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() вызвало бы ошибку.

Ответ 4

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

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

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

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

Ответ 5

Представления позволяют получить доступ к структуре данных подстилки без копирования. Помимо динамического, а не создания списка, одним из наиболее полезных способов использования является 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 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 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 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