【问题标题】:"Double" iterator and a generator function“双”迭代器和生成器函数
【发布时间】:2018-04-30 12:08:33
【问题描述】:

我想用类似迭代器的对象获取“下一个资产”,但是(而不是 __next__() 方法)有两种算法加载下一个资产(next1next2 下面),可以实现为一个“准迭代器”,例如:

class AssetLoader(object):
    def __init___(self):
        pass

    def next1(self):
        # ...

    def next2(self):
        # ...

需要明确的是,下一个检索到的对象可能取决于调用next1next2 的“历史”,例如:

next1(); next1(); next2(); next1(); next2()

我的问题:这(迭代器中的两种“下一步”步骤)可以实现为生成器函数吗?

我想这可以通过函数引用的全局变量来完成。但是可以不使用全局变量,而是使用一些局部变量来完成吗?

如果当前的 Python 很难或不可能,我们可以讨论如何在 Python 中添加新的语义以使其成为可能吗?

【问题讨论】:

  • 您能否提供更多关于选择 next1 或 next2 以获得下一个元素的逻辑?为什么 __next__ 中的简单条件是不够的?
  • 这听起来很有趣... OTOH,它可能是XY problem。 ;) 如果你能给我们一个简单的“假”例子,说明你如何将它与它产生的输出一起使用,它会让我们更容易理解你想要做什么。
  • @porton 如果您无法添加更多上下文,您将得不到任何有用的答案。
  • 我们不是要你的真实例子。只是一个简单示例,展示了您想要实现的行为类型。然后我们可以 a) 向您展示执行此操作的代码,或者 b) 告诉您为什么使用普通 Python 语法无法做到这一点。 Python 非常强大且用途广泛,因此我对 a) 寄予厚望。但如果没有明确的问题陈述,恐怕您的问题将无法回答。
  • 好的。调用生成器的代码会选择红色还是蓝色?如果是这样,那听起来像是 send 的工作。

标签: python iterator generator


【解决方案1】:

这是一个使用send 在两种不同迭代模式之间切换生成器的简单示例:它要么增加其当前值,要么将其相乘。同样的原理也可以应用于你的图遍历任务。

send 方法允许您将对象发送到生成器。烦人的是,send 的结果是您通过调用next 获得的当前值;如果您可以在不让生成器产生值的情况下发送,那就太好了,但这只是我们必须忍受的。

def add_or_mul(current, step, scale, mode='add'):
    ''' A generator that either adds step to the current value,
        or multiplies it by scale
    '''
    while True:
        newmode = yield current
        if newmode is not None:
            if newmode not in ('add', 'mul'):
                raise ValueError('Bad mode: ' + newmode)
            mode = newmode
        if mode == 'add':
            current += step
        else:
            current *= scale

# Test

    gen = add_or_mul(1, 1, 2)
    for i in range(5):
        print(next(gen))
    print(gen.send('mul'))
    for i in range(4):
        print(next(gen))
    print(gen.send('add'))
    for i in range(4):
        print(next(gen))       

输出

    1
    2
    3
    4
    5
    10
    20
    40
    80
    160
    161
    162
    163
    164
    165

如果您在将这种技术应用于图形遍历任务时遇到问题,请提出一个新问题(可能链接到这个问题),其中包含一些相关的图形代码,这样回答者就不必从头开始编写这些东西来测试并演示他们的代码。

【讨论】:

    【解决方案2】:

    你可以试试这个:

    class AssetLoader(object):
        def __init___(self):
            self.current_next = self.next1
    
        def next1(self):
            if condition:
                self.current_next = self.next2
            elif conition:
                return x
            else:
                raise StopIteration
    
        def next2(self):
            if condition:
                self.current_next = self.next1
            elif conition:
                return y
            else:
                raise StopIteration
    
        def __next__(self):
            return self.current_next()
    
        def __iter__(self):
            return self
    

    【讨论】:

    • @porton 你的问题还不清楚。为什么需要生成器函数而不是不同类型的迭代器?对于它的价值,将这个实现变成一个生成器函数非常简单。请展示您的尝试,然后我们或许能够了解您的实际问题。
    • 如果遇到next[12] 中的第一个condition,则迭代器将产生一个None 元素,这似乎是错误的。
    • @porton 我完全不明白你的问题。为什么不简单地将当前状态存储在局部变量中?
    • 我根本没有得到这个答案。为什么有两个next1next2 函数有时会设置一个属性,有时会返回一些东西,有时会抛出异常?这些有什么意义?他们在做什么?我将如何使用这个 AssetLoader 类?
    • 不要责怪答案。对于初学者来说这个问题还不清楚
    猜你喜欢
    • 2020-03-10
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 2016-09-04
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多