要想创建一个iterator,必须实现一个有__iter__()和__next__()方法的类,类要能够跟踪内部状态并且在没有元素返回的时候引发StopIteration异常. 这个过程很繁琐而且违反直觉.Generator能够解决这个问题. python generator是一个简单的创建iterator的途径.前面讲的那些繁琐的步骤都可以被generator自动完成. 简单来说,generator是一个能够返回迭代器对象的函数. 怎样创建一个python generator?就像创建一个函数一样简单,只不过不使用return 声明,而是使用yield声明. 如果一个函数至少包含一个yield声明(当然它也可以包含其他yield或return),那么它就是一个generator. yield和return都会让函数返回一些东西,区别在于,return声明彻底结束一个函数,而yield声明是暂停函数,保存它的所有状态,并且后续被调用后会继续执行. generator函数和普通函数的区别
下面这个例子说明上述全部要点,我们有一个名为my_gen()的函数,它带有一些yield声明.
# A simple generator function
def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
在线实例: https://www.bytelang.com/o/s/c/nDeJ2dm7FUo= 有趣的是,在这个例子里变量n在每次调用之间都被记住了。和一般函数不同的是,在函数yield之后本地变量没有被销毁,而且,generator对象只能被这样迭代一次。 要想重复上面的过程,需要类似 a = my_gen() 这样创建另一个generator对象,并对其使用next方法迭代。 注意 :我们可以对generator对象直接使用for循环。 这是因为一个for循环接收一个iterator对象,且使用next()函数迭代它,当遇到StopIteration异常的时候自动停止。
# A simple generator function
def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
# Using for loop
# Output:
# This is printed first
# 1
# This is printed second
# 2
# This is printed at last
# 3
for item in my_gen():
print(item)
在线示例: https://www.bytelang.com/o/s/c/3py5nUg_WVI= 有循环的python generator上面的例子没有实际的应用意义,我们只是为了探究背后原理。 通常来说,generator都是和循环结合实现的,且这个循环带有一个终止条件。 我们来看一个reverse一个字符串的例子
def rev_str(my_str):
length = len(my_str)
for i in range(length - 1,-1,-1):
yield my_str[i]
# For loop to reverse the string
# Output:
# o
# l
# l
# e
# h
for char in rev_str("hello"):
print(char)
在线示例: https://www.bytelang.com/o/s/c/_rs3yQEbIhE= 我们在for循环里面使用range()函数来获取反向顺序的index。 generator除了可以应用于string,还可以应用于其它类型的iterator,例如list,tuple等。 python generator 表达式使用generator表达式可以很容易地创建简单的generator。 就像lambda函数可以创建匿名函数一样,generator函数创建一个匿名generator函数。 generator表达式的语法类似于python的list comprehension,只是方括号被替换为了圆括号而已。 list comprehension和generator表达式的主要区别在于,前者产生全部的list,后者每次仅产生一项。 它们有些懒惰,仅在接到请求的时候才会产生输出。因此,generator表达式比list comprehension更加节省内存。 # Initialize the list my_list = [1, 3, 6, 10] # square each term using list comprehension # Output: [1, 9, 36, 100] [x**2 for x in my_list] # same thing can be done using generator expression # Output: <generator object <genexpr> at 0x0000000002EBDAF8> (x**2 for x in my_list) 在线示例: https://www.bytelang.com/o/s/c/BgIb7R1NCls= 上面的例子中,generator表达式没有立即产生需要的结果,而是在需要产生item的时候返回一个generator对象。 # Intialize the list my_list = [1, 3, 6, 10] a = (x**2 for x in my_list) # Output: 1 print(next(a)) # Output: 9 print(next(a)) # Output: 36 print(next(a)) # Output: 100 print(next(a)) # Output: StopIteration next(a) 在线示例: https://www.bytelang.com/o/s/c/p1^6fITXP5A= generator表达式可以在函数内部使用。当这样使用的时候,圆括号可以丢弃。 python里为什么要使用generator?1.容易实现相对于iterator类来说,generator的实现清晰、简洁。下面是用iterator实现一个2的指数函数
class PowTwo:
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n > self.max:
raise StopIteration
result = 2 ** self.n
self.n += 1
return result
generator这样实现
def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1
因为generator自动跟踪实现细节,因此更加清晰、简洁。 2.节省内存一个函数返回一个序列(sequence)的时候,会在内存里面把这个序列构建好再返回。如果这个序列包含很多数据的话,就过犹不及了。 而如果序列是以generator方式实现的,就是内存友好的,因为他每次只产生一个item。 3.代表无限的streamgenerator是一个很棒的表示无限数据流的工具。无限数据流不能被保存在内存里面,并且因为generator每次产生一个item,它就可以表示无限数据流。 下面的代码可以产生所有的奇数
def all_even():
n = 0
while True:
yield n
n += 2
4.generator流水线(pipeline)generator可以对一系列操作执行流水线操作。 假设我们有一个快餐连锁店的日志。日志的第四列是每小时售出的披萨数量,我们想对近5年的这一数据进行求和。 假设所有数据都是字符,不可用的数据都以"N/A"表示,使用generator可以这样实现
with open('sells.log') as file:
pizza_col = (line[3] for line in file)
per_hour = (int(x) for x in pizza_col if x != 'N/A')
print("Total pizzas sold = ",sum(per_hour))
这个流水线既高效又易读,并且看起来很酷!:) (责任编辑:好模板) |


ecshop仿趣玩2012最新版
人气:720
ecshop桃花坞成人用品网站
人气:2206
ecshop免费模板仿一号店综
人气:5019
三色可换企业网站模板a
人气:575
Prestashop英文医疗护理网站
人气:209
服装韩国IW模板|ecshop模板
人气:392