Reputation: 21
I'm still new to generators in python. I was trying out one on my own and tried to something really simple:
def fib(a):
... if a==0 or a==1:return 1
... yield fib(a-1)+fib(a-2)
print(list(fib(5))
This code gave me this error:
TypeError: unsupported operand type(s) for +: 'generator' and 'generator'
Can't generators be used in this manner?
Upvotes: 1
Views: 2090
Reputation: 1121824
Calling a generator function doesn't produce the next value. It produces a generator object, a specialist version of an iterator object. You have, in effect, something that wraps a paused function.
To get another value from that function, you'd have to call next(iterator)
on the object or use something like list(iteratort)
or for ... in iterator
to loop over the object and get the values out. See What does the "yield" keyword do? for more details.
So here, the you'd have to use next(fib(a-1)) + next(fib(a-2))
to get the two recursive values out. That'll also fail, because your termination case (a == 0 or a == 1
) uses return
(translated into the value of a StopIteration
exception) and not yield
; you'd have to fix that too.
And this highlights why your recursive function should not be a generator function. Your function doesn't produce a series of values to iterate over. There's just one result mfor a given argument value. You'd be far better off to just use return
and not yield
.
If you wanted to generate a sequence of fibonacci numbers, the function argument would need to be seen as a limit; "give me the first n fibonacci numbers". The following iterative function does that:
def first_n_fibonacci(n):
a, b = 0, 1
for i in range(0, n):
a, b = b, a + b
yield a
This would give you a list of the first n
fibonacci numbers, as a generator:
>>> f = first_n_fibonacci(5)
>>> f
<generator object first_n_fibonacci at 0x10b2c8678>
>>> next(f)
1
>>> next(f)
1
>>> list(f)
[2, 3, 5]
or you could use the argument to produce all fibonacci values up to a limit, or to produce an endless generator of fibonacci numbers. None of those would require recursion, a loop like the above suffices.
Upvotes: 6
Reputation: 2121
If you do want to use a generator, you need to think about outputting a sequence, and not a single value. Do you want your fib(a)
to output the a
th fib number or the the 1st, 2nd, 3rd, 4th, 5th ... a
th fib number? If the latter, then generators are good for this.
Here is an example generator for the Fibonacci numbers from the 1st to the n
th number.
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
Upvotes: 0
Reputation: 106543
Generators are meant to be used for iterations, and yet by adding two of the returning values from fib
you are trying to use it as a scalar value, which is confirmed by your terminal condition (where a
equals to 0
or 1
) also returning a scalar value.
You should simply use return
in this case.
def fib(a):
if a==0 or a==1:return 1
return fib(a-1)+fib(a-2)
print(fib(5))
Upvotes: 1