转载至:https://www.bytelang.com/article/content/NQbmUaRIXyA=


要想创建一个iterator,必须实现一个有__iter__()和__next__()方法的类,类要能够跟踪内部状态并且在没有元素返回的时候引发StopIteration异常.

这个过程很繁琐而且违反直觉.Generator能够解决这个问题.

python generator是一个简单的创建iterator的途径.前面讲的那些繁琐的步骤都可以被generator自动完成.

简单来说,generator是一个能够返回迭代器对象的函数.

怎样创建一个python generator?

就像创建一个函数一样简单,只不过不使用return 声明,而是使用yield声明.

如果一个函数至少包含一个yield声明(当然它也可以包含其他yield或return),那么它就是一个generator.

yield和return都会让函数返回一些东西,区别在于,return声明彻底结束一个函数,而yield声明是暂停函数,保存它的所有状态,并且后续被调用后会继续执行.

generator函数和普通函数的区别

  • generator函数包含一个以上的yield声明
  • generator函数被调用的时候,会返回一个iterator对象,但是函数并不会立即开始执行
  • __iter__()和__next__()方法被自动实现,所以可以使用next()函数对返回的此iterator对象进行迭代
  • 一旦一个generator 执行到yield语句,generator函数暂停,程序控制流被转移到调用方
  • 在对generator的连续调用之间,generator的本地变量和状态会被保存
  • 最终,generator函数终止,再调用generator会引发StopIteration异常

下面这个例子说明上述全部要点,我们有一个名为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.代表无限的stream

generator是一个很棒的表示无限数据流的工具。无限数据流不能被保存在内存里面,并且因为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))

这个流水线既高效又易读,并且看起来很酷!:)

Python中Generators教程的更多相关文章

  1. 在Python中进行自动化单元测试的教程

    From: https://www.jb51.net/article/64119.htm 一.软件测试 大型软件系统的开发是一个很复杂的过程,其中因为人的因素而所产生的错误非常多,因此软件在开发过程必 ...

  2. python操作txt文件中数据教程[4]-python去掉txt文件行尾换行

    python操作txt文件中数据教程[4]-python去掉txt文件行尾换行 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文章 python操作txt文件中数据教程[1]-使用pyt ...

  3. python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件

    python操作txt文件中数据教程[3]-python读取文件夹中所有txt文件并将数据转为csv文件 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 python操作txt文件中 ...

  4. python操作txt文件中数据教程[2]-python提取txt文件

    python操作txt文件中数据教程[2]-python提取txt文件中的行列元素 觉得有用的话,欢迎一起讨论相互学习~Follow Me 原始txt文件 程序实现后结果-将txt中元素提取并保存在c ...

  5. python操作txt文件中数据教程[1]-使用python读写txt文件

    python操作txt文件中数据教程[1]-使用python读写txt文件 觉得有用的话,欢迎一起讨论相互学习~Follow Me 原始txt文件 程序实现后结果 程序实现 filename = '. ...

  6. python基础系列教程——Python中的编码问题,中文乱码问题

    python基础系列教程——Python中的编码问题,中文乱码问题 如果不声明编码,则中文会报错,即使是注释也会报错. # -*- coding: UTF-8 -*- 或者 #coding=utf-8 ...

  7. Python教程:Python中的for 语句

    Python 中的 for 语句与你在 C 或 Pascal 中可能用到的有所不同. Python教程 中的 for 语句并不总是对算术递增的数值进行迭代(如同 Pascal),或是给予用户定义迭代步 ...

  8. python中global的用法——再读python简明教程

    今天看了知乎@萧井陌的编程入门指南,想重温一下 <python简明教程>,对global的用法一直不太熟练,在此熟练一下,并实践一下python中list.tuple.set作为参数的区别 ...

  9. 在Python中使用lambda高效操作列表的教程

    在Python中使用lambda高效操作列表的教程 这篇文章主要介绍了在Python中使用lambda高效操作列表的教程,结合了包括map.filter.reduce.sorted等函数,需要的朋友可 ...

随机推荐

  1. 阐述 QUEST CENTRAL FOR DB2 八罪

    作为一个从事oracle plsql发展2猿 - 年计划,现在,在退出DB2数据仓库项目. 同PL/SQL Developer参考,下文PLSQL,阐述QUEST CENTRAL FOR DB2 5. ...

  2. PDF解决方案(3)--PDF转SWF

    相关专题链接 PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:上一篇中介绍了上传的文件转PDF, ...

  3. ubuntu忘记密码,无法sudo的解决方法

    想要安装一个sublime Text Editor,发现需要root权限,而且sudo用户的密码输进去没有作用!@ubuntu 14.04 LTS 这个时候怎么办呢? 打开终端,在终端中使用 sudo ...

  4. js 监控浏览器关闭事件

    代码如下: <!DOCTYPE html> <html> <head> <title>监控浏览器关闭事件</title> </head ...

  5. Extension+NVelocity

    VS Extension+NVelocity系列(二)——让VS支持 NVelocity的智能提示(上)   一.基础概念 应该庆幸的是,VS的插件是靠着MEF实现而不是MAF,这让你所做的工作减轻了 ...

  6. .net微软消息队列(msmq)简单案例

    1.首先我们需要安装消息队列服务,它是独立的消息记录的服务,并保存在硬盘文件中. 我们添加名为:DMImgUpload的私有消息队列. 2.定义消息队列的连接字符串建议采用IP: (1)FormatN ...

  7. iOS基础 - 单元测试

    单元测试(unit testing):对软件中最小可测试单元进行检查和验证.一般面向过程的语言中,基本单元为函数,面向对象的语言中,基本单元通常是类,其实对于一个手机上的app来说基本单元也可以是一个 ...

  8. IT团队管理

    如果在IT项目实施中选出最难解决的几个问题,那么管理问题一定名列前茅.在管理问题中,团队管理又是其中的难点.一个项目管理的 好坏,很大程度就体现在团队的建设和管理上.团队管理涉及到管理学.心理学和哲学 ...

  9. 网​址​U​R​L​中​特​殊​字​符​转​义​编​码

    网址URL中特殊字符转义编码 字符 - URL编码值 空格 - %20 " - %22 # - %23 % - %25 & - %26 ( - %28 ) - %29 + - %2B ...

  10. [原]使用MachOView辅助破解AppStore应用

    在破解iOS应用的过程中,需要经常使用 otool 开获取程序本身的信息(比如:是否启用了PIE),获取加密信息, 但是CLI的程序在直观性上还是不如GUI的, 下面描述使用MachOView来查看到 ...