【python核心】生成器(面试题常考)
文章目录
- 生成器generator
-
- 定义
- 生成器函数
-
- 定义
- 练习
- 内置生成器
- 练习
- 生成器表达式
-
- 定义
- 练习
- 总结
生成器generator
定义
作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。
以上作用也称之为延迟操作或惰性操作,通俗的讲就是在需要的时候才计算结果,从而不是一次构建出所有结果。
""" yield --> 生成器 生成器 = 可迭代对象 + 迭代器 简述生成器与迭代器的区别(面试题常考)"""#生成器的原理class MyGenerator: """ 生成器 = 可迭代对象 + 迭代器 """ def __init__(self,stop_value): self.begin = 0 self.stop_value = stop_value def __iter__(self): return self def __next__(self): if self.begin >= self.stop_value: raise StopIteration temp = self.begin self.begin += 1 return tempdef my_range(stop_value): number = 0 while number < stop_value: yield number number += 1my01 = my_range(5)print(type(my01),dir(my01))print(id(my01.__iter__()),id(my01))for item in my01: print(item)
生成器函数
定义
含有yield语句的函数,返回值为生成器对象。
练习
从列表[4,5,566,7,8,10]中选出所有偶数。
方法1:结果存入另外一个列表中
方法2:使用生成器实现
方法一:list01 = [4,5,566,7,8,10]result = []for item in list01: if item % 2 == 0: result.append(item)print(result)方法二:list01 = [4,5,566,7,8,10]def get_even(): for item in list01: if item %2 ==0: yield itemmy01 = get_even()for item in my01: print(item)
内置生成器
- 枚举函数enumerate
作用:遍历可迭代对象时,可以将索引与元素组合为一个元组。 - zip
作用:将多个可迭代对象中对应的元素组合成一个个元组。
练习
练习1:定义生成器函数my_enumerate,实现下列现象,将元素与索引合成一个元组。
""" 练习"""# #原理# list01 = [ 3,4,55,6,7]# for item in enumerate(list01):# #(索引,元素)# print(item)## #实际开发写的# for index,element in enumerate(list01):# print(index, element)def my_enumerate(iterable_target): #方法1: index = 0 for item in iterable_target: yield (index,item) index += 1 # 方法2: # for index in range(len(iterable_target)): # yield (index,iterable_target[index])list01 = [3,4,55,6,7]for index,element in my_enumerate(list01): print(index, element)
练习2:定义生成器函数my_zip,实现下列现象。将多个列表的每个元素合成一个元组。【暂不考虑长度不相等的情况。】
# list02 =["孙悟空","猪八戒","唐僧","沙僧"]# list03 =[ 101,102,103,104]# for item in zip(list02,list03):# print(item)# def my_zip(iterable_target01,iterable_target02):# for i in range(len(iterable_target01)):# yield (iterable_target01[i],iterable_target02[i])# # list02 =["孙悟空","猪八戒","唐僧","沙僧"]# list03 =[ 101,102,103,104]# for item in my_zip(list02,list03):# print(item)def my_zip(*args): #根据星号元组形参args第一个参数的长度生成索引(len(args[0]) for i in range(len(args[0])): list_result = [] for item in args: list_result.append(item[i]) yield tuple(list_result)list02 =["孙悟空","猪八戒","唐僧","沙僧"]list03 =[ 101,102,103,104]for item in my_zip(list02,list03): print(item)
生成器表达式
定义
用推导式形式创建生成器对象。
""" 生成器表达式"""list01 = [3, "54", True,6, "76",1.6,False,3.5]def find01(): for item in list01: if type(item) == int: yield itemre = find01()for item in re: print(item)#生成器表达式#此时没有计算,更没有结果re = (item for item in list01 if type(item) == int)#不做#一次循环,一次计算,一个结果for item in re: print(item)#列表推导式#此时已经完成所有计算,得到所有结果。re = [item for item in list01 if type(item) == int]#一次性做完#只是获取所有结果for item in re: print(item)#总结#变量= [itme for item in 可迭代对象 if 条件] 列表推导#变量= {k,v for k,v in可迭代对象 if 条件} 字典推导#变量= item for item in 可迭代对象 if 条件 } 集合推导#变量= (item for item in 可迭代对象if 条件) 生成器表达
练习
练习1:获取列表中所有字符串。
要求:使用生成器函数/生成器表达式/列表推导式完成。
list01 = [3, "54", True,6, "76",1.6,False,3.5]def find02(): for item in list01: if type(item) == str: yield itemre = find02()for item in re: print(item)re = (item for item in list01 if type(item) == str)for item in re: print(item)re = [item for item in list01 if type(item) == str]for item in re: print(item)
练习2:获取列表中所有小数。
要求:使用生成器函数/生成器表达式/列表推导式完成。
list01 = [3, "54", True,6, "76",1.6,False,3.5]def find03(): for item in list01: if type(item) == float: yield itemfor item in find03(): print(item)for item in (item for item in list01 if type(item) == float): print(item)for item in [item for item in list01 if type(item) == float]: print(item)
练习3:
class SkillData: def __init__(self,id,name,atk_ratio,duration): """ 技能信息 :param id:技能编号 :param name:技能名称 :param atk_ratio: 攻击比例 :param duration: 持续时间 """ self.id = id self.name = name self.atk_ratio = atk_ratio self.duraftion = durationlist_skill = [ SkillData(101, "乾坤大挪移",5, 10), SkillData(102, "降龙十八掌", 8, 5), SkillData(103, "葵花宝典",10,2),]
要求如下:
(1) 获取攻击比例大于6的所有技能。
(2)获取持续时间在4–11之间的所有技能。
(3)获取技能编号是102的技能。
(4)获取技能名称大于4个字并且持续时间小于6的所有技能。
要求:使用生成器函数/生成器表达式完成。
class SkillData: def __init__(self,id,name,atk_ratio,duration): """ 技能信息 :param id:技能编号 :param name:技能名称 :param atk_ratio: 攻击比例 :param duration: 持续时间 """ self.id = id self.name = name self.atk_ratio = atk_ratio self.duraftion = duration def __str__(self): return "技能数据是:%d,%s,%d,%d"%(self.id,self.name,self.atk_ratio,self.duraftion)list_skill = [ SkillData(101, "乾坤大挪移",5, 10), SkillData(102, "降龙十八掌", 8, 5), SkillData(103, "葵花宝典",10,2),]print("----------------1-------------------")def find01(): for item in list_skill: if item.atk_ratio > 6 : yield itemfor item in find01(): print(item)print("----------------1-------------------")for item in (item for item in list_skill if item.atk_ratio > 6 ): print(item)print("----------------2-------------------")def find02(): for item in list_skill: if 4 < item.duraftion < 11: yield itemfor item in find02(): print(item)print("----------------2-------------------")for item in (item for item in list_skill if 4 < item.duraftion < 11 ): print(item)print("----------------3-------------------")def find03(): for item in list_skill: if item.id == 102: return item #编号唯一,返回一个用returnre = find03()print(re)print("----------------4-------------------")def find04(): for item in list_skill: if len(item.name)> 4 and item.duraftion <6 : yield itemfor item in find04(): print(item)print("----------------4-------------------")#不建议使用生成器表达式# for item in (item for item in list_skill if len(item.name)> 4 and item.duraftion <6 ):# print(item)
总结
迭代可迭代对象:具有__iter__迭代器生成器class 可迭代对象:def __iter__()创建迭代器对象class 迭代器:def __next__()返回一个元素如果没有元素,则抛出一个StopIteration异常。for 变量 in 可迭代对象:变量得到的就是__next__方法返回值原理:iterator = 可迭代器对象.__iter__()while True:try:变量 = iterator.__next__()except:break启发:调用next,执行一次,计算一次,返回一次。生成器函数:def 函数名():...yield 数据...#调用方法不执行生成器 = 函数名()#for 生成器 才执行函数体for item in 生成器:...优势:延迟/惰性操作生成器源码:class 生成器:def __iter__():return selfdef __next__():定义着yield以前的代码返回yield后面的数据生成器与迭代器渊源:生成器通过yield标记变成迭代代码,for循环调用__next__,而__next__内部定义着yield以前的代码,返回yield后面的数据,__next__就是做迭代器工作。...