是否有内置方法(例如装饰器)在定义时实例化 Python 生成器?

Is there a built-in way (e.g., a decorator) to instantiate a Python generator at definiton?

有没有built-in/recommended方法来替换装饰器:

def generator(f):
    return f()

在下面的例子中?

from random import randint

@generator
def mygenerator():
    while True:
        yield randint(0, 9)

for i in mygenerator:
    print i

...因为我不想写:

for i in mygenerator():
    print i

这是一个简化的例子。在实际用例中,没有 need/reason 有两个 mygenerator 实例,因此我想立即创建实例。最好以无法创建其他实例的方式。

内置的方法是这样的:

def mygenerator():
    while True:
        yield randint(0, 9)

mygenerator = mygenerator()

这至少有一个优点是清楚,所以你不必查找@generator是做什么的。

可以使用 () 语法创建生成器 - 即

mygenerator = (randint(0, 9) for i in range(0, 100))

但我想你的问题是生成器是无限的 - 你可以试试这个:

import itertools
from random import randint

mygenerator = (randint(0, 9) for i in itertools.count())

有关更多详细信息,请参阅 this answer

您正在做的事情尽可能符合惯用语。一些语言有一个名为 do 的二进制前缀运算符,它调用它的参数:

generator = do <generator expression>

Python 语法不允许您将多行函数编写为表达式。您必须使用 def 语句。这就是为什么您不能在 Python 中使用常规调用将多行函数或生成器传递给装饰器的原因:

generator = decorator(def generator(): yield) # syntax error

您必须预先定义函数或生成器:

def generator(): yield
generator = decorator(generator)

主要是语法限制迫使 Python 采用 @ 语法来装饰用 def 语句定义的函数。下面的代码等同于最后一个示例(除了 分配名称时 的细微差别外:

@decorator
def generator(): yield

正如 Greg 所提到的,有生成器推导式,它们在您可以使用它们的地方工作得非常好,但是如果您需要在主体中使用更多逻辑,那么您正在做的事情似乎是最多的 Pythonic 方式。只是 Python 语法总是让函数式编程变得笨拙。


您在评论中询问了具有 do 运算符的语言。 CoffeeScript 和 Haskell 都有。老实说,我不太明白 anything the Haskell docs say,但在 CoffeeScript 中,do 对于在闭包中创建值很有用。

看看这段代码(下面有解释)。

updateElementText = do ->
  element = jQuery "#someElement"
  return (newText) -> element.text newText

在 JS 中看起来像这样:

let updateElementText = function() {
  let element = jQuery("#someElement");
  return function(newText) { element.text(newText) };
}(); // Immediately-Invoked Function Expression (IIFE)

代码将 updateElementText 分配给第 3 行返回的函数,该函数通过闭包引用 element。该元素仅被 jQuery 选择一次(在第 2 行),无论调用多少次 updateElementText 来更新该元素。还要注意 element 是隐藏的,所以它只能被更新它的函数引用。