Ответ Йоахима Зауэра очень хорошо объясняет, почему 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
.