if then 块中 yield 的奇怪行为
Odd behavior of yield inside a if then block
我有一个函数 returns 生成器或列表取决于标志。
然而,即使我将标志设置为 list
,函数仍然是 returns 生成器;也不打印标志。
我希望首先评估 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
这不是我所期望的;我期待列表。
如果函数中包含单词 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
功能,可以将函数修改为 return 生成器。也可以把paths
做成list comprehension,这样可以简化函数:
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]
任何具有 yield
语句的函数都会成为生成器函数,因此,它的 return
语句具有不同的含义(与普通函数的 return
语句相比).
如果您有时确实需要 get_iterator_all_files_name
函数来 return 一个生成器,而在其他时候需要一个列表,一种方法是这样的:
- 在
if
子句中再定义一个函数(例如 my_gen_func
)来完成您现在正在做的事情。因此,这个新函数将是一个生成器
函数(因为它会有一个 yield
语句)。
- 在
get_iterator_all_files_name
函数中,修改 if
子句,只调用 my_gen_func
,return 它的
return-值。 (现在,您的 get_iterator_all_files_name
函数不再是生成器函数,而只是一个普通函数,因为它没有 yield
语句)
- 您的
elif
子句可以保持不变。
我有一个函数 returns 生成器或列表取决于标志。
然而,即使我将标志设置为 list
,函数仍然是 returns 生成器;也不打印标志。
我希望首先评估 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
这不是我所期望的;我期待列表。
如果函数中包含单词 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
功能,可以将函数修改为 return 生成器。也可以把paths
做成list comprehension,这样可以简化函数:
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]
任何具有 yield
语句的函数都会成为生成器函数,因此,它的 return
语句具有不同的含义(与普通函数的 return
语句相比).
如果您有时确实需要 get_iterator_all_files_name
函数来 return 一个生成器,而在其他时候需要一个列表,一种方法是这样的:
- 在
if
子句中再定义一个函数(例如my_gen_func
)来完成您现在正在做的事情。因此,这个新函数将是一个生成器 函数(因为它会有一个yield
语句)。 - 在
get_iterator_all_files_name
函数中,修改if
子句,只调用my_gen_func
,return 它的 return-值。 (现在,您的get_iterator_all_files_name
函数不再是生成器函数,而只是一个普通函数,因为它没有yield
语句) - 您的
elif
子句可以保持不变。