day13. 迭代器与高阶函数
一、迭代器
""" 能被next调用,并不断返回下一个值的对象,叫做迭代器(对象) 概念: 迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的, 单纯的重复并不是迭代 特征: 并不依赖索引,而通过next指针迭代所有数据,一次只取一个值,大大节省空间 """
1、可迭代对象
setvar = {"a","b","c","d"} for i in setvar: print(i) # dir 获取当前类型对象中的所有成员 """__iter__ 方法用来判断是否是可迭代性数据""" lst = dir(setvar) print(dir("123")) res = "__iter__" in dir(setvar) print(res)
2、迭代器
""" for 循环能够遍历一切可迭代性数据的原因在于,底层调用了迭代器,通过next方法中的指针实现数据的获取 可迭代对象 -> 迭代器 不能够被next直接调用 -> 可以被next直接调用的过程 如果是一个可迭代对象不一定是迭代器 但如果是一个迭代器就一定是一个可迭代对象 """
2.1、如何来定义一个迭代器
setvar = {"a","b","c","d"} it = iter(setvar) print(it)
2.2、如何来判断一个迭代器
print(dir(it)) res = "__iter__" in dir(it) and "__next__" in dir(it) print(res)
2.3、如何来调用一个迭代器
"""next在调用迭代器中的数据时,是单向不可逆,一条路走到黑的过程"""
res = next(it) print(res) res = next(it) print(res) res = next(it) print(res) res = next(it) print(res) """ # StopIteration 报错 停止迭代 res = next(it) print(res) """
3、重置迭代器
it = iter(setvar) res = next(it) print(res)
4、使用其他方式判断迭代器或者可迭代对象
"""Iterator 迭代器 Iterable 可迭代对象""" # from ... 从哪里 import 引入 ... from collections import Iterator,Iterable # from collections.abc import Iterator,Iterable python3.7 res = isinstance(it,Iterator) print(res) res = isinstance(it,Iterable) print(res)
5、使用其他方式调用迭代器中的数据
# 1. for 循环 print("<=>") for i in it: print(i) # 2. for + next print("<=>") lst = [1,2,3,4,5,6,7,7,8,9,10] it = iter(lst) for i in range(10): res = next(it) print(res) print(next(it)) print(next(it))
6、总结
''' 迭代器: 迭代器(Iterator)可以看做是一个特殊的对象,每次调用该对象是会返回自身的下一个元素,一个迭代器对象必须是定义了__iter__()方法和next()方法的对象 为什么要有迭代器: 序列类型字符串、列表、元组都有下标,用下标访问没问题。但是非序列类型像字典、集合、文件对象就不能用下标,for循环就是基于迭代器协议 提供了一个统一的可以遍历所有对象的方法。即在遍历前,先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问 这样所有的对象都可以通过for循环访问了。循环结束,捕捉异常,循环结束。这种方式不依赖与索引 可迭代对象: 可迭代对象是指内置有__iter__ 方法的对象,即 obj.__iter__ 字符串、元组、列表、字典都可以进行迭代 'kxq'.__iter__ open('kxq.txt'.__iter__) 迭代器对象 可迭代对象执行obj.__iter__()得到的结果就是迭代器对象 迭代器对象指内置有 __iter__ 、 __next__ 方法的对象 迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象 '''
i = [1, 2, 3] iter_l = i.__iter__() # 得到迭代器对象, print(iter_l.__next__()) # 与 next(iter_l)相同 print(iter_l.__next__()) print(iter_l.__next__()) print(iter_l.__next__())# 抛出异常 StopIteration # iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误;
6.1、for 循环原理
i = [1, 2, 3] for x in i: print(x) # 原理 # 1.执行i.__iter__() 方法,得到一个迭代器对象 iter_i # 2.执行 iter_i.__next__()方法,将得到的值赋值给x,进入循环体 # 重复2,捕捉StopIteration异常,循环结束
6.2、优缺点
1 # 缺点: 它的特性决定了它只能往前,不能后退 2 3 # 有点:节省内存,惰性计算,不依赖与索引
二、map函数
""" map(func,Iterable) 功能:处理数据 把Iterable中的数据一个一个拿出来,扔到func函数中做处理 把处理之后的结果放到迭代器当中,最后返回迭代器 参数: func : 自定义函数 或 内置函数 Iterable : 可迭代性数据(容器类型数据 range对象 迭代器) 返回值: 迭代器 """
1、lst = ["1","2","3","4"] 转换为 [1,2,3,4]
lst = ["1","2","3","4"] # 常规写法 lst_new = [] for i in lst: lst_new.append(int(i)) print(lst_new) # map改造 it = map(int,lst) """ # 代码解析: 先把"1" 扔到int当中做处理,将强转后的结果扔到迭代器中 然后把"2" 扔到int当中做处理,将强转后的结果扔到迭代器中 然后把"3" 扔到int当中做处理,将强转后的结果扔到迭代器中 然后把"4" 扔到int当中做处理,将强转后的结果扔到迭代器中 最终返回迭代器 """
1.1、获取迭代器中的数据
# 1.next res = next(it) print(res) res = next(it) print(res) res = next(it) print(res) res = next(it) print(res) # 2.for for i in it: print(i) # 3.for + next for i in range(4): res = next(it) print(res) # 4.list强转 print(list(it))
2、[1,2,3,4] 转换为 [2,8,24,64]
lst = [1,2,3,4] ''' 1 * 2^1 = 2 2 * 2^2 =8 3 * 2^3 =24 4 * 2^4 =64 ''' lst_new = [] for i in lst: res = i << i lst_new.append(res) print(lst_new)
# map改造 '''参数和返回值return一定要写''' def func(n): return n << n lst = [1,2,3,4] it = map(func,lst) print(list(it))
# lambda + map it = map(lambda n : n << n , lst) print(list(it))
3、{"a":97,"b":98,"c":99} 转换为 [97,98,99]
dic = {"a":97,"b":98,"c":99} def func(lst): lst_new = [] # 遍历列表 for i in lst: # 通过键取值 res = dic[i] # 把值追加到新的列表中 lst_new.append(res) # 返回新列表 return lst_new # [97,98,99] res = func(lst = ["a","b","c"]) print(res)
# 将键值对反转 dic = {97:"a",98:"b",99:"c"} dic_new = {} for k,v in dic.items(): dic_new[v] = k print(dic_new) lst = ["a","b","c"] lst_new = [] # 遍历列表 for i in lst: # 通过键取值 res = dic_new[i] # 把值追加到新的列表中 lst_new.append(res) # 返回新列表 print(lst_new)
# map改造 def func(n): # 原字典 dic = {97:"a",98:"b",99:"c"} # 新字典 dic_new = {} # 遍历原字典 for k,v in dic.items(): # 更换键值对 dic_new[v] = k print(dic_new) # {'a': 97, 'b': 98, 'c': 99} # 通过键来获取值 return dic_new[n] lst = ["a","b","c"] it = map(func,lst) print(list(it))
三、filter函数
""" filter(func,iterable) 功能: 过滤数据 return True 当前这个数据保留 return False 当前这个数据舍弃 参数: func : 自定义函数 iterable : 可迭代型数据(容器类型数据,range对象,迭代器) 返回值: 迭代器 """
lst = [1,2,3,4,5,6,7,8,9,10] # 常规写法 lst_new = [] for i in lst: if i % 2 == 0: lst_new.append(i) print(lst_new)
# filter改写 def func(i): if i % 2 == 0: return True else: return False it = filter(func,lst)
# (1) next res = next(it) print(res) # (2) for print("<====>") for i in it: print(i) # (3) for + next it = filter(func,lst) for i in range(3): res = next(it) print(res) # (4) list强转 res = list(it) print(res)
# filter + lambda 改写 it = filter(lambda i : True if i % 2 == 0 else False , lst ) print(list(it))
四、reduce函数
""" reduce(func,iterable) 功能:计算数据 先把iterable中的前两个值拿出来,扔到func当中做运算, 把计算的结果和iterable中的第三个元素在扔到func当中做运算, 再把结果算出来,和第四个元素做运算,以此类推 直到所有结果运算完毕.返回该结果 参数: func : 自定义函数 iterable : 可迭代型数据(容器类型数据,range对象,迭代器) 返回值: 计算之后的结果 """
1、lst = [5,4,8,8] 转换 整型5488
# 常规写法 # 方法一 strvar = "" for i in lst: strvar += str(i) print(strvar , type(strvar)) res = int(strvar) print(res , type(res))
from functools import reduce from collections import Iterator,Iterable lst = [5,4,8,8] it = iter(lst) print(isinstance(it , Iterator)) print(isinstance(it , Iterable)) num1 = next(it) num2 = next(it) print(num1,num2) num = num1 * 10 + num2 print(num) # 54 for i in it: num = num * 10 + i # 54 * 10 + 8 => 548 print(num, type(num))
# reduce 改造 def func(x,y): return x*10 + y lst = [5,4,8,8] res = reduce(func,lst) print(res , type(res))
""" # 代码解析: 先拿出5和4两个元素,扔到func当中做运算,结果是54 在拿54和8两个元素,扔到func当中做运算,结果548 在拿548和8两个元素,扔到func当中做运算,结果5488 返回最终的结果: 5488 程序结束 """
# 使用reduce + lambda改造 res = reduce(lambda x,y:x*10+y,lst) print(res)
2、"789" => 789 禁止使用int强转
# "789" -> 数字7 数字8 数字9 def func1(x,y): return x*10 + y def func2(n): dic = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9} return dic[n] it = map(func2,"789") # [7,8,9] res = reduce(func1,it) print(res,type(res))
五、sorted函数
""" sorted(iterable,key=函数,reverse=False) 功能:排序 参数: iterable:可迭代型数据(容器类型数据,range对象,迭代器) key :指定自定义函数或内置函数 reverse :代表升序或者降序 , 默认是升序(从小到大排序) reverse=False 返回值: 排序后的结果 """
# 1.默认是从小到大排序 lst = [1,2,3,4,5,-90,-4,-1,100] res = sorted(lst) print(res) # 2.reverse 从大到小排序 res = sorted(lst,reverse=True) print(res) # 3.指定函数进行排序 # 按照绝对值排序 abs lst = [-10,-1,3,5] res = sorted(lst,key=abs) """ -1 => abs(-1) => 1 3 => abs(3) => 3 5 => abs(5) => 5 -10 => abs(-10) => 10 [-1, 3, 5, -10] """ print(res)
1、使用自定义函数进行排序
lst = [19,21,38,43,55] def func(n): return n % 10 lst = sorted(lst,key=func) print(lst) """ 21 => n % 10 => 1 43 => n % 10 => 3 55 => n % 10 => 5 38 => n % 10 => 8 19 => n % 10 => 9 21 43 55 38 19 """
2、可迭代类型数据排序
# 字符串 container = "eadc" # 列表 container = [19,21,38,43,55] # 元组 container = (19,21,38,43,55) # 集合 container = {19,21,38,43,55} # 字典 (排序的是字典的键) container = {"c":3,"a":1,"b":2} container = {"aa":3,"bb":2} print("<===>") res = sorted(container) print(res)
3、sorted 和 sort 之间的区别
# (1) sorted可以排序一切容器类型数据, sort只能排列表 # (2) sorted返回的是新列表,sort是基于原有的列表进行修改 # (3) 推荐使用sorted
六、练习
""" # 1.用map来处理字符串列表,把列表中所有人都变成 leader ,比方alex_leader name = ['oldboy', 'alex', 'wusir'] # 2.用map来处理下述 listvar ,要求得到新列表,每个元素名字加后面加_leader listvar = [{'name':'alex'},{'name':'wusir'}] # 3.用filter来处理,得到股票价格大于20的股票名字 shares={ 'IBM':36.6, 'Lenovo':23.2, 'oldboy':21.2, 'ocean':10.2, } # 4.有下面字典: portfolio=[ {'name':'IBM','shares':100,'price':91.1}, {'name':'AAPL','shares':20,'price':54.0}, {'name':'FB','shares':200,'price':21.09}, {'name':'HPQ','shares':35,'price':31.75}, {'name':'YHOO','shares':45,'price':16.35}, {'name':'ACME','shares':75,'price':115.65} ] # a.获取购买每只股票的总价格(乘积),迭代器中[9110.0, 1080.0 ,......] # b.用filter过滤出price大于100的股票。 # 5.将listvar 按照列表中的每个字典的values大小进行排序,形成一个新的列表。 listvar = [ {'sales_volumn': 0}, {'sales_volumn': 108}, {'sales_volumn': 337}, {'sales_volumn': 475}, {'sales_volumn': 396}, {'sales_volumn': 172}, {'sales_volumn': 9}, {'sales_volumn': 58}, {'sales_volumn': 272}, {'sales_volumn': 456}, {'sales_volumn': 440}, {'sales_volumn': 239} ] """
def func(n): return n+"_leader" name = ['oldboy', 'alex', 'wusir'] it = map(func,name) print(list(it)) # lambda it = map(lambda n : n+"_leader",name) print(list(it))
def func(n): print(n) # {'name': 'alex'} return n["name"] + "_leader" listvar = [{'name':'alex'},{'name':'wusir'}] it = map(func,listvar) print(list(it)) # lambda it = map(lambda n : n["name"] + "_leader" , listvar) print(list(it))
shares={ 'IBM':36.6, 'Lenovo':23.2, 'oldboy':21.2, 'ocean':10.2, } def func(n): return shares[n] > 20 it = filter(func,shares) print(list(it)) # lambda it = filter(lambda n : shares[n] > 20 , shares) print(list(it))
portfolio=[ {'name':'IBM','shares':100,'price':91.1}, {'name':'AAPL','shares':20,'price':54.0}, {'name':'FB','shares':200,'price':21.09}, {'name':'HPQ','shares':35,'price':31.75}, {'name':'YHOO','shares':45,'price':16.35}, {'name':'ACME','shares':75,'price':115.65} ] # a.获取购买每只股票的总价格(乘积),迭代器中[9110.0, 1080.0 ,......] def func(n): return n["shares"] * n["price"] it = map(func,portfolio) print("<====>") print(list(it))
portfolio=[ {'name':'IBM','shares':100,'price':91.1}, {'name':'AAPL','shares':20,'price':54.0}, {'name':'FB','shares':200,'price':21.09}, {'name':'HPQ','shares':35,'price':31.75}, {'name':'YHOO','shares':45,'price':16.35}, {'name':'ACME','shares':75,'price':115.65} ] # b.用filter过滤出price大于100的股票 def func(n): return n["price"] > 100 it = filter(func,portfolio) print(list(it))
# 5.将listvar 按照列表中的每个字典的values大小进行排序,形成一个新的列表。 listvar = [ {'sales_volumn': 0}, {'sales_volumn': 108}, {'sales_volumn': 337}, {'sales_volumn': 475}, {'sales_volumn': 396}, {'sales_volumn': 172}, {'sales_volumn': 9}, {'sales_volumn': 58}, {'sales_volumn': 272}, {'sales_volumn': 456}, {'sales_volumn': 440}, {'sales_volumn': 239} ] def func(n): return n["sales_volumn"] print("<===>") lst = sorted(listvar,key=func) print(lst)