简体   繁体   English

在Python中包装生成器函数

[英]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. 在编写时,这将尝试迭代Nonetype并引发异常。 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. 这样我可以有条件地提高StopIteration,如果它是一个生成器,或者只返回None否则。

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. 但这需要Python 2.6或更高版本。

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. 不幸的是,没有一个很好的方法可以知道函数是否可以在不调用它的情况下返回某种类型的iterable,请参阅另一个问题的答案以获得对某些潜在问题的非常好的解释。

However, you can get around this by using a modified memoize decorator. 但是,您可以使用修改后的memoize装饰器来解决这个问题。 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. 通常,memoizing装饰器会创建一个带有先前参数返回值的缓存,但是不是存储完整值,而是可以存储返回值的类型。 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: 这是一个memoize装饰器的链接,可以帮助您入门:
http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize http://wiki.python.org/moin/PythonDecoratorLibrary#Memoize

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM