if if块中yield的奇怪行为

时间:2019-02-05 05:04:08

标签: python if-statement generator control-flow yield-keyword

我有一个函数可以根据标志返回生成器或列表。

即使将标志设置为list,该函数仍会返回生成器;也不打印标志。

我希望在yield命令之前的print语句首先被评估。同样,如果该标志设置为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 :(得分:1)

如果函数中包含单词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]

答案 1 :(得分:1)

任何具有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子句可以保持不变。