迭代器

一 迭代器介绍

# 迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动,其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代
while True:
    msg = input('>>: ').strip()
    print(msg)
# 下述while循环才是一个迭代过程,不仅满足重复,而且以每次重新赋值后的index值作为下一次循环中新的索引进行取值,反复迭代,最终可以取尽列表中的值
goods=['mac','lenovo','acer','dell','sony']
 
index=0
while index < len(goods):
    print(goods[index])
    index+=1

1.1 可迭代对象

# 通过索引的方式进行迭代取值,实现简单,但仅适用于序列类型:字符串,列表,元组。对于没有索引的字典、集合等非序列类型,必须找到一种不依赖索引来进行迭代取值的方式,这就用到了迭代器。

# 要想了解迭代器为何物,必须事先搞清楚一个很重要的概念:可迭代对象(Iterable)。从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象:
{'name':'egon'}.__iter__
{7,8,9}.__iter__
……

1.2 迭代器对象

# 调用obj.iter()方法返回的结果就是一个迭代器对象(Iterator)。迭代器对象是内置有iter和next方法的对象,打开的文件本身就是一个迭代器对象,执行迭代器对象.iter()方法得到的仍然是迭代器本身,而执行迭代器.next()方法就会计算出迭代器中的下一个值。 迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值
>>> s={1,2,3} # 可迭代对象s
>>> i=iter(s)  # 本质就是在调用s.__iter__(),返回s的迭代器对象i,
>>> next(i) # 本质就是在调用i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)  #抛出StopIteration的异常,代表无值可取,迭代结束

二 for循环原理

# 有了迭代器后,我们便可以不依赖索引迭代取值了,使用while循环的实现方式如下
goods=['mac','lenovo','acer','dell','sony']
i=iter(goods) #每次都需要重新获取一个迭代器对象
while True:
    try:
        print(next(i))
    except StopIteration: #捕捉异常终止循环
        break
# for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为
goods=['mac','lenovo','acer','dell','sony']
for item in goods:   
    print(item)
# for 循环在工作时,首先会调用可迭代对象goods内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给item,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代。

三 迭代器的优缺点

# 基于索引的迭代取值,所有迭代的状态都保存在了索引中,而基于迭代器实现迭代的方式不再需要索引,所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:

3.1 优点:

# 1、为序列和非序列类型提供了一种统一的迭代取值方式。
# 2、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。

3.2 缺点:

# 1、除非取尽,否则无法获取迭代器的长度
# 2、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。

今日内容概要

  • 配合匿名函数使用的方法
  • 可迭代对象
  • 迭代器对象
  • for循环内部原理
  • 异常捕获
  • 生成器

今日内容详细

配合匿名函数使用的方法

1. map(函数名, 要遍历的数据)  # 内部本质就是for循环,再记住两个参数的位置和作用
# 2. zip 拉链
l = [11, 22, 33, 44, 55, 66]
ll1 = ['name', 'age', 'hobby', 'aaa', 'b', 'ccc', 'ddd', 'fff']
ll2 = ['nam2e', 'age1', 'hobby1', 'aaa1', 'b', 'ccc', 'ddd', 'fff']
ll3 = ['name1', 'age2', 'hobby2', 'aaa2', ]

# d1 = {'username': 'tony'}
# d2 = {'username1': 'kevin'}
# [(11,'name'), (22, 'age'), (33, 'hobby')]

# lst = []
# for i in range(len(l)):
#     lst.append((l[i], ll1[i]))
# print(lst)

res = zip(l, ll1, ll2, ll3)  # <zip object at 0x000001646C22FE00> [(11, 'name'), (22, 'age'), (33, 'hobby')]
print(list(res))


# 3. max
# l = [1, 2, 10, 30, 5, 6, 7, 8]
# 求出列表中最大值
# print(max(l))

# 求出最小值
# print(min(l))

#
d = {
    'Aevin': 10000,
    'zack': 2000,
    'zony': 30000,
    'Fank': 5000000000
}
'''
    A-Z:65-90
    a:97
'''
'''如果是字典,比较的是key,说白了就是你暴露什么,就按照什么比较'''
def index(key):
    return d[key]
'''如果传了key参数,就是返回什么值就按照什么值比较'''
print(max(d, key=index))
print(max(d, key=lambda key:d[key]))

print(min(d, key=index))
print(min(d, key=lambda key:d[key]))

# 4. 过滤
l = [1, 10, 20, 55, 66, 77]
# ll = []
# for i in l:
#     if i > 20:
#         ll.append(i)
# print(ll)

def index(x):
    return x > 20
# res=filter(index, l)
res=filter(lambda x:x>20, l)
print(list(res))  # [55, 66, 77]

可迭代对象

# 什么是迭代
	迭代就是每一次的结果必须依赖于上一次的结果
v1.0  v2.0   v3.0

# 可迭代对象
	内置有__iter__方法的对象都是可迭代对象
    '''内置的意思是python自带的,解释器中已经存在的,我们可以直接使用的'''
# 目前我所学的数据类型中,有哪些是可迭代对象, 都支持for循环
	str, list, dict, tuple, set, 文件对象
 print(c)
print(c.__iter__())  # <str_iterator object at 0x0000017E0C21C610>
print(iter(c))  # <str_iterator object at 0x000001B18D4DC610>
# print(c.__len__())  # 5
# print(len(c))

'''一般双下滑先开头的方法都有一个简便的写法,就是函数名()'''

迭代器对象

# 什么是迭代器对象
	既有__iter__方法, 也含有__next__方法

'''文件对象即是可迭代对象又是迭代器对象'''

# 如果生成迭代器对象
	可迭代对象调用__iter__方法

注意:
	迭代给我们提供了一种不依赖索引取值的方法
    
 # 练习题:hello
res=c.__iter__()
res.__next__()
res.__next__()
res.__next__()
res.__next__()

print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())
print(c.__iter__().__next__())

for循环内部原理

l = [1, 2, 3, 4, 5, 6, 7]
# 要求:循环打印出列表中每个元素,但是,不能使用for循环,__next__ next()

# 1. 可迭代对象要转为迭代器
# res = l.__iter__()
# 
# while True:
#     print(res.__next__())

# for i in l:
#     print(i)

'''for循环内部其实也报错了,只不过错误没让我们看见,内部处理了'''

"""
	for循环内部执行流程:
		1. 把关键字in后面的数据类型转为了迭代器 __iter__
		2. 循环next取值
		3. next取值完毕之后也报错了,自动处理错误并且结束while循环
"""

捕捉异常

1. 什么是异常?
	# 异常就是错误发生的信号,如果此信号不做处理,那么,从本行开始之后的代码都不能正常执行了
2. 异常
	2.1 Traceback
    2.2 XXXError
    	# 错误的类型
    2.3   XXXError冒号后面的内容,报错的详细原因,我们主要看的也是这部分,大致定位错误的原因 
3. 异常的种类
	1. 语法错误
    	# 是坚决不允许的,遇到之后要立刻改正,否则,代码不能运行
    2. 逻辑错误
    	# 是可以被允许的,但是,我们写逻辑的时候要尽可能的避免逻辑错误的发生
        
4. 常见的错误类型
	NameError
    IndexError
    KeyError
    ValueError
    ZeroDivisionError
    ...
5. 如何捕捉异常
	try:
      	被监测的代码
    except 错误的类型1 as e:
        错误处理,e:错误的原因
    except 错误的类型2 as e:
        错误处理,e:错误的原因
    except 错误的类型3 as e:
        错误处理,e:错误的原因
    except 错误的类型4 as e:
        错误处理,e:错误的原因
        
 '''万能异常'''
try:
    # print(username)
    # print(1/ 0)
    # l = [1,2,3,4]
    # print(l[6])
    d = {'a':1, 'b':2}
    print(d['c'])  #KeyError
except ZeroDivisionError as e:
    print('')
except NameError as e:
    print(123)
except IndexError as e:
    print(123)
except Exception as e:
    print(e) # name 'username' is not defined
    
    
    
"""
	try except异常捕捉需要注意
    	1. try里面被监测的代码尽量少
    	2. 在明显没有错误的代码不要被捕捉
"""
posted @ 2023-05-16 19:22  秋洛尘  阅读(26)  评论(0)    收藏  举报