1、生成器表达式
生成器表达式是一种类似于列表推导的语法,但是它返回的是一个生成器对象而不是列表。生成器表达式使用圆括号 ()
。
# 使用生成器表达式创建生成器 ret = (x ** 2 for x in range(10)) # 遍历生成器 for value in ret: print(value)
如对G量级的日志文件做处理。使用for
循环,可以一次只处理一行而不需要将下一行读入内存。并且不会创建一个最终的容器对象。则可以创建一个生成器表达式,语法很简洁。代码如下,
import sys
inname = sys.argv[1]
outname = sys.argv[2]
with open(inname) as infile:
with open(outname, "w") as outfile:
warnings = (l for l in infile if 'WARNING' in l)
for l in warnings:
outfile.write(l)
2、生成器(yield)
yield
是生成器的关键字,可以通过编写一个普通的函数,然后在其中使用 yield
语句而不是 return
来创建生成器。当函数执行到 yield
时,它会返回一个值并暂停执行。下次从生成器中获取值时,它会从停止的地方继续执行。
# 使用 yield 创建生成器函数 def myYield(): for x in range(10): yield x ** 2 # 创建生成器 generator = myYield() # 遍历生成器 for value in generator: print(value)
可以通过yield
删除日志文件中WARNING列的例子,代码如下,
import sys
iname, outname = sys.argv[1:3]
def warnings_filter(p) :
for l in p:
if 'WARNING' in l:
yield l.replace('\tWARNING',' ')
with open(inname) as infile:
with open(outname, "w") as outfile:
filter = warnings_filter(infile)
for l in filter:
outfile.write(l)
带有yield
关键字函数返回的是一个生成器对象,这个对象有__iter__
和__next__
方法,每当__next__
被调用,生成器都会执行到yield
语句。然后它会返回yield
的值。当__next__
下一次被调用时,它会在上次停止的地方继续执行。
yield方法返回生成器对象
>>> help(warnings_filter([]))
Help on generator object:
warnings_filter = class generator(object)
| Methods defined here:
|
| __del__(...)
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __next__(self, /)
| Implement next(self).
|
| __repr__(self, /)
| Return repr(self).
|
| close(...)
| close() -> raise GeneratorExit inside generator.
|
| send(...)
| send(arg) -> send 'arg' into generator,
| return next yielded value or raise StopIteration.
|
| throw(...)
| throw(typ[,val[,tb]]) -> raise exception in generator,
| return next yielded value or raise StopIteration.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| gi_code
|
| gi_frame
|
| gi_running
|
| gi_yieldfrom
| object being iterated by yield from, or None
通过生成器(yield
)实现,可读性可以,代码也很简洁。如果只是用for
循环或面向对象方式实现,代码应该都会稍微复杂一点。