Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python包装生成器函数_Python_Generator_Decorator - Fatal编程技术网

用Python包装生成器函数

用Python包装生成器函数,python,generator,decorator,Python,Generator,Decorator,我正在编写一些代码来遍历可能具有循环引用的结构。 我不想在递归函数的开头显式地进行检查,而是想创建一个装饰器,它不允许使用相同的参数多次调用函数 下面是我想到的。在编写时,这将尝试在非类型上迭代并引发异常。我知道我可以通过返回一个空列表来修复它,但我想变得更优雅。有没有一种方法可以从装饰器内部判断被装饰的函数是否是生成器函数?这样,如果StopIteration是生成器,我可以有条件地提出它,否则只返回None previous = set() def NO_DUPLICATE_CALLS(fu

我正在编写一些代码来遍历可能具有循环引用的结构。 我不想在递归函数的开头显式地进行检查,而是想创建一个装饰器,它不允许使用相同的参数多次调用函数

下面是我想到的。在编写时,这将尝试在非类型上迭代并引发异常。我知道我可以通过返回一个空列表来修复它,但我想变得更优雅。有没有一种方法可以从装饰器内部判断被装饰的函数是否是生成器函数?这样,如果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
好的,看看这个:

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

不过,这需要Python 2.6或更高版本。

不幸的是,要知道函数是否可以返回某种类型的iterable而不调用它,还没有一个好方法,请参阅另一个问题,以获得对某些潜在问题的非常好的解释

但是,您可以通过使用修改后的memoize装饰器来解决这个问题。通常,记忆装饰器会创建一个缓存,其中包含以前参数的返回值,但您可以只存储返回值的类型,而不是存储完整值。当您遇到已经看到的参数时,只需返回该类型的新初始化,这将导致空字符串、列表等

这里有一个链接,可以帮助您开始使用memoize decorator:

>isinstance(s,generator)回溯(最近一次调用):文件“”,第1行,在名称中错误:名称“generator”不正确defined@JAB:生成器是Python3.2吗?“isinstance(func,generator)”只是在Python 2中给出了一个NameError。7@cldy,Gerrat:抱歉,刚才注意到,即使类名是“generator”,您也必须从
类型
模块导入
GeneratorType
,并使用它来工作(更新了我的答案以反映这一点)。不过,这很愚蠢,因为像
isinstance(1,int)
这样的东西工作得很好。(好吧,在Python 2.2+中)我想这是由于
int
等也是内置函数,但
generator
不是。函数不应该引发StopIteration,它应该返回一个迭代器,在第一次
下一次
调用时引发StopIteration,空列表可以正常工作。而且,这根本不起作用。生成器函数是在调用时返回生成器的函数,该函数本身不是
Generator
类的实例。您必须使用
isinstance(func(),GeneratorType)
,这与目的背道而驰。删除了我的答案,因为它最终毫无用处。看起来搜索
dis.dis(foo)
的结果以获得
YIELD\u VALUE
,如您链接的问题中所述,可能是最佳选择。另一方面,eric在技术上已经在他的
前一套
中使用了一种备忘录形式。仔细想想,
检查
模块实际上相当整洁。