10、Python迭代器与生成器(iterator、for循环、generator、yield)
一、迭代器(foreach)
1、可迭代的对象
内置有__iter__方法的都叫可迭代的对象。
Python内置str、list、tuple、dict、set、file都是可迭代对象。
x = 1.__iter__ # SyntaxError: invalid syntax # 以下都是可迭代的对象
name = 'nick'.__iter__
print(type(name)) # <class 'method-wrapper'>
2、迭代器对象
执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象。
只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的,只能使用迭代器对象。
- 内置有
__iter__方法,执行该方法会拿到迭代器本身。 - 内置
__next__方法,执行该方法会拿到迭代器对象中的一个值。
s = 'hello'
iter_s = s.__iter__()
print(type(iter_s)) # <class 'str_iterator'> iter_s为迭代器对象
while True:
try:
print(iter_s.__next__())
except StopIteration:
break
#hello
3、迭代器有两个基本的方法:iter() 和 next()。
s = 'hello'
iter_s = iter(s) # 创建迭代器对象
print(type(iter_s)) # <class 'str_iterator'> iter_s为迭代器对象 while True:
try:
print(next(iter_s)) # 输出迭代器的下一个元素 except StopIteration:
break
# hello
4、for迭代器循环
可迭代对象可以直接使用常规for语句进行遍历
for循环称为迭代器循环,in后必须是可迭代的对象。
#str
name = 'nick'
for x in name:
print(x) #list
for x in [None, 3, 4.5, "foo", lambda: "moo", object, object()]:
print("{0} ({1})".format(x, type(x))) #dict
d = {
'1': 'tasty',
'2': 'the best',
'3 sprouts': 'evil',
'4': 'pretty good'
} for sKey in d:
print("{0} are {1}".format(sKey, d[sKey])) #file
f = open('32.txt', 'r', encoding='utf-8')
for x in f:
print(x)
f.close()
5、实现迭代器(__next__和__iter__)
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。
- __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
- __next__() 方法会返回下一个迭代器对象。
- StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
创建一个返回数字的迭代器,初始值为 1,逐步递增 1,在 20 次迭代后停止执行:
class MyNumbers:
def __iter__(self):
self.a = 1
return self def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration myclass = MyNumbers()
myiter = iter(myclass) for x in myiter:
print(x)
1、模拟range
class Range:
def __init__(self, n, stop, step):
self.n = n
self.stop = stop
self.step = step def __next__(self):
if self.n >= self.stop:
raise StopIteration
x = self.n
self.n += self.step
return x def __iter__(self):
return self for i in Range(1, 7, 3):
print(i) #1
#4
2、斐波那契数列
class Fib:
def __init__(self):
self._a = 0
self._b = 1 def __iter__(self):
return self def __next__(self):
self._a, self._b = self._b, self._a + self._b
return self._a f1 = Fib()
for i in f1:
if i > 100:
break
print('%s ' % i, end='') # 1 1 2 3 5 8 13 21 34 55 89
二、生成器
1、yield
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
yield后面可以加多个数值(可以是任意类型),但返回的值是元组类型的。
- 提供一种自定义迭代器的方式
- yield可以暂停住函数,并提供当前的返回值
import sys def fibonacci(n): # 函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if counter > n:
return
yield a
a, b = b, a + b
counter += 1 f = fibonacci(10) #f 是一个生成器
print(type(f)) # <class 'generator'> while True:
try:
print(next(f), end=" ")
except StopIteration:
sys.exit()
yield和return:
- 相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制
- 不同点:return只能返回一次值;yield可以返回多次值
2、自定义range()方法
def my_range(start, stop, step=1):
while start < stop:
yield start
start += 1 g = my_range(0, 3)
print(f"list(g): {list(g)}")
复杂版本:
def range(*args, **kwargs):
if not kwargs:
if len(args) == 1:
count = 0
while count < args[0]:
yield count
count += 1
if len(args) == 2:
start, stop = args
while start < stop:
yield start
start += 1
if len(args) == 3:
start, stop, step = args
while start < stop:
yield start
start += step else:
step = 1 if len(args) == 1:
start = args[0]
if len(args) == 2:
start, stop = args for k, v in kwargs.items():
if k not in ['start', 'step', 'stop']:
raise ('参数名错误') if k == 'start':
start = v
elif k == 'stop':
stop = v
elif k == 'step':
step = v while start < stop:
yield start
start += step for i in range(3):
print(i) # 0,1,2 for i in range(99, 101):
print(i) # 99,100 for i in range(1, 10, 3):
print(i) # 1,4,7 for i in range(1, step=2, stop=5):
print(i) # 1,3 for i in range(1, 10, step=2):
print(i) # 1,3,5,7,9
3、生成器表达式(i.for .in)
把列表推导式的[]换成()就是生成器表达式 。
优点:比起列表推导式,可以省内存,一次只产生一个值在内存中
t = (i for i in range(10))
print(t) # <generator object <genexpr> at 0x00000000026907B0>
print(next(t)) # 0
print(next(t)) # 1
举例:
with open('32.txt', 'r', encoding='utf8') as f:
nums = [len(line) for line in f] # 列表推导式相当于直接给你一筐蛋
print(max(nums)) # 2
with open('32.txt', 'r', encoding='utf8') as f:
nums = (len(line) for line in f) # 生成器表达式相当于给你一只老母鸡。
print(max(nums)) # ValueError: I/O operation on closed file.
10、Python迭代器与生成器(iterator、for循环、generator、yield)的更多相关文章
- python—迭代器,生成器与for循环机制
一:什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代器中的下一项,要么就引起一个stoplteration异常,以终止协议(只能往后走不能往前) 2.可迭代对 ...
- 一文搞懂Python迭代器和生成器
很多童鞋搞不懂python迭代器和生成器到底是什么?它们之间又有什么样的关系? 这篇文章就是要用最简单的方式让你理解Python迭代器和生成器! 1.迭代器和迭代过程 维基百科解释道: 在Python ...
- Python - 迭代器与生成器 - 第十三天
Python 迭代器与生成器 迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问 ...
- 怎么理解Python迭代器与生成器?
怎么理解Python迭代器与生成器?在Python中,使用for ... in ... 可以对list.tuple.set和dict数据类型进行迭代,可以把所有数据都过滤出来.如下: ...
- Python 迭代器和生成器(转)
Python 迭代器和生成器 在Python中,很多对象都是可以通过for语句来直接遍历的,例如list.string.dict等等,这些对象都可以被称为可迭代对象.至于说哪些对象是可以被迭代访问的, ...
- python迭代器和生成器(3元运算,列表生成式,生成器表达式,生成器函数)
1.1迭代器 什么是迭代器: 迭代器是一个可以记住遍历的位置对象 迭代器对象从集合的第一个元素元素开始访问,直到所有元素被访问完结束,迭代器只能往前不会后退. 迭代器有两个基本方法:iter ,nex ...
- python迭代器和生成器
迭代器 #可以被netxt()函数调用不断返回一个值的对象成为迭代器:Iterator #迭代器是访问集合元素的一种方式,从集合第一个元素开始(用next()方法)访问就不能回退,便于循环遍历一些较大 ...
- Python迭代器,生成器--精华中的精华
1. 迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一大 ...
- Python—迭代器与生成器
迭代器与生成器 生成器(generator) 先来了解一下列表生成器: list = [i*2 for i in range(10)] print(list)>>>>[0, 2 ...
随机推荐
- mysql语句笔记
创建数据库 create database name(自定义): #创建一个数据库 name自己取 create database if not exists name() default cha ...
- Java的三大版本
Java的三大版本 Write Once.Run Anywhere JavaSE:标准版(桌面程序,控制台开发......) JavaME:嵌入式开发(手机,小家电......) JavaEE:E企业 ...
- 腾讯云直播+点播全线产品支持AV1,带来极致视频体验
日前,腾讯视频云直播.点播.媒体处理全线产品均已支持AV1标准,据悉,腾讯云也是国内首家直播+点播同时支持AV1视频处理业务的公有云厂商. 据悉,AV1(Alliance for Open Media ...
- Java中参数始终是按值传递
Java中参数始终是按值传递. public class Main { public static void main(String[] args) { int x = 5; change(x); S ...
- Dubbo2.7.3入门
2.7.X的Dubbo,包名不再是com.alibaba,而是org.apache 先看工程目录结构 一个公共api模块,一个SpringBoot项目充当Dubbo服务,一个SpringBoot项目充 ...
- Java集合框架(Java总结五)
”https://www.runoob.com/java/” 集合接口区别 List 接口存储一组不唯一,有序(插入顺序)的对象,允许有相同的元素. Set 接口存储一组唯一,无序的对象,不保存重复的 ...
- Linux内核--伙伴系统--页释放
本文转载自:http://www.cnblogs.com/tolimit/ 感觉原博分析的不错,借花献佛. ---------------------------------------------- ...
- C语言环境搭建
UNIX/Linux 上的安装 如果您使用的是 Linux 或 UNIX,请在命令行使用下面的命令来检查您的系统上是否安装了 GCC: $ gcc -v 如果您的计算机上已经安装了 GNU 编译器,则 ...
- c语言 判断字符串长度 实现
/* 首先明白答案的本质(该函数)是一个计数器该计数器用for循环来实现实现对一串字符串的计数字符串以空格开头 不计算空格 计算空格后的数字直到遇到\0结束.num计算器字符串不以空格结束 计算空格后 ...
- Spark之RDD弹性特性
RDD作为弹性分布式数据集,它的弹性具体体现在以下七个方面. 1.自动进行内存和磁盘数据存储的切换 Spark会优先把数据放到内存中,如果内存实在放不下,会放到磁盘里面,不但能计算内存放下的数据,也能 ...