当下一个方法应该返回两个生成器的值时,如何为类创建下一个方法?

Posted

技术标签:

【中文标题】当下一个方法应该返回两个生成器的值时,如何为类创建下一个方法?【英文标题】:How to create a next method for a class when the next method is supposed to return the values of two generators? 【发布时间】:2018-02-07 13:12:48 【问题描述】:

我有以下示例,其中一个类的下一个方法应该从两个生成器返回值:

class Test():
    def __next__(self):
        g1, g2 = self._gen1(), self._gen2() 
        return next(g1), next(g2)

    def _gen1(self):
        i = 0
        while True:
            yield i
            i += 2

    def _gen2(self):
        i = 1
        while True:
            yield i
            i += 2

但是,当我为此类调用 next 时,值不会增加。

>>> t = Test()
>>> next(t)
>>> (0, 1)
>>> next(t)
>>> (0, 1)

怎么了?有没有更雄辩的方式来写这门课?

【问题讨论】:

这个类的实例应该是什么?迭代器,还是多用途迭代器?为什么你有这个类而不是编写另一个生成器? 你打算通过编写这个类来创建什么行为? 我基本上想从两个单独的函数返回值。我不想在 next 方法中编写这两个函数,这些函数可以是生成器。有意义吗? 你会接受你得到的答案之一吗?如果不是,为什么会这样? 对不起。我不知道我需要接受答案。 【参考方案1】:

虽然我不知道您要完成什么,但这里有一个经过整理的版本,(我认为)可以满足您的要求。

class Test():
    def __init__(self):
        self.g1 = self._gen2() 
        self.g2 = self._gen1()
    def __next__(self):
        return next(self.g1), next(self.g2)

    def _gen1(self):
        i = 0
        while True:
            yield i
            i += 2

    def _gen2(self):
        i = 1
        while True:
            yield i
            i += 2

t = Test()

print(next(t))           
print(next(t))           
print(next(t))  

【讨论】:

谢谢。我认为我的例子是不言自明的。我的下一个方法应该从两个函数返回值。我不想在下一个方法体中编写这些函数。这些函数可以潜在地编写为生成器。这有意义还是我错过了什么?什么不清楚? 提供的解决方案不能做到这一点吗? 它有效,但既然你提到它不清楚我在做什么,我想知道我的方法是否错误。有没有其他方法可以实现这个目标? 好吧,如果你只想同时迭代两个生成器,我不知道你需要一个类的所有样板。为什么不直接做类似foo = zip(range(10),range(11,20)).【参考方案2】:

您的代码不起作用,因为它每次在调用__next__() 时重新创建生成器函数,这在返回下一个next() 值之前有效地将它们重置回初始状态:

    def __next__(self):
        g1, g2 = self._gen1(), self._gen2()  # Don't do this here.
        return next(g1), next(g2)

您可以通过添加 __init__() 方法并在其中初始化它们来解决此问题:

class Test:
    def __init__(self):
        self.g1, self.g2 = self._gen1(), self._gen2()  # Initialize here.

    def __next__(self):
        return next(self.g1), next(self.g2)
    ...

一个更雄辩和稍微更简洁的方法来避免这个问题是使用内置的zip() function创建一个“生成器迭代器”,每次它都会从每个生成器返回成对的下一个值。叫。另一个优点是它很容易扩展以处理更多的生成器,只需更改 __init__() 方法即可。

这就是我的意思:

class Test:
    def __init__(self):
        self.generators = zip(self._gen1(), self._gen2())

    def __next__(self):
        return next(self.generators)

    def _gen1(self):
        i = 0
        while True:
            yield i
            i += 2

    def _gen2(self):
        i = 1
        while True:
            yield i
            i += 2

t = Test()
for _ in range(3):
    print(next(t))

输出:

(0, 1)
(2, 3)
(4, 5)

【讨论】:

以上是关于当下一个方法应该返回两个生成器的值时,如何为类创建下一个方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何为表中的两列返回相同的值

iPhone - 我应该如何编写一个 init 方法?

如何为两个不同的子类创建超类

如何为不同类的字段赋值?

如何为 Google App Signing 生成上传密钥?

如何为泛型类编写 C# 扩展方法