【问题标题】:Python 3.8: definition with if/else condition and return/yield (always returns a generator)Python 3.8:使用 if/else 条件和 return/yield 定义(总是返回一个生成器)
【发布时间】:2021-02-06 09:14:37
【问题描述】:

[Python 3.8 |蜘蛛]

我试图引入一个简单的定义,它可以将数字按顺序排列为return [1,2,3]yield

最低工作代码如下:

def example(condition):
    if condition:
        yield 1
        yield 2
        yield 3
    else:
        return [1,2,3]

如果有人尝试使用def它总是会返回一个生成器。即使 return 在 if/else 对中首先出现:

def example(condition):
    if not condition:
        return [1,2,3]

    else:
        yield 1
        yield 2
        yield 3

即使condition = False,python 似乎也没有忽略收益率的存在。 这是一种意外行为。

【问题讨论】:

  • 如果函数中存在任何yield,它将成为一个生成器。它不需要被“击中”。
  • 但这残酷地限制了它。这意味着 if/else 根本不被尊重,如果不被尊重,是否至少不构成安全漏洞?
  • @David:我不确定您是如何实现这一飞跃的(针对安全漏洞)-备用分支中的代码没有以任何方式执行,只是编译阶段使用了它决定函数是生成器。这种行为是众所周知的。从任何代码路径产生的函数是生成器。如果您返回某些内容,我认为实际上会导致StopIteration 异常,并将返回值作为值。
  • 安全性飞跃是我担心编译过程会考虑 if/else 对中的任何内容,而不关心将要执行的部分是否是 if 或 else 中的内容。与此同时,我找到了临时的、极其悲伤的解决方案:
  • 为什么你需要它这样做顺便说一句?如果您不想将其用作生成器,您就不能直接说 list(example()) 吗?

标签: python if-statement return yield python-3.8


【解决方案1】:

可以以生成器表达式的形式返回生成器:

>>> def example(condition):
...     if condition:
...         return (i for i in (1, 2, 3))
...     else:
...         return [1, 2, 3]
>>> example(1)
<generator object example.<locals>.<genexpr> at 0x000000000257BBA0>

>>> example(0)
[1, 2, 3]

或者你可以单独定义生成器:

>>> def g():
...     yield 1
...     yield 2
...     yield 3
...
>>> def example(condition):
...     if condition:
...         return g()
...     else:
...         return [1, 2, 3]
>>> example(1)
<generator object g at 0x000000000257BBA0>

>>> example(0)
[1, 2, 3]

【讨论】:

  • 不幸的是,我不得不接受这个可悲的解决方案(python 的错)。它使我们不必要地重复代码。
【解决方案2】:

从语法上讲,def 语句在其套件中带有 yield 语句定义了一个生成器。在运行时是否实际到达yield 是无关紧要的,实际上是无法确定的。

def another_example():  # this function has a well-defined type
    if random.random() < 0.5:
       yield 'What is the type of this function?'
    return 'Of course it is a generator function!'

为了让函数计算生成器或非生成器值,请为生成器或生成器表达式使用单独的定义。

def example_generator():
    yield 1
    yield 2
    yield 3

def example(condition):
    if not condition:
        return [1,2,3]
    else:
        return example_generator()

如果两条路径最终都应该提供相同的值,那么在函数之外进行选择在语义上是相同的。这使得只提供一个生成器功能就足够了;结果可以在外部转换为另一种类型。

def example():
    yield 1
    yield 2
    yield 3

print("I prefer lists, such as:", list(example()))

【讨论】:

    猜你喜欢
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 2016-09-03
    • 2016-05-10
    相关资源
    最近更新 更多