itertools.chain возвращает неожиданный итератор - PullRequest
0 голосов
/ 16 мая 2019

Насколько я понимаю, Python itertools.chain предназначен для объединения нескольких итераторов.

Когда первый генератор содержит ['a/a.jpg', 'a/b.jpg'], а второй генератор является пустым генератором, ожидаемый выходной сигнал равен ['a/a.jpg', 'a/b.jpg'].

Но приведенный ниже код дает мне запутанный результат ['a/b/a.jpg', 'a/b/b.jpg']:

import itertools
import os

jpeg_paths = iter([])
# jpeg_paths = []

walk = [("a", ["a.jpg", "b.jpg"]), ("a/b", ["a.txt"])]

for dirpath, filenames in walk:
    # select image files
    jpg_filenames = filter(lambda name: str.endswith(name, "jpg"), filenames)
    # generate absolute path
    image_fullpath = map(lambda name: os.path.join(dirpath, name), jpg_filenames)

    jpeg_paths = itertools.chain(jpeg_paths, image_fullpath)
    # jpeg_paths += image_fullpath

a = list(jpeg_paths)
print(a)

1 Ответ

2 голосов
/ 16 мая 2019

Причина в том, что iterable выполняется с last dirpath, то есть a/b.Не всегда itertools всегда возвращает iterator, он не будет выполнен, пока не будет повторен.

Таким образом, чтобы связать dirpath с каждым iteration в цикле for, мыможно использовать простой function как mapfunc.Таким образом, результирующий код будет выглядеть так:

import itertools
import os

jpeg_paths = []

walk = [("a", ["a.jpg", "b.jpg"]), ("a/b", ["a.txt"])]

def mapfunc(filenames, dirpath=None): # `dirpath` will be associated with each function object
    return map(lambda name: os.path.join(dirpath, name), filenames)


for dirpath, filenames in walk:
    # select image files
    jpg_filenames = filter(lambda name: name.endswith("jpg"), filenames)
    # generate absolute path
    #break
    image_fullpath = mapfunc(jpg_filenames, dirpath=dirpath) # associate the `dirpath` to each `function` object
    jpeg_paths = itertools.chain(jpeg_paths, image_fullpath)

print(list(jpeg_paths))

, или, возможно, исчерпывает iterator на каждой итерации, например,

image_fullpath = tuple(map(lambda name: os.path.join(dirpath, name), jpg_filenames))

Таким образом, он будет ассоциировать dirpath в этот момент.на jpg_filenames звонок.Но это сохранит все objects в memory, и если вещь, которую вы хотите пройти, достаточно велика, это не очень хорошая идея:)

...