【问题标题】:Hybrid Generator/Function in PythonPython中的混合生成器/函数
【发布时间】:2016-12-22 14:24:21
【问题描述】:

在 Python 中是否有可能有一个在循环中产生值的生成器,也可以作为普通函数调用,并返回该循环的最终值?我尝试将标志设置为参数,然后根据该标志选择屈服或返回。但是函数中仅仅存在关键字 yield 就会自动将其转换为生成器,Python 抱怨说生成器中有 return 语句。

这里有一个这样的函数的例子:

def function(generator=True):
    a = 0
    for i in range(10):
        a = i
        if generator:
            yield a
    if not generator:
        return a

当在某些情况下我只需要最终结果(例如,将其用作残差函数进行优化)而在其他情况下我需要每次迭代后的增量结果(例如使用微分机器人模型,用每个新的速度命令更新机器人的位姿)。现在我有两个函数,一个有收益,另一个有回报。那么这两者可以结合起来吗?

【问题讨论】:

  • 创建一个迭代整个生成器并返回最后一个结果的包装器?!同一个函数可以像生成器正常函数一样起作用,这似乎很疯狂。分担这个责任。话虽如此,为单个值迭代整个生成器似乎更疯狂。不能直接计算最后一个值,真的分担这两个函数的职责吗?
  • 据我所知这是不可能的,因为来自机器人的数据代表周期性的电机编码器刻度(达到 65536 时重置为零)并且需要逐步计算位姿更新,它毕竟被称为“差分”模型。包装器仍然是另一个功能,所以我想知道是否可以进行融合。疯狂并不总是一个坏词:)
  • 在您的代码中将return 替换为yield。现在,当您想将该函数用作“简单函数”时,您只需使用next(function(generator=False)),而当您想将其用作生成器时,您将其用作for x in function(generator=True)

标签: python-2.7 function return generator yield


【解决方案1】:

它仍然是一个生成器,甚至调用 return。 无论如何,我都不会同时使用生成器/常规函数。

你可以在迭代器的顶部包裹一些东西,以防你需要循环遍历结果。

一个可以做你想做的简单代码:

last = None
for last in function(): pass

现在 last 保存你想要的值,你可以在你的代码中使用它。

生成器内的返回被添加到Python 3.3 并且等价于 StopIteration(value)

在生成器中返回 expr 会引发 StopIteration(expr) 从生成器退出时。

在生成器中,语句

返回值在语义上等价于

raise StopIteration(value) 除了目前的例外 不能被返回生成器中的 except 子句捕获。

【讨论】:

  • 即使在建议的问题中重复,人们说 return 可以在生成器中调用,但在我的情况下,它会导致我的程序崩溃。 SyntaxError: 'return' with parameter inside generator
  • 看来python 3.3上添加了generator里面的“return”python.org/dev/peps/pep-0380/…你用的是哪个版本?
  • 似乎有道理,我正在使用的 Python 2.7 中 return 是不允许有值的。
【解决方案2】:

您仍然需要对其进行迭代以获取其单个值,但您可以再次使用 yield 而不是 return 来完成此操作。

>>> def function(generator=True):
...     a = 0
...     for i in range(10):
...         a = i
...         if generator:
...             yield a
...     if not generator:
...         yield a
...
>>> a = function()
>>> print(*a)
0 1 2 3 4 5 6 7 8 9
>>> a = function(0)
>>> print(a)
<generator object function at 0x0000000001603240>
>>> print(*a)
9
>>> a = function(0)

请注意,在生成器中包含 return 在 Python 2 中是 SyntaxError,但在 Python 3 中不是。将 return 替换为 yield 在 2 和 3 中会产生相同的结果。

【讨论】:

  • 你也可以直接调用next:val = next(function(False)),而不是解压。
  • @Bakuriu - 我考虑过,但还是选择了*,因为它更短而且我很懒。 :P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-22
  • 1970-01-01
  • 2019-02-23
  • 2016-12-16
  • 2022-06-16
相关资源
最近更新 更多