Pushpak Dagade
Pushpak Dagade

Reputation: 6450

How to check if an object is a generator object in Python?

In Python, how do I check if an object is a generator object?

Trying

>>> type(myobject, generator)

gives the error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'generator' is not defined

(I know I can check if the object has a __next__ method for it to be a generator, but I want some way using which I can determine the type of any object, not just generators.)

Upvotes: 224

Views: 83158

Answers (10)

kantal
kantal

Reputation: 2407

There is no need to import a module, you can declare an object for comparison at the beginning of the program:

gentyp = type(1 for i in "")
# ...
type(myobject) == gentyp

Upvotes: 7

Luca Sbardella
Luca Sbardella

Reputation: 1124

The inspect.isgenerator function is fine if you want to check for pure generators (i.e. objects of class "generator"). However it will return False if you check, for example, a zip iterable. An alternative way for checking for a generalised generator is to use this function:

def isgenerator(iterable):
    return hasattr(iterable, '__iter__') and not hasattr(iterable, '__len__')

Upvotes: 18

utdemir
utdemir

Reputation: 27216

You can use GeneratorType from types:

>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True

Upvotes: 313

Tatarinho
Tatarinho

Reputation: 784

It's a little old question, however I was looking for similar solution for myself, but for async generator class, so you may find this helpful.

Based on utdemir reply:

import types
isinstance(async_generator(), types.AsyncGeneratorType)

Upvotes: 0

user9074332
user9074332

Reputation: 2636

You could use the Iterator or more specifically, the Generator from the typing module.

from typing import Generator, Iterator
g = (i for i in range(1_000_000))
print(type(g))
print(isinstance(g, Generator))
print(isinstance(g, Iterator))

result:

<class 'generator'>
True
True

Upvotes: 9

user6830669
user6830669

Reputation: 177

If you are using tornado webserver or similar you might have found that server methods are actually generators and not methods. This makes it difficult to call other methods because yield is not working inside the method and therefore you need to start managing pools of chained generator objects. A simple method to manage pools of chained generators is to create a help function such as

def chainPool(*arg):
    for f in arg:
      if(hasattr(f,"__iter__")):
          for e in f:
             yield e
      else:
         yield f

Now writing chained generators such as

[x for x in chainPool(chainPool(1,2),3,4,chainPool(5,chainPool(6)))]

Produces output

[1, 2, 3, 4, 5, 6]

Which is probably what you want if your looking to use generators as a thread alternative or similar.

Upvotes: 2

Robert Lujo
Robert Lujo

Reputation: 16361

I think it is important to make distinction between generator functions and generators (generator function's result):

>>> def generator_function():
...     yield 1
...     yield 2
...
>>> import inspect
>>> inspect.isgeneratorfunction(generator_function)
True

calling generator_function won't yield normal result, it even won't execute any code in the function itself, the result will be special object called generator:

>>> generator = generator_function()
>>> generator
<generator object generator_function at 0x10b3f2b90>

so it is not generator function, but generator:

>>> inspect.isgeneratorfunction(generator)
False

>>> import types
>>> isinstance(generator, types.GeneratorType)
True

and generator function is not generator:

>>> isinstance(generator_function, types.GeneratorType)
False

just for a reference, actual call of function body will happen by consuming generator, e.g.:

>>> list(generator)
[1, 2]

See also In python is there a way to check if a function is a "generator function" before calling it?

Upvotes: 45

S.Lott
S.Lott

Reputation: 391854

I know I can check if the object has a next method for it to be a generator, but I want some way using which I can determine the type of any object, not just generators.

Don't do this. It's simply a very, very bad idea.

Instead, do this:

try:
    # Attempt to see if you have an iterable object.
    for i in some_thing_which_may_be_a_generator:
        # The real work on `i`
except TypeError:
     # some_thing_which_may_be_a_generator isn't actually a generator
     # do something else

In the unlikely event that the body of the for loop also has TypeErrors, there are several choices: (1) define a function to limit the scope of the errors, or (2) use a nested try block.

Or (3) something like this to distinguish all of these TypeErrors which are floating around.

try:
    # Attempt to see if you have an iterable object.
    # In the case of a generator or iterator iter simply 
    # returns the value it was passed.
    iterator = iter(some_thing_which_may_be_a_generator)
except TypeError:
     # some_thing_which_may_be_a_generator isn't actually a generator
     # do something else
else:
    for i in iterator:
         # the real work on `i`

Or (4) fix the other parts of your application to provide generators appropriately. That's often simpler than all of this.

Upvotes: 1

Corey Goldberg
Corey Goldberg

Reputation: 60604

>>> import inspect
>>> 
>>> def foo():
...   yield 'foo'
... 
>>> print inspect.isgeneratorfunction(foo)
True

Upvotes: 4

mouad
mouad

Reputation: 70031

You mean generator functions ? use inspect.isgeneratorfunction.

EDIT :

if you want a generator object you can use inspect.isgenerator as pointed out by JAB in his comment.

Upvotes: 52

Related Questions