任何人都可以解释这些示例中的生成器是如何工作的吗?
在此示例中来自http://www.dabeaz.com/generators/index.html
wwwlog = open("access-log")
bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)
在此示例中(x * x表示范围内的x(1,100000000))
原因我有这个疑问就是这个片段:
def foo():
for each in range(1,100000):
yield each
a = foo()
# Here range is not evaluated until generator is run or just
# before first yield is hit which is expected.
a=(x for x in range(1,100000))
# I thought also does exact thing as that function and it i is a
# syntactic sugar for a=foo() which also yields a generator object.
使用生成器超过列表或场景更有实际可行吗?
答案 0 :(得分:5)
sum
)。bytes = (int(x) for x in (line.rsplit(None,1)[1] for line in wwwlog) if x != '-')
range
中返回一个列表,您需要xrange
来生成类似生成器的对象。range
中表现得像Python 2 xrange
。同样的事情发生在map
和filter
等其他功能上。生成器的主要优点是它们不会立即存储整个内容。它们的主要缺点是你只能迭代它们一次。
答案 1 :(得分:0)
1.当我们连接这样的生成器时,在我们执行sum()之前是否会发生任何实际工作?
生成器表达式返回一个按需生成结果的对象,而不是构建一个 结果列表,所以你的答案是否定的(但仍取决于你对实际工作的意思)。
2.为什么我们需要分别line.split(None,1)[1]
和int(x)
- 这样做是否有优势?
它只是让你的代码更具可读性并增加灵活性(基于你对该表达式的处理),你可以在一行中完成:
(int(line.rsplit(None,1)[1]) for line in wwwlog if ine.rsplit(None,1)[1] != '-')
在此示例中(x * x表示范围内的x(1,100000000))
3.在Python 2中是否计算了范围(1,100000000)?
是的,它是剂量,而在python 2中你可以使用返回迭代器的
xrange
。
4.如果是在本声明中或在发电机首次运行期间
...
5.在Python 3中这有什么不同吗?
在python 3中,内置函数返回一个迭代器,如
open
或range
要回答您的第4个问题和评论中的问题,我认为learning python by Mark Lutz的这一部分可能会有所帮助:
在所有最新版本的Python中,迭代器和列表推导的概念都是 结合了语言的新特性,生成器表达式。句法上, erator表达式就像普通的列表推导一样,但是它们被包含在内 括号而不是方括号:
>>> [x ** 2 for x in range(4)]
[0, 1, 4, 9] # List comprehension: build a list
>>> (x ** 2 for x in range(4))
<generator object at 0x011DC648> # Generator expression: make an iterable
事实上,至少在函数的基础上,编码列表理解基本上是相同的 在列表内置调用中包装生成器表达式以强制它生成所有它 立即生成一个列表:
>>> list(x ** 2 for x in range(4))
[0, 1, 4, 9]
然而,在操作上,生成器表达式是非常不同的 - 而不是构建 结果列表在内存中,它们返回一个生成器对象,后者又支持 迭代协议在任何迭代上下文中一次产生一个结果列表:
>>> G = (x ** 2 for x in range(4))
>>> next(G)
0
>>> next(G)
1
>>> next(G)
4
>>> next(G)
9
>>> next(G)
Traceback (most recent call last):
...more text omitted...
StopIteration
我们通常不会看到发电机引擎盖下的下一个迭代器机器 像这样的压力,因为for循环会自动触发它:
>>> for num in (x ** 2 for x in range(4)):
...
print('%s, %s' % (num, num / 2.0))
...
0, 0.0
1, 0.5
4, 2.0
9, 4.5
正如我们已经了解的那样,每个迭代上下文都会这样做,包括sum,map和 排序的内置函数;列表理解;和我们学到的其他迭代上下文 关于第14章,例如any,all和list内置函数。 请注意,如果它们是生成器表达式,则不需要括号 括在其他括号中的唯一项目,如函数调用。额外的 - 但是,在第二次调用sort:
时需要这些论文>>> sum(x ** 2 for x in range(4))
14
>>> sorted(x ** 2 for x in range(4))
[0, 1, 4, 9]
>>> sorted((x ** 2 for x in range(4)), reverse=True)
[9, 4, 1, 0]
>>> import math
>>> list( map(math.sqrt, (x ** 2 for x in range(4))) )
[0.0, 1.0, 2.0, 3.0]
生成器表达式主要是内存空间优化 - 它们不会重新 quire整个结果列表一次全部构建,作为方括号列表 理解确实如此。在实践中它们也可能运行得稍慢,所以它们可能也是如此 最好只用于非常大的结果集。关于per-的更权威的陈述 但是,formance必须等待我们将在本章后面编写的时序脚本。