Python: функция list () портит карту ()

1

Я немного играл с функциями map() и filter() на python 3. Я попытался взять список и отфильтровать его, а затем на объект фильтра, чтобы выполнить функцию карты:

f = list(range(10))
print(f)
print('-----------')
y = filter(lambda a: a > 5, f)
print(list(y))
print(y)
print(type(y))
print('-----------')
x = map(lambda value: value+1, y)
print(list(y))
print(y)
print(type(y))
print('-----------')
print(list(x))
print(x)
print(type(x))

Результат:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-----------
[6, 7, 8, 9]
<filter object at 0x7f46db255ac8>
<class 'filter'>
-----------
[]
<filter object at 0x7f46db255ac8>
<class 'filter'>
-----------
[]
<map object at 0x7f46db3fc128>
<class 'map'>

Когда я комментирую print(list(y)) она внезапно работает хорошо. Вы столкнулись с этим? Что я делаю неправильно? Я запускаю python 3.6.3 на ubuntu.

  • 3
    Вызов list() для y потребляет итератор. Итераторы могут использоваться только один раз. Когда вы вызываете выход y во второй раз в print() не остается значений для выхода. Вы можете увидеть это просто с помощью: y = filter(lambda a: a > 5, f); print(list(y)); print(list(y))
  • 0
    @roganjosh вы должны опубликовать это как ответ.
Показать ещё 5 комментариев
Теги:
list
python-3.x
dictionary
filter

2 ответа

8

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

Это более четко демонстрируется:

f = list(range(10))
print(f)
print('-----------')
y = filter(lambda a: a > 5, f)
print(list(y))
print(list(y))

Который дает:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-----------
[6, 7, 8, 9]
[] # Nothing to yield

Если вы хотите сохранить значения в y вам нужно будет присвоить ему имя:

y = list(filter(lambda a: a > 5, f))
  • 0
    Могли бы мы также просто y = list(filter(lambda a: a > 5, f) затем print(y) сейчас, когда мы хотим использовать y в будущем, нам не нужно использовать list каждый раз, когда мы вызываем y
  • 0
    @vash_the_stampede да, это то, что я предлагаю в нижней строке. Смысл двойного вызова list() заключается в том, что второй выведет пустой список
Показать ещё 4 комментария
1

Я согласен с ответом roganjosh, но давайте посмотрим, смогу ли я добавить немного дополнительного:

Что немного запутывает функции filter(), map() и reversed() это то, что они не возвращают списки (как и ожидалось), а вместо этого возвращают итераторы. (Это указано в тексте справки, который вы можете прочитать при вводе help(filter), help(map) и help(reversed).)

Итак, теперь, когда вы знаете, что они возвращают итераторы вместо списков, вам может быть интересно: почему это имеет значение? Ну, итераторы должны повторяться один раз (то есть не более одного раза), например, в for-loop, например, for я in iterator: И то, что важно иметь в виду, состоит в том, что после повторения итератора у него больше не осталось больше элементов для повторения.

Для иллюстрации рассмотрим этот код:

backwards = reversed( [1, 2, 3, 4, 5] )   # creates an iterator; not a list!
myList = list(backwards)   # iterates over the iterator to create a list
print(myList)   # prints "[5, 4, 3, 2, 1]", as you'd expect
myList = list(backwards)   # nothing left to iterate over, so creates an empty list
print(myList)   # prints "[]" (an empty list)

Итак, что вы делаете, если хотите получить список из filter(), map() и reversed() вместо итератора? Ну, вы можете немедленно обернуть эти вызовы функций в list() и использовать этот результат, когда вам это нужно, например:

myList = list( reversed( [1, 2, 3, 4, 5] ) )
# Now use myList whenever you need it, without worrying that it will disappear.

Или вы можете заменить filter() и map() на список, например:

f = list(range(10))
y = [a for a in f if a > 5]  # you can use this instead of filter()
x = [a + 1 for a in f]  # you can use this instead of map()

А что касается замены reversed()? Попробуй это:

z = f[::-1]  # you can use this instead of reversed()

Вам может быть интересно: если я могу использовать замены для filter(), map() и reversed(), зачем мне их использовать?

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню