有没有办法在生成器的定义中获取对返回的生成器对象的引用?这类似于传递给迭代器的self
方法内的方法的__next__
参数。浏览Python的文档后,我没有找到类似的东西。
这个问题出现的时候我正在探索以下论文的大部分内容,我可以使用生成器作为协同程序在Python中实现。论文:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.79
我能做的最接近的是使用装饰器,它基于David Beazley的coroutine
装饰器,但感觉有点像黑客。
from functools import wraps
def coroutine(func):
@wraps(func)
def decorated(*args, **kwargs):
f = func(*args, **kwargs)
next(f)
f.send(f)
return f
return decorated
@coroutine
def A():
self = yield
# do stuff...
编辑:基于下面的答案,下面的类可以用作装饰器,让生成器接收对self
的引用作为其第一个参数。它具有额外的好处,任何用它装饰的生成器都将具有类型coroutine
。
class coroutine(object):
"""Decorator class for coroutines with a self parameter."""
def __new__(cls, func):
@wraps(func)
def decorated(*args, **kwargs):
o = object.__new__(cls)
o.__init__(func, args, kwargs)
return o
return decorated
def __init__(self, generator, args, kw):
self.generator = generator(self, *args, **kw)
next(self.generator)
def __iter__(self):
return self
def __next__(self):
return next(self.generator)
next = __next__
def send(self, value):
return self.generator.send(value)
# Usage:
@coroutine
def A(self):
while True:
message = yield
print self is message
a = A()
b = A()
a.send(a) # outputs True
a.send(b) # outputs False
答案 0 :(得分:3)
以下是使用代理的建议。
def selfDecorator(func):
def wrap(*args, **kw):
return SelfGenerator(func, args, kw)
return wrap
class SelfGenerator(object):
"""This class implements the generator interface"""
def __init__(self, generator, args, kw):
self.generator = generator(self, *args, **kw)
def __iter__(self):
return self
def __next__(self):
return next(self.generator)
next = __next__
def send(self, value):
return self.generator.send(value)
@selfDecorator
def gen(self, x): # your generator function with self
for i in range(x):
yield self
for x in gen(5):
print x # prints <__main__.SelfGenerator object at 0x02BB16D0>
由于SelfGenerator
是原始生成器的代理,因此它具有相同的接口,可以完全用作Pythons自己的生成器。
第一个答案
您无法自行调用生成器:
>>> def generator():
for value in g:
yield value
>>> g = generator()
>>> next(g)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
next(g)
File "<pyshell#11>", line 2, in generator
for value in g:
ValueError: generator already executing
猜测:论文中的自我可能并不意味着生成器本身而是一个对象,一些状态持有者可能在某些生成器之间共享。
更确切地说,当被视为无向图时,约束的有向图需要无周期。
这让我觉得生成器没有引用它的“相同”执行。为什么它应该通过迭代来获得自己的价值?它可以使用局部变量。
协同程序源自Simula。也许要了解自我是什么,你可以看看语言。