python函数基础 之迭代器和生成器

目录

一、迭代器

1.1、什么是迭代器?

1.2、迭代器的定义

1.3、可迭代对象和迭代器对象

1.4、迭代器的使用

1.5、迭代器的优缺点

二、生成器

2.1、生成器的概念

2.2、生成器的用法


1.1 什么是迭代器

 python中字符串,列表或元组对象等可迭代对象是可以通过索引下标来进行迭代的,但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器

1.2  迭代器的定义

  1. 迭代是python最强大的功能之一,是访问集合元素的一种方式
  2. 迭代器是一个可以记住遍历的位置的对象。(不依赖索引)
  3. 迭代器对象从集合的一个元素开始访问知道所有的元素被访问结束,迭代器只能往前不能后退。

1.3 可迭代对象和迭代器对象

1.3.1可迭代对象

for i in 50:
print(i)

#for i in 50:
#TypeError: 'int' object is not iterable

报错:TypeError: 'int' object is not iterable

类型报错:'int'对象是不可迭代的    

何为迭代?

在Python中,对list、tuple、str等类型的数据可以使用for...in...的循环语法,从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。

在Python的基本数据类型中,列表、元组、字符串、字典都是可迭代的,而整数、浮点数、布尔数都是不可迭代的。

 怎么判断对象是否为可迭代对象?

从上面代码可以简单分析出能被for循环取值的就是可迭代,那么我们就可以初步总结出可迭代的类型:str、list、tuple、set、dict

简单说:内置有__iter__方法的对象,即obj.__iter__ 即为可迭代对象

可以使用 isinstance() 判断一个对象是否是 iterable 对象(见下方代码):

from collections import Iterable

a = list()
b = tuple()
c = dict()
d = "hello world"
e = 1212
f = 3.141592654
print(isinstance(a, Iterable))
print(isinstance(b, Iterable))
print(isinstance(c, Iterable))
print(isinstance(d, Iterable))
print(isinstance(e, Iterable))
print(isinstance(f, Iterable))

结果为:

True
True
True
True
False
False

可迭代对象的本质

可迭代对象的本质就是可以向我们提供一个迭代器来帮助我们对其进行迭代遍历使用,可迭代对象通过 __iteration__(缩写_iner_)提供一个迭代器, 在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的迭代器,然后通过迭代器来获取对象中的每一个元素。

1.3.2  什么是迭代器对象

迭代器是一个实现了迭代器协议的对象:即指的是即内置有__iter__又内置有__next__方法的对象。

 什么是迭代器协议:

1.迭代器协议是指:对象必须提供一个next方法,执行方法要么返回迭代器中的下一项,要么就引起一个StopIteration异常,以终止迭代(只能往后走,不能往前退)
2.可迭代对象:实现了迭代器协议的对象(实现方式:对象内部定义了一个iter()方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,Python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

1.4 迭代器的使用 

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
iter_dic.__iter__() is iter_dic #True

print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
# print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志

#有了迭代器,我们就可以不依赖索引迭代取值了
iter_dic=dic.__iter__()
while 1:
    try:
        k=next(iter_dic)
        print(dic[k])
    except StopIteration:
        break
  

1.4.1 for循环

for循环的循环对象一定要是可迭代对象,但是这不意味着可迭代对象就可以取值,因为for循环的内部机制是:将可迭代对象转换成迭代器,然后利用next进行取值,最后利用异常处理处理StopIteration抛出的异常。也就是说for循环是迭代器的一个种高级应用。

#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
    print(dic[k])

#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环

1.5 迭代器的优缺点

  1. 优点:
    1. 惰性计算,节约内存。 通过调用next()方法每次只从对象中读取一条数据,不会造成内存的过大开销。
    2. 迭代器提供了一个统一的访问序列的接口,不依赖于索引。
  2. 缺点
    1. 无法获取对象长度。(每次只从对象中读取一条数据,不读取完,无法得知对象长度。)
    2. 只能往后取值,不能后退。历史的值用完就销毁,无法调用。

2.1、生成器的概念

利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。

 2.1.1 生成器函数

在函数中如果出现了yield关键字,那么该函数就不再是一个普通函数而是一个生成器函数。

def foo():
	yield 1
	yield 2
	return 
	yield 3
f=foo()
print(next(f))#程序会停留在对应yield后的语句
print(next(f))
print(next(f))#当程序遇到return,return后的语句不会再执行,因此报错。

生成器的特点
生成器是一个函数,而且函数的参数都会保留。迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的。

yield 生成器的运行机制
当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把 yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态开始运行,直至出现yield语句,把参数给你,之后停下。如此反复,直至退出函数。
 

2.2 生成器的用法

'''
使用生成器模仿range的功能

version:01
Author:jasn
Date:2020-01-06

'''
#功能需求
for i in range(1,9,2):
    print(i)
print('========================')

#功能实现
def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start+=step
for i in my_range(1,9,2):
    print(i)
发布了46 篇原创文章 · 获赞 37 · 访问量 4538

猜你喜欢

转载自blog.csdn.net/weixin_42444693/article/details/103865775