1

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?

Trooper Z
  • 1,617
  • 14
  • 31
Shriram
  • 21
  • 4

3 Answers3

6

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.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

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))
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

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 ath fib number or the the 1st, 2nd, 3rd, 4th, 5th ... ath 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 nth number.

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b
Bruno Lubascher
  • 2,071
  • 14
  • 19