【问题标题】:Is there anything similar to "self" inside a Python generator?Python 生成器中有什么类似于“self”的东西吗?
【发布时间】:2014-02-16 06:32:44
【问题描述】:

有没有办法在生成器的定义中获取对返回的生成器对象的引用?这类似于传递给迭代器的__next__ 方法内部的方法的self 参数。在浏览了 Python 的文档后,我没有发现任何类似的东西。

当我在探索以下论文中的多少想法时,我提出了这个问题,我可以使用生成器作为协程在 Python 中实现多少。论文:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.79

我能做的最接近的方法是使用装饰器,它基于 David Beazley 的 coroutine 装饰器,但感觉有点像 hack。

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

【问题讨论】:

  • 我已经简要浏览了大约三分之一的论文,我没有看到任何你希望协程引用自身的内容。不过,看起来您希望协程能够在任何给定索引处触发协程。这是准确的,还是我应该回去实际阅读论文而不是略读?
  • 如果你确实想让协程引用自身,你会用它做什么?协程会将自己作为回调传递给代码的其他部分吗?
  • 你能放一些用例吗,其实我不清楚你在做什么。
  • 有趣的问题 (+1)。鉴于要求是多么深奥,您的解决方案并没有让我觉得有一半是坏的。也就是说,看看有人能不能想出一些更整洁的东西确实很有趣……
  • 了解您的确切用例也会很有趣。

标签: python coroutine


【解决方案1】:

这是使用代理的建议。

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 是原始生成器的代理,因此它具有相同的接口,可以完全用作 Python 自己的生成器。

第一个答案

你不能自己调用​​生成器:

>>> 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

猜测:论文中的 self 可能不是生成器本身,而是一个对象,一个可能在一些生成器之间共享的状态持有者。

更准确地说,约束的有向图被认为是无向图时,要求它是无环的。

这让我觉得生成器没有引用它的“相同”执行。为什么它要通过迭代来获得自己的价值?它可以使用局部变量。

协程源自 Simula。也许要了解自我是什么,您可以看一下语言。

【讨论】:

  • 您是否引用过“协程源自 Simula”?快速浏览 Wikipedia 上的相关页面显然是模棱两可的; Simula 可能只是一个早期采用者。 (一个非常的早期采用者。)
  • 不,我没有引文。当我读到一些关于面向对象的历史的东西时,它成为了我的知识。据我所知,它是第一个采用者。 (= origin) 也许是第一个成功的采用者。我写这篇文章是因为我不确定 Sahand 对“自我”的含义。引用自身的运行生成器对我来说毫无意义。
  • 我只是问,因为我很好奇,因为快速扫描 WP 并不清楚。 (我不在工作,所以我不能轻易地直接阅读很久以前的文献。)我发现 coros 是一个早已失宠的功能,但近年来却在某种程度上得到了复兴,这很有趣。 .
  • 您的装饰器解决方案非常好。编辑:没关系,它确实适用于send!好的。至于生成器无法调用自己,绝对是的。这不是这里的意图。在本文的后面,有些算法中,“troll”需要引用前一个和下一个“troll”(这里的 troll 基本上是一个协程)。为了避免必须提前构建协程,我试图获取对“self”的引用,该引用可以传递给新创建的协程作为它们的“先前”引用。
  • 如果你有结果,你能更新这篇文章吗?我想看看您如何跟踪协同程序并推理图表。使用此代理时,应该可以在传递给其他协程时跟踪协程。
猜你喜欢
  • 2011-01-31
  • 2011-05-08
  • 2018-02-09
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-22
相关资源
最近更新 更多