Wrapping generator functions in Python
I am writing some code that trave开发者_StackOverflow中文版rses 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
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.
Unfortunately there is not really a good way to know whether a function might return some type of iterable without calling it, see this answer to another question for a pretty good explanation of some potential issues.
However, you can get around this by using a modified memoize decorator. Normally memoizing decorators would create a cache with the return values for previous parameters, but instead of storing the full value you could just store the type of the return value. When you come across parameters you have already seen just return a new initialization of that type, which would result in an empty string, list, etc.
Here is a link to memoize decorator to get you started:
http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
精彩评论