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

dict методы dict.keys(), dict.items() и dict.values ​​() возвращают "views" вместо списков. http://docs.python.org/dev/3.0/whatsnew//3.0.html

Прежде всего, как отличается взгляд от итератора? Во-вторых, в чем преимущество этого изменения? Это просто по соображениям производительности?

Мне это не кажется интуитивным, т.е. я прошу список вещей (дайте мне все свои ключи), и я снова получаю что-то еще. Будет ли это путать людей?

Ответ 1

Вы эффективно получаете список. Это просто не копия внутреннего списка, а нечто, что действует так, как если бы оно имело список, но только представляло внутреннее состояние.

То же самое реализовано в Java (и, возможно, во многих других языках и средах).

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

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

Ответ 2

Ответ Joachim Sauer очень хорошо объясняет, почему list не возвращается. Но это ставит вопрос о том, почему эти функции не возвращают итераторы, так же как и iteritems и т.д. В Python 2.

Итератор гораздо более ограничительный, чем контейнер. Например, итератор не допускает более одного прохода; если вы попробуете второй проход, вы найдете его пустым. Поэтому операции, такие как elem in cont, поддерживаются контейнерами, но не могут поддерживаться итераторами: как только вы проверяете, находится ли элемент в "итераторе", итератор уничтожается!

С другой стороны, для получения контейнера обычно требуется создать копию, например, создать список из ключей словаря.

Объект view имеет лучшее из обоих миров: он ведет себя как контейнер и все же не делает копию словаря! Это, фактически, своего рода виртуальный контейнер только для чтения, который работает путем ссылки на базовый словарь. Я не знаю, видел ли он где-нибудь еще в стандартном Python.

Edit:

@AntonyHatchkins: причина, по которой он не возвращает функцию генератора, заключается в том, что она не позволит выполнить быструю операцию in. Да, in работает для функций генератора (когда вы их вызываете). То есть вы можете сделать это:

def f():
  for i in range(10):
    yield i

5 in f() # True

Но согласно определению in, если правая часть является генератором, python будет проходить через все элементы n генератора, что приведет к сложности времени O(n). Там вы ничего не можете с этим поделать, потому что единственным значимым поведением является произвольный генератор.

С другой стороны, в случае словарного представления вы можете реализовать in любым способом, потому что вы знаете больше о данных, которыми вы управляете. И фактически in реализуется с помощью O(1) сложности с использованием хеш-таблицы. Вы можете проверить его, запустив

>>> d = dict(zip(range(50000000), range(50000000)))
>>> 49999999 in d
True
>>> 49999999 in iter(d) # kinda how generator function would work
True
>>>

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

Ответ 3

Как уже упоминалось в связанном вопросе, в представлении есть метод len(), которого не хватает итератору (но у него есть список).

Другим преимуществом возврата представления вместо списка является то, что по крайней мере для ключей он имеет оптимизированное тестирование членства в операциях O (1) вместо O (N) для списка (или итератора).