How to Solve Python TypeError: ‘generator’ object is not callable

by | Programming, Python, Tips

If you put parentheses after a generator object, Python interprets this as a call. As only functions are callable, the Python interpreter will raise the TypeError: ‘generator’ object is not callable.

This error typically occurs when overriding a function name with a generator object, and then trying to call the function.

You can solve this error by not overriding previously defined functions. If you want to access the values in a generator object using a for loop, you do not need to put parentheses after the variable name. For example,

def inf_sequence():

    num = 0

    while True:

        yield num

        num +=1

inf_gen = inf_sequence()

for i in inf_gen:

    print(i, end=" ")

This tutorial will go through how to solve the error with code examples.


TypeError: ‘generator’ object is not callable

What is a TypeError?

TypeError occurs in Python when you perform an illegal operation for a specific data type.

Calling a function means the Python interpreter executes the code inside the function. In Python, we can only call functions. We can call functions by specifying the name of the function we want to use followed by a set of parentheses, for example, function_name(). Let’s look at an example of a working function that returns a string.

# Declare function

def simple_function():

    print("Learning Python is fun!")

# Call function

simple_function()
Learning Python is fun!

We declare a function called simple_function in the code, which prints a string. We can then call the function, and the Python interpreter executes the code inside simple_function().

Integers do not respond to a function call because they are not functions. If you try to call a int object as if it were a function, you will raise the TypeError: ‘int’ object is not callable.

We can check if an object is callable by passing it to the built-in callable() function. If the method returns True, then the object is callable. Otherwise, if it returns False the object is not callable.

Generator functions allow us to declare a function that behaves like an iterator. We use a yield statement rather than a return statement in a generator function.

A generator function is callable and returns a generator object. A generator object is not callable. Let’s evaluate a generator function and a generator object with the callable() function.

# A simple generator function
def my_gen():
    n = 1
    print('First print statement')
    # Generator function contains yield statements
    yield n

    n += 1
    print('Second print statement')
    yield n

    n += 1
    print('Third print statement')
    yield n

gen = my_gen()

print(type(my_gen))
print(callable(my_gen))
print(type(gen))
print(callable(gen))
<class 'function'>
True
<class 'generator'>
False

The callable function returns True for the my_gen function. We call the my_gen function by putting parentheses after it, which returns a generator object. The callable function returns False for the generator object.

Example

Let’s look at an example of trying to call a generator object. First, we will define a generator function that yields an infinite sequence of numbers.

def inf_sequence():

    num = 0

    while True:

        yield num

        num +=1

Next, we will define a function which takes the generator function as its argument, calls it and then iterates over the values with a for loop, printing only the even numbers. The function then breaks after reaching 100.

def print_even(inf_generator):

    inf_gen = inf_generator()

    for num in inf_gen():

        if num % 2 == 0:

            print(num)

        if num > 100:

            break

Next, we will call the print_even function:

print_even(inf_sequence)

Let’s run the code to see what happens:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [20], in <cell line: 1>()
----> 1 print_even(inf_sequence)

Input In [19], in print_even(inf_generator)
      1 def print_even(inf_generator):
      2     inf_gen = inf_generator()
----> 3     for num in inf_gen():
      4         if num % 2 == 0:
      5             print(num)

TypeError: 'generator' object is not callable

The error occurs because we tried to call the generator object when defining the for loop. We already called the generator function to get the generator object on the previous line.

Solution #1

We can solve the error by removing the parentheses from the generator object. Let’s look at the revised code:

def print_even(inf_generator):

    inf_gen = inf_generator()

    for num in inf_gen:

        if num % 2 ==0:

            print(num, end=" ")

        if num > 100:

            break

print_even(inf_sequence)

Let’s run the code to see the result:

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 

Solution #2

We can also solve the error by shifting the generator function call to the for loop. Let’s look at the revised code:

def print_even(inf_generator):

    for num in inf_generator():

        if num % 2 ==0:

            print(num, end=" ")

        if num > 100:

            break

print_even(inf_sequence)

Let’s run the code to get the result:

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100 

Example #2

Let’s look at a second example of trying to call a generator object. First, we will define a function that reverses a string and yields the characters in reverse.

def rev_str(my_str):

    length = len(my_str)

    for i in range(length - 1, -1, -1):

        yield my_str[i]

Next, we will define a string and pass it as an argument to the generator function call. Then, we will use a for loop to iterate over the values contained in the generator object.

my_str = 'Python'

rev_str = rev_str(my_str)

for ch in rev_str:

    print(ch)
n
o
h
t
y
P

Next, we will define a second string and attempt to pass it to the rev_str function call and then iterate over and print over the values in the generator object.

my_new_str = 'Numpy'
rev_new_str = rev_str(my_new_str)
for ch in rev_new_str:
    print(ch)

Let’s run the code to see what happens:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [25], in <cell line: 2>()
      1 my_new_str = 'Numpy'
----> 2 rev_new_str = rev_str(my_new_str)
      3 for ch in rev_new_str:
      4     print(ch)

TypeError: 'generator' object is not callable

The error occurs because we named the first generator object rev_str, which overrides the name of the generator function. Then, when we tried to call rev_str a second time, we are instead calling the generator object.

We can check the type of an object using the built-in type() object:

print(type(rev_str))
<class 'generator'>

Solution

We can solve the error by deleting the rev_str object using the del keyword and giving the generator object a different name. Let’s look at the revised code:

del rev_str

def rev_str(my_str):

    length = len(my_str)

    for i in range(length - 1, -1, -1):

        yield my_str[i]

my_str = 'Python'

reversed_str = rev_str(my_str)

for ch in reversed_str:

    print(ch)
n
o
h
t
y
P

We named the generator object reversed_str instead of rev_str. Therefore, we can make further function calls as we did not override it.

my_new_str = 'Numpy'

reversed_new_str = rev_str(my_new_str)

for ch in reversed_new_str:

    print(ch)
y
p
m
u
N

Summary

Congratulations on reading to the end of this tutorial!

For further reading on not callable TypeErrors, go to the articles:

To learn more about Python, specifically for data science and machine learning, go to the online courses page on Python.

Have fun and happy researching!

Research Scientist at Moogsoft | + posts

Suf is a research scientist at Moogsoft, specializing in Natural Language Processing and Complex Networks. Previously he was a Postdoctoral Research Fellow in Data Science working on adaptations of cutting-edge physics analysis techniques to data-intensive problems in industry. In another life, he was an experimental particle physicist working on the ATLAS Experiment of the Large Hadron Collider. His passion is to share his experience as an academic moving into industry while continuing to pursue research. Find out more about the creator of the Research Scientist Pod here and sign up to the mailing list here!