是否有内置方法(例如装饰器)在定义时实例化 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
是隐藏的,所以它只能被更新它的函数引用。
有没有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
是隐藏的,所以它只能被更新它的函数引用。