我希望您考虑以下代码:
def func(alist):
if len(alist) == 1:
return arg * 2
for item in alist:
yield item * 2
运行时,出现此错误:
SyntaxError: 'return' with argument inside generator
现在,我意识到我无法做到这一点。但是,我想知道为什么。导致Python抛出SyntaxError
的幕后到底发生了什么?
Python必须在字节码编译时决定一个函数是否是生成器。这是因为生成器的语义表明,生成器函数中的任何代码都不会在第一个next
调用之前运行;生成器函数返回一个生成器迭代器,当调用next
时,它将运行生成器代码。因此,Python在运行到yield
或return
之前,无法通过运行函数来确定该函数是否应为生成器;相反,函数中存在yield
表示该函数是生成器。
参见此处:What does the "yield" keyword do in Python?
这将详细描述您的问题。简而言之,因为Python插入函数的方式(作为生成对象或返回对象,所以Python中的所有内容都是对象,有些东西会将该对象定义为特定类型。在这种情况下,Yield是生成对象)
TL; DR:您不能在同一功能中使用yield
和return
。在函数中使用任意多次,请不要多次使用。
不是,当函数具有让其成为生成器的收益时,您不能使用带有yield的收益,而不能与参数一起使用return
您可能希望将实现更改为
def func(lis):
for item in lis:
yield item * 2
您真正想要的是可能的:
def func(lis):
if len(lis) == 1:
return lis[0] * 2
else:
return (item * 2 for item in lis)
在一种情况下返回一个值,在另一种情况下返回一个生成器。
但是请注意,这将导致问题:在每次通话中,您都必须做出区分
res = func(lis)
if len(lis) == 1:
print res # my value
else:
for i in res: print i # several values
建议将两个用例区分开来:
您可以做
def func(val):
return val * 2
,并且在需要时执行以下任一操作
reslist = [func(i) for i in lis]
resgen = (func(i) for i in lis)
或
您可以做
def func(lis):
for item in lis:
yield lis[0] * 2
def func1(val):
for i in func([val]):
return i # returns the first value
其他答案已经解释了产量/收益率问题。您可以只使用map
使其更简单:
def func(lis):
return map(lambda item: item * 2, lis)
# similar to: return [item * 2 for item in lis]
当然,这将始终返回一个列表,因为lis
是一个列表,即使它只有一个项目也是如此。您可以将其更改为复合语句:
def func(lis):
return map(lambda item: item * 2, lis) if len(lis) > 1 else lis[0] * 2