Search code examples
pythongeneratoryield

yield + generator in python in class


I am very new in Python and I wanna create a generator object that yields two lists for Fibonacci sequence. First list of number and second list of fibonacci. The function define in the class. Before it I define fibonacci function as below:

def fib(self, _n,) -> int:
        if _n == 0:
            return 0
        if _n == 1:
            return 1
        return self.fib(_n-1) + self.fib(_n-2)

I need to define def fib_seq(self, _n): function with yield and use gen() together.

I did it:

def fib_seq(self, _n):
        """
        - input: n=4
        - output: generator object that produces:
            ([0, 1, 2, 3, 4],
             [0, 1, 1, 2, 3])
        """
        for i in range(_n):
            nlist = gen(i)
            flist = gen(self.fib(i))

        yield ([nlist], [flist])

but I got below error in test part:

Traceback (most recent call last):
  File --- line 161, in <module> # this part is in test section
    n, fib = next(gen)      # trigger generator
             ^^^^^^^^^
  File ---, line 53, in fib_seq # this part is my code
    nlist = gen(i)
            ^^^^^^
TypeError: 'generator' object is not callable

Solution

  • I'm not sure what the gen function you are using is, but you don't need to use it. You could do (removing self in this example to have standalone functions):

    def fib(_n):
        if _n == 0:
            return 0
        if _n == 1:
            return 1
        return fib(_n-1) + fib(_n-2)
    
    def fib_seq(n):
        for i in range(n + 1):
            nlist = list(range(i + 1))
            flist = [fib(j) for j in range(i + 1)]
        yield (nlist, flist)
    
    # as fib_seq yields a generator you have to use it in, e.g., a for loop
    for k in fib_seq(4):
        print(k)
    
    ([0, 1, 2, 3, 4], [0, 1, 1, 2, 3])
    

    Note that the for loop in fib_seq is a bit superfluous as it stands. You could move the yield to within the loop, e.g.,

    def fib_seq(n):
        for i in range(n + 1):
            nlist = list(range(i + 1))
            flist = [fib(j) for j in range(i + 1)]
            yield (nlist, flist)
    

    which would give:

    for k in fib_seq(4):
        print(k)
    
    ([0], [0])
    ([0, 1], [0, 1])
    ([0, 1, 2], [0, 1, 1])
    ([0, 1, 2, 3], [0, 1, 1, 2])
    ([0, 1, 2, 3, 4], [0, 1, 1, 2, 3])
    

    or, if you only want one output, have:

    def fib_seq(n):
        nlist = list(range(n + 1))
        flist = [fib(j) for j in range(n + 1)]
        yield (nlist, flist)
    

    which would give:

    for k in fib_seq(4):
        print(k)
    
    ([0, 1, 2, 3, 4], [0, 1, 1, 2, 3])