【问题标题】:Odd behavior of yield inside a if then blockif then 块中 yield 的奇怪行为
【发布时间】:2019-02-05 05:04:08
【问题描述】:

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

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

我希望先评估 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

这不是我所期望的;我期待的名单。

【问题讨论】:

  • 如果一个问题有一个被接受的答案,那么它就被“解决”了。没有理由在问题中加上“已解决”这个词。

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


【解决方案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]

【讨论】:

  • 但是如果我们发送 flag='generator' 这也会返回列表
  • @ravishankarchavare 重点是,如果您需要生成器,请不要致电list。如果您需要一份清单,请致电list
  • OK 现在了解场景
【解决方案2】:

任何具有yield 语句的函数都将成为生成器函数,因此其return 语句具有不同的含义(与普通函数的return 语句相比)。 如果您确实需要 get_iterator_all_files_name 函数有时返回生成器而有时返回列表,那么一种方法是:

  1. if 子句中再定义一个函数(比如my_gen_func)来执行您现在正在执行的操作。因此,这个新功能将是一个生成器 函数(因为它会有 yield 语句)。
  2. get_iterator_all_files_name 函数中,修改if 子句,只调用my_gen_func,并返回它的 返回值。 (现在,您的 get_iterator_all_files_name 函数不再是生成器函数,而只是一个普通函数,因为它没有 yield 语句)
  3. 您的elif 子句可以保持不变。

【讨论】:

    猜你喜欢
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多