假设我有一些函数
f
将接受可变数量的参数:
def f(*args):
for a in args:
print(a)
下面我通过三种方式调用这个函数:
f(l for l in range(5))
>>> <generator object <genexpr> at 0x1234>
f((l for l in range(5)))
>>> <generator object <genexpr> at 0x1234>
*
aka splat 展开它:f(*(l for l in range(5)))
>>> 0
>>> 1
>>> 2
>>> 3
>>> 4
f(l for l in range(5)) == f((l for l in range(5)))
返回:
<generator object <genexpr> at 0x7f8b2a5df570>
<generator object <genexpr> at 0x7f8b2a5df570>
True
这向我表明生成器表达式周围的括号实际上没有做任何事情。对吗?True
/False
输出,但它无法帮助自己并向我展示它为每个函数调用创建了一个生成器对象(? ).也就是说,如果我将输出分配给一个新变量,即 f2 = f(l for l in range(5))
,f2
是 NoneType
和 f2.__next__()
抛出错误(TypeError: 'NoneType' object is not an iterator
),向我表明我刚刚创建的生成器不能被分配给一个变量。*
展开?换句话说,括号是否只是因为口译员无法理解*l for l in range(5)
?f()
“看到”了什么?asyncio
上的这个 Real Python 教程,他们在其中反复使用生成器扩展(?),例如:
async def main():
res = await asyncio.gather(*(makerandom(i, 10 - i - 1) for i in range(3)))
return res
...我收集等于:
async def main():
res = await asyncio.gather(makerandom(0, 9),makerandom(1, 8), makerandom(2, 7))
return res
...但这是我在 Python 职业生涯中第一次真正面对 生成器艺术.
这向我表明生成器表达式周围的括号实际上没有做任何事情。对吗?
你是对的,括号没有做任何事情,但是
==
测试没有表明这一点; f
总是返回 None
,所以 f(a) == f(b)
对于任意两个值 a
和 b
(允许 f
返回)。
此外,当在上面的问题 2 中测试相等性时,虽然我期望一个简单的 True/False 输出,但它无法帮助自己并向我展示它为每个函数调用创建了一个生成器对象(?)。
(l for l in range(5))
是一个创建生成器对象的表达式。 f
在调用它时打印生成器对象,因为生成器对象是 args
的一个元素,并且您告诉它打印 args
的每个元素。如果你尝试 f(1) == f(2)
它会打印 1 和 2.
案例3中的括号是否只是为了打包我的表达式以便它可以
展开?换句话说,括号是否只是因为口译员无法理解*
?*l for l in range(5)
是的。
情况3,操作顺序是什么?
(l for l in range(5))
计算生成器表达式f(*value)
迭代 value
并将其转换为参数列表,使用该参数列表调用 f
接上一个问题——在案例3中,
“看到”了什么?f()
args == (1, 2, 3, 4)
。你可以print(args)
看到这个;它只是一个元组。
描述案例 3 的正确用语是什么? “扩展生成器并将其传递给函数”?
当然。