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) для списка (или итератора).