Странное поведение yield внутри блока if then - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть функция, которая возвращает генератор или список в зависимости от флага.

Тем не менее, даже когда я устанавливаю флаг на list, функция все еще возвращает генератор;также не печатает флаг.

Я ожидаю, что оператор print до команды yield будет оценен первым.Также в этом отношении, если флаг установлен в list, я не ожидаю, что блок generator оценит вообще.

import os

def get_iterator_all_files_name(dir_path, flag):
    if flag == 'generator':
        print(flag)
        for (dirpath, dirnames, filenames) in os.walk(dir_path):
            for f in filenames:
                yield os.path.join(dirpath, f)
    elif flag == 'list':
        print(flag)
        paths = list()
        for (dirpath, dirnames, filenames) in os.walk(dir_path):
            for f in filenames:
                paths.append(os.path.join(dirpath, f))
        return paths

Использование функции ...

file_path = 'path/to/files'
flag = 'list'
foo = get_iterator_all_files_name(file_path, flag)
type(foo)

, которая дает результат ...

generator

Что не то, чтоЯ жду;Я ожидал список.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Любая функция, имеющая оператор yield, становится функцией-генератором, и, следовательно, ее оператор return имеет другое значение (по сравнению с оператором return нормальной функции).Если вам действительно нужна функция get_iterator_all_files_name, чтобы иногда возвращать генератор и список в другое время, один из способов сделать это:

  1. Определить еще одну функцию (скажем, my_gen_func) для выполнениячто вы делаете сейчас внутри вашего if предложения.Следовательно, эта новая функция будет функцией генератора (поскольку она будет иметь оператор yield).
  2. Внутри функции get_iterator_all_files_name измените предложение if, чтобы просто вызвать my_gen_funcи вернуть его возвращаемое значение.(Теперь ваша функция get_iterator_all_files_name больше не является функцией генератора, а является просто нормальной функцией, поскольку она не имеет оператора yield)
  3. Ваше предложение elif может остаться прежним.
0 голосов
/ 05 февраля 2019

Если функция содержит слово yield, это генератор.Без исключений.Код не будет оцениваться до тех пор, пока не будет предпринята попытка итерации.

Просто вызовите list вместо результата:

def get_iterator_all_files_name(dir_path):
    for (dirpath, dirnames, filenames) in os.walk(dir_path):
        for f in filenames:
            yield os.path.join(dirpath, f)

file_path = 'path/to/files'
foo = list(get_iterator_all_files_name(file_path))

Вы можете изменить свою функцию, чтобы она возвращала генератор, если вы действительно хотелисохранить функциональность flag.Вы также можете сделать paths списком, который может упростить функцию:

def get_iterator_all_files_name(dir_path, flag):
    if flag == 'generator':
        return (os.path.join(dirpath, f) for (dirpath, dirnames, filenames) in os.walk(dir_path) for f in filenames)
    elif flag == 'list':
        return [os.path.join(dirpath, f) for (dirpath, dirnames, filenames) in os.walk(dir_path) for f in filenames]
...