Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping generator functions in Python

I am writing some code that traverses a structure that may have cyclic references. Rather than explicitly doing checks at the beginning of the recursive functions I thought that I would create a decorator that didn't allow a function to be called more than once with the same arguments.

Below is what I came up with. As it is written, this will try to iterate over Nonetype and raise an exception. I know that I could fix it by returning say an empty list, but I wanted to be more elegant. Is there a way to tell from within the decorator whether the function being decorated is a generator function or not? This way I could conditionally raise StopIteration if it is a generator or just return None otherwise.

previous = set()
def NO_DUPLICATE_CALLS(func):
    def wrapped(*args, **kwargs):
        if args in previous:
            print 'skipping previous call to %s with args %s %s' % (func.func_name, repr(args), repr(kwargs))
            return
        else:
            ret = func(*args, **kwargs)
            previous.add(args)
            return ret
    return wrapped

@NO_DUPLICATE_CALLS
def foo(x):
    for y in x:
        yield y

for f in foo('Hello'):
    print f

for f in foo('Hello'):
    print f
like image 479
eric.frederich Avatar asked Jun 20 '11 16:06

eric.frederich


People also ask

What are generator functions in Python?

Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python. Simply speaking, a generator is a function that returns an object (iterator) which we can iterate over (one value at a time).

How do you create a generator in Python?

It is quite simple to create a generator in Python. It is similar to the normal function defined by the def keyword and uses a yield keyword instead of return. Or we can say that if the body of any function contains a yield statement, it automatically becomes a generator function.

Are Python generators thread safe?

It's not thread-safe; simultaneous calls may interleave, and mess with the local variables.

What is the advantage of generator function in Python?

Generators allow you to create iterators in a very pythonic manner. Iterators allow lazy evaluation, only generating the next element of an iterable object when requested. This is useful for very large data sets. Iterators and generators can only be iterated over once.


1 Answers

Okay, check this out:

>>> from inspect import isgeneratorfunction
>>> def foo(x):
...    for y in x:
...        yield y
...
>>> isgeneratorfunction(foo)
True

This requires Python 2.6 or higher, though.

like image 165
JAB Avatar answered Sep 30 '22 06:09

JAB