列表上的生成器与链接生成器和内存消耗?
Generators on a list vs chaining generators and memory consumption?
谁能解释一下生成器在这些示例中的工作原理?
本例来自 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)
- 当我们像这样链接生成器时,除了代码对象创建之外,在我们执行 sum() 之前是否会发生任何实际工作?
- 为什么我们需要做 line.split(None,1)[1]
和 int(x) 分开 - 这样做有优势吗?
在这个例子中(x*x for x in range(1,100000000))
- 当解释器计算这个表达式时,Python 2 中是否计算了范围(1,100000000)?
- 在该语句期间或在生成器的第一次运行期间是否发生这种情况
- 这在 Python 3 中有什么不同吗?
原因我怀疑是这个片段:
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.
使用生成器比使用列表或更实用的场景有什么优势吗?
1.When 我们像这样链接生成器在我们执行 sum() 之前会发生任何实际工作吗?
Generator expression return an object that produces results on demand instead of building a
result list so your answer is No (but it still depends on your mean about real work).
2.Why 我们是否需要分别执行 line.split(None,1)[1]
和 int(x)
- 这样做有优势吗?
it just make your code more readable and increase flexibility (based on what you may do with that expression), you can do it in one line :
(int(line.rsplit(None,1)[1]) for line in wwwlog if ine.rsplit(None,1)[1] != '-')
在这个例子中(x*x for x in range(1,100000000))
3.Is range(1,100000000) 在 Python 2 ?
中计算
yes it dose , instead in python 2 you can use xrange
that return an iterator.
4.If 在此语句期间或生成器的第一个 运行 期间也是如此
...?
5.Is 这个不同 Python 3 ?
in python 3 meany of built-in functions return an iterator like open
or range
对于您的第 4 个问题和您在评论中的问题的回答,我认为 learning python by Mark Lutz 的这一部分可能会有所帮助:
生成器表达式:迭代器满足理解
在 Python 的所有最新版本中,迭代器和列表理解的概念是
结合了语言的新特性,生成器表达式。从句法上讲,gen-
运算符表达式就像普通的列表推导式一样,但它们包含在
括号而不是方括号:
>>> [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
事实上,至少在功能基础上,编码列表理解本质上是相同的
将生成器表达式包装在列表 built-in 调用中以强制它生成所有
立即生成列表:
>>> list(x ** 2 for x in range(4))
[0, 1, 4, 9]
列表理解等价
然而,在操作上,生成器表达式非常不同——而不是构建
内存中的结果列表,它们 return 一个生成器 object,它反过来支持
在任何迭代上下文中一次产生一个结果列表的迭代协议:
>>> 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
我们通常不会在生成器 ex- 的引擎盖下看到下一个迭代器机制
像这样压缩是因为 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 和
排序 built-in 函数;列出理解;以及我们学到的其他迭代上下文
关于第 14 章中的 any 、 all 和 list built-in 函数。
请注意,生成器表达式周围不需要括号,如果它们是
包含在其他括号中的唯一项目,就像函数调用的那些一样。额外的父母-
然而,在第二次调用 sorted 时需要这些:
>>> 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]
生成器表达式主要是 memory-space 优化——它们不会重新
要求一次性构建整个结果列表,如 square-bracketed 列表
理解力呢。他们在实践中也可能 运行 稍微慢一点,所以他们可能是
最好只用于非常大的结果集。比较权威的说法是per-
但是,性能必须等待我们将在本章稍后编写的计时脚本。
- 生成器是惰性的,因此在您遍历它们之前什么也不会发生(例如使用
sum
)。
- 它只是让它更具可读性。如果你想,你可以这样写:
bytes = (int(x) for x in (line.rsplit(None,1)[1] for line in wwwlog) if x != '-')
- 是的,在Python 2
range
returns 一个列表中,你需要xrange
来生成类似生成器的对象。
- 迭代生成器时计算,在此之前什么都不做。
- 是的,在 Python 3
range
中表现得像 Python 2 的 xrange
。同样的事情也发生在其他函数上,比如 map
和 filter
.
生成器的主要优点是它们不会一次存储全部内容。它们的主要缺点是您只能迭代一次。
谁能解释一下生成器在这些示例中的工作原理?
本例来自 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)
- 当我们像这样链接生成器时,除了代码对象创建之外,在我们执行 sum() 之前是否会发生任何实际工作?
- 为什么我们需要做 line.split(None,1)[1] 和 int(x) 分开 - 这样做有优势吗?
在这个例子中(x*x for x in range(1,100000000))
- 当解释器计算这个表达式时,Python 2 中是否计算了范围(1,100000000)?
- 在该语句期间或在生成器的第一次运行期间是否发生这种情况
- 这在 Python 3 中有什么不同吗?
原因我怀疑是这个片段:
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.
使用生成器比使用列表或更实用的场景有什么优势吗?
1.When 我们像这样链接生成器在我们执行 sum() 之前会发生任何实际工作吗?
Generator expression return an object that produces results on demand instead of building a result list so your answer is No (but it still depends on your mean about real work).
2.Why 我们是否需要分别执行 line.split(None,1)[1]
和 int(x)
- 这样做有优势吗?
it just make your code more readable and increase flexibility (based on what you may do with that expression), you can do it in one line :
(int(line.rsplit(None,1)[1]) for line in wwwlog if ine.rsplit(None,1)[1] != '-')
在这个例子中(x*x for x in range(1,100000000))
3.Is range(1,100000000) 在 Python 2 ?
中计算yes it dose , instead in python 2 you can use
xrange
that return an iterator.
4.If 在此语句期间或生成器的第一个 运行 期间也是如此
...?
5.Is 这个不同 Python 3 ?
in python 3 meany of built-in functions return an iterator like
open
orrange
对于您的第 4 个问题和您在评论中的问题的回答,我认为 learning python by Mark Lutz 的这一部分可能会有所帮助:
生成器表达式:迭代器满足理解
在 Python 的所有最新版本中,迭代器和列表理解的概念是 结合了语言的新特性,生成器表达式。从句法上讲,gen- 运算符表达式就像普通的列表推导式一样,但它们包含在 括号而不是方括号:
>>> [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
事实上,至少在功能基础上,编码列表理解本质上是相同的 将生成器表达式包装在列表 built-in 调用中以强制它生成所有 立即生成列表:
>>> list(x ** 2 for x in range(4))
[0, 1, 4, 9]
列表理解等价
然而,在操作上,生成器表达式非常不同——而不是构建 内存中的结果列表,它们 return 一个生成器 object,它反过来支持 在任何迭代上下文中一次产生一个结果列表的迭代协议:
>>> 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
我们通常不会在生成器 ex- 的引擎盖下看到下一个迭代器机制 像这样压缩是因为 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 和 排序 built-in 函数;列出理解;以及我们学到的其他迭代上下文 关于第 14 章中的 any 、 all 和 list built-in 函数。 请注意,生成器表达式周围不需要括号,如果它们是 包含在其他括号中的唯一项目,就像函数调用的那些一样。额外的父母- 然而,在第二次调用 sorted 时需要这些:
>>> 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]
生成器表达式主要是 memory-space 优化——它们不会重新 要求一次性构建整个结果列表,如 square-bracketed 列表 理解力呢。他们在实践中也可能 运行 稍微慢一点,所以他们可能是 最好只用于非常大的结果集。比较权威的说法是per- 但是,性能必须等待我们将在本章稍后编写的计时脚本。
- 生成器是惰性的,因此在您遍历它们之前什么也不会发生(例如使用
sum
)。 - 它只是让它更具可读性。如果你想,你可以这样写:
bytes = (int(x) for x in (line.rsplit(None,1)[1] for line in wwwlog) if x != '-')
- 是的,在Python 2
range
returns 一个列表中,你需要xrange
来生成类似生成器的对象。 - 迭代生成器时计算,在此之前什么都不做。
- 是的,在 Python 3
range
中表现得像 Python 2 的xrange
。同样的事情也发生在其他函数上,比如map
和filter
.
生成器的主要优点是它们不会一次存储全部内容。它们的主要缺点是您只能迭代一次。