Python 函数 `yield` 用于列表,return 用于单个元素
Python function `yield` for lists, return for individual elements
是否可以有一个函数在传递列表时生成生成器,但在给定单个值时会 return?
以此为例:
def duty2015(x):
if type(x) in [list, np.ndarray]:
for xi in x:
yield new_duty(xi)
else:
sd = 0
if x <= 120000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
显然这不起作用,我收到 SyntaxError: 'return' with argument inside generator
错误。
我意识到我可以做这样的事情:
def duty2015(x):
if type(x) in [list, np.ndarray]:
for xi in x:
for result in duty2015(xi):
yield result
else:
sd = 0
if x <= 125000:
yield sd
elif x <= 250000:
yield (x-125000) * 0.02
elif x <= 925000:
yield 2500 + (x-250000)*0.05
elif x <= 1500000:
yield 36250 + (x-925000)*0.1
else:
yield 93750 + (x-1500000)*0.12
但是当我在单个项目上调用它时,它会给我一个生成器,我宁愿只在较大的项目上调用它时才得到它。
显然我可以把它作为一个列表来做,但这同样不是最优的。
对于下面答案中的评论,这样的事情会更好吗:
def duty_new(x, generator=False):
if type(x) in [list, np.ndarray]:
if generator:
return (duty_new(xi) for xi in x)
else:
return [duty_new(xi) for xi in x]
else:
sd = 0
if x <= 125000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
因此在正常使用下,它会具有可预测的行为或 returning 传递给它的相同类型的参数(至少对于合理的参数,并且可能不会只是遍历 numpy 数组),但如果需要生成器,可以明确要求生成器吗?
Return 生成器表达式,像这样
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return (result for xi in x for result in duty2015(xi))
else:
...
...
现在,每当您使用单个元素调用 duty2015
时,您将获得单独的值,否则您将获得生成器表达式,必须使用 next
协议进行迭代。
就我个人而言,我觉得你的第二个版本很好并且是一致的,因为它使 duty2015
成为一个生成器函数,而且正如 Martijn Pieters 在评论中提到的那样,它没有调用者猜测它得到了什么回来,最好坚持下去。
注意:你的代码第一版和第二版不一样。我选择第二个版本中的代码来展示思路。
这样怎么样,return 发电机? :
def new_fun(x):
return x + 1
def duty2015(x):
if type(x) is list:
return (new_fun(i) for i in x)
else:
sd = 0
if x <= 120000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
print duty2015([1,2,3])
print (1)
输出:
<generator object <genexpr> at 0x10be06b40>
1
这样你就可以使用return得到一个生成器对象。
您可以 return 另一个作为生成器的函数的结果,如下所示:
def dolist(li):
for el in li:
yield el * 2
def either(x):
if isinstance(x, list):
return dolist(x)
else:
return x * 2
print either(4) # prints 8
print list(either([2,3])) # prints [4,6]
您可以 return 函数内的生成器。通过
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return (new_duty(xi) for xi in x)
else:
...
或使用辅助生成器函数:
def duty_gen(x):
for xi in x:
yield new_duty(xi)
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return duty_gen(x)
是否可以有一个函数在传递列表时生成生成器,但在给定单个值时会 return?
以此为例:
def duty2015(x):
if type(x) in [list, np.ndarray]:
for xi in x:
yield new_duty(xi)
else:
sd = 0
if x <= 120000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
显然这不起作用,我收到 SyntaxError: 'return' with argument inside generator
错误。
我意识到我可以做这样的事情:
def duty2015(x):
if type(x) in [list, np.ndarray]:
for xi in x:
for result in duty2015(xi):
yield result
else:
sd = 0
if x <= 125000:
yield sd
elif x <= 250000:
yield (x-125000) * 0.02
elif x <= 925000:
yield 2500 + (x-250000)*0.05
elif x <= 1500000:
yield 36250 + (x-925000)*0.1
else:
yield 93750 + (x-1500000)*0.12
但是当我在单个项目上调用它时,它会给我一个生成器,我宁愿只在较大的项目上调用它时才得到它。
显然我可以把它作为一个列表来做,但这同样不是最优的。
对于下面答案中的评论,这样的事情会更好吗:
def duty_new(x, generator=False):
if type(x) in [list, np.ndarray]:
if generator:
return (duty_new(xi) for xi in x)
else:
return [duty_new(xi) for xi in x]
else:
sd = 0
if x <= 125000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
因此在正常使用下,它会具有可预测的行为或 returning 传递给它的相同类型的参数(至少对于合理的参数,并且可能不会只是遍历 numpy 数组),但如果需要生成器,可以明确要求生成器吗?
Return 生成器表达式,像这样
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return (result for xi in x for result in duty2015(xi))
else:
...
...
现在,每当您使用单个元素调用 duty2015
时,您将获得单独的值,否则您将获得生成器表达式,必须使用 next
协议进行迭代。
就我个人而言,我觉得你的第二个版本很好并且是一致的,因为它使 duty2015
成为一个生成器函数,而且正如 Martijn Pieters 在评论中提到的那样,它没有调用者猜测它得到了什么回来,最好坚持下去。
注意:你的代码第一版和第二版不一样。我选择第二个版本中的代码来展示思路。
这样怎么样,return 发电机? :
def new_fun(x):
return x + 1
def duty2015(x):
if type(x) is list:
return (new_fun(i) for i in x)
else:
sd = 0
if x <= 120000:
return sd
elif x <= 250000:
return (x-125000) * 0.02
elif x <= 925000:
return 2500 + (x-250000)*0.05
elif x <= 1500000:
return 36250 + (x-925000)*0.1
else:
return 93750 + (x-1500000)*0.12
print duty2015([1,2,3])
print (1)
输出:
<generator object <genexpr> at 0x10be06b40>
1
这样你就可以使用return得到一个生成器对象。
您可以 return 另一个作为生成器的函数的结果,如下所示:
def dolist(li):
for el in li:
yield el * 2
def either(x):
if isinstance(x, list):
return dolist(x)
else:
return x * 2
print either(4) # prints 8
print list(either([2,3])) # prints [4,6]
您可以 return 函数内的生成器。通过
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return (new_duty(xi) for xi in x)
else:
...
或使用辅助生成器函数:
def duty_gen(x):
for xi in x:
yield new_duty(xi)
def duty2015(x):
if isinstance(x, list) or isinstance(x, np.ndarray):
return duty_gen(x)