是否有内置方式(例如装饰器)在definiton实例化Python生成器?

时间:2016-05-16 22:11:40

标签: python generator decorator

是否有内置/推荐的方法来替换装饰器:

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

这是一个简化的例子。在实际用例中,没有必要/理由有两个mygenerator实例,因此我想立即创建实例。优选地,不能创建其他实例。

3 个答案:

答案 0 :(得分:2)

内置的方法是这样的:

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

mygenerator = mygenerator()

这至少具有明确的优点,因此您不必查看@generator所做的事情。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

你正在做的事情就像它可能是惯用的一样。有些语言有一个名为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所说,有一些生成器理解,它可以很好地用于你可以使用它们,但如果你需要更多的逻辑,那么你所做的似乎是最恐怖的方式。只是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是隐藏的,因此只能由更新它的函数引用。