问题
I would like you to consider the following code:
def func(alist):
if len(alist) == 1:
return arg * 2
for item in alist:
yield item * 2
When I run it, I get this error:
SyntaxError: 'return' with argument inside generator
Now, I realize that I cannot do this. However, I would like to know why. What exactly is going on behind the scenes that is causing Python to throw the SyntaxError
?
回答1:
Python has to decide whether a function is a generator at bytecode compilation time. This is because the semantics of generators say that none of the code in a generator function runs before the first next
call; the generator function returns a generator iterator that, when next
is called, runs the generator code. Thus, Python can't decide whether a function should be a generator or not by running it until it hits a yield
or a return
; instead, the presence of a yield
in a function signals that the function is a generator.
回答2:
See here: What does the "yield" keyword do in Python?
This describes your issue in detail. In short, because the way Python will interprate the function (either as an generating object or a returning object, everything in Python is objects and some things will define that object as a specific type. In this case Yield is a generating object)
TL;DR: You can't use yield
and return
within the same function. Use either one as many times as you wan't within the function, just not both.
回答3:
Is not that, you cannot use a return with yield, but rather, you cannot use return with argument, when your function has a yield making it a generator
You might want to change your implementation to
def func(lis):
for item in lis:
yield item * 2
回答4:
What you want is indeed possible:
def func(lis):
if len(lis) == 1:
return lis[0] * 2
else:
return (item * 2 for item in lis)
This returns a value in the one case and a generator in the other case.
But be aware that this will lead to problems: On every call, you will have to make the distinction
res = func(lis)
if len(lis) == 1:
print res # my value
else:
for i in res: print i # several values
It is much more advisable to make the two use cases distinct:
You can do
def func(val): return val * 2
and, when you need, do either of
reslist = [func(i) for i in lis] resgen = (func(i) for i in lis)
or
you can do
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
回答5:
The other answers already explained the yield/return issue. You can just use map
to make this much simpler:
def func(lis):
return map(lambda item: item * 2, lis)
# similar to: return [item * 2 for item in lis]
Of course, this will always return a list, because lis
is a list, even if it only has one item. You can change it to a compound statement:
def func(lis):
return map(lambda item: item * 2, lis) if len(lis) > 1 else lis[0] * 2
来源:https://stackoverflow.com/questions/18215828/why-cant-i-use-yield-with-return