【问题标题】:Variable length 'yield'?可变长度“产量”?
【发布时间】:2012-10-22 18:13:27
【问题描述】:

我希望能够yield 可变数量的项目,这将允许编写类似于以下内容的生成器函数:

x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]

def multi_enumerate(*iterables):
    n = 0
    iterators = map(iter, iterables)
    while iterators:
        yield n, *tuple(map(next, iterators))  # invalid syntax
        n += 1

for i,a,b,c in multi_enumerate(x, y, z):
    print i,a,b,c

有人知道这样做的方法吗?我知道我可以生成一个元组,但这需要在接收端明确解包它,例如:a,b,c = t[0], t[1], t[2]

最终解决方案

FWIW,这是我最终使用的,基于 John Kugelman 的出色回答:

from itertools import izip

def multi_enumerate(*iterables, **kwds):
    start = kwds.get('start')
    if start is None:
        if kwds: raise TypeError(
            "multi_enumerate() accepts only the keyword argument 'start'")
        try:
            iter(iterables[-1])  # last non-keyword arg something iterable?
        except TypeError:        # no, assume it's the start value
            start, iterables = iterables[-1], iterables[:-1]
        else:
            start = 0  # default

    return ((n,)+t for n, t in enumerate(izip(*iterables), start))

添加的代码是因为我希望它也接受一个可选的不可迭代的最后一个参数来指定一个非 0 的起始值(或使用 start 关键字参数指定它),就像内置的一样enumerate()函数。

【问题讨论】:

  • 您在寻找zip 还是izip
  • yield 在某种意义上就像return - 你可以产生同样数量的东西,你可以返回。也就是说,一件事物,但你可以返回所有参数的元组。
  • 如果您只想将迭代器组合到一个生成器中,请使用itertools.izip
  • @Makoto:是的,好点子。问题的关键是我没有意识到如果函数只是 yielded 一个 single 元组,那么它可以在接收端正确拆分。我接受的答案解决了这个问题,然后解决了一些问题。

标签: python generator enumerate


【解决方案1】:

yield 语句更改为:

yield (n,) + tuple(map(next, iterators))

或者使用izipenumerate来消除整个循环:

from itertools import izip

def multi_enumerate(*iterables):
    return ((n,) + t for n, t in enumerate(izip(*iterables)))

【讨论】:

    【解决方案2】:

    我会使用来自itertoolschain

    yield tuple(chain((n,), map(next, iterators)))
    

    【讨论】:

      【解决方案3】:

      如果你想委派几个项目从你的生成器到另一个生成器,没有单行的方法可以做到这一点——除非你使用features yield from的Python 3.3。

      我会迭代嵌套生成器,显式地从它们产生值,比如

      yield n
      for value in (delegated.next for delegated in iterators):
        yield value
      

      【讨论】:

        【解决方案4】:

        这将返回一个迭代器,该迭代器为 i n-length ls 生成 (n, *l[n])。它将直接替代您的 multienumerate 方法。

        from itertools import izip
        def enumerated_columns(*rows):
            return izip(range(len(rows[0])), *rows)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-06
          • 2013-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-08
          • 2014-07-27
          • 2020-11-20
          相关资源
          最近更新 更多