【python基础语法六】迭代器,生成器,推导式和高阶函数

迭代器

"""
迭代器:
	能被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator  迭代器是对象)
概念:
	迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,
	单纯的重复并不是迭代  
特征:
	并不依赖索引,而通过next指针(内存地址寻址)迭代所有数据,一次只取一个值,
	而不是一股脑的把所有数据放进内存.大大节省空间,
"""

一.可迭代对象

内置函数: dir 获取当前对象的内置成员

setvar = {"王同培","马春配","赵万里","赵沈阳"}
# 获取当前对象的内置成员
lst = dir(setvar)
print(lst)
# 判断是否是可迭代对象
res = "__iter__" in lst
print(res) # True
for i in setvar:
	print(i)

二.迭代器

"""
for循环之所以可以遍历所有的数据,是因为底层使用了迭代器,通过地址寻址的方式,一个一个的找数据;
可迭代对象 -> 迭代器  实际上就是从不能够被next直接调用 -> 可以被next指针直接调用的过程

如果是可迭代对象 -> 不一定是迭代器
如果是迭代器     -> 一定是可迭代对象
"""

1.如何创建一个迭代器

setvar = {"王同培","马春配","赵万里","赵沈阳"}
it = iter(setvar)
print(it) # <set_iterator object at 0x00>

2.如何判断一个迭代器

print(dir(it))
res = "__iter__" in dir(it)  and "__next__" in dir(it)
print(res) # True

3.如何调用一个迭代器

"""next是单向不可逆的过程,一条路走到黑"""
res = next(it)
print(res) # 赵沈阳 (无序的)
res = next(it)
print(res)
res = next(it)
print(res)
res = next(it)
print(res)
# res = next(it) # 报错 StopIteration
# print(res) 

4.重置迭代器

it = iter(setvar) # 需要重新获取迭代器
print(  it.__next__()  ) # 可以使用迭代器的魔法方法
print(  it.__next__()  )
print(  it.__next__()  )
print(  it.__next__()  )

5.调用迭代器的其他方法

# 1 for调用
it = iter(setvar)
for i in  it:
	print(i)

# 2 for + next
it = iter(setvar)
for i in range(2):
	print( next(it) )

print( next(it) ) # 第三个元素
print( next(it) )
# print( next(it) ) # error  超出了寻址范围

6.判断 迭代器Iterator/可迭代对象Iterable 的其他方法

# 从...模块 引入...内容
from collections import Iterator, Iterable
"""Iterator 迭代器  Iterable 可迭代的对象"""
res = isinstance(it,Iterator)
print(res)
res = isinstance(it,Iterable)
print(res)
# 迭代器一定是可迭代对象;可迭代对象不一定是迭代器

7. range()返回值是迭代器么?

print(isinstance(range(10),Iterator)) # False
print(isinstance(range(10),Iterable)) # True

# 变成迭代器
it = range(10).__iter__()
print(isinstance(it,Iterator)) # True
print(isinstance(it,Iterable)) # True

# 调用it
# next
res = next(it)
print(res)
res = next(it)
print(res)

# for
for i in it:
	print(i)

高阶函数

高阶函数 : 能够把函数当成参数传递的就是高阶函数 (map ,filter ,reduce , sorted)

1. map

"""
map(func,iterable)
功能: 处理数据
	把iterable中的数据一个一个拿出来,扔到func做处理,通过调用迭代器来获取返回值
参数:
	func : 函数(内置函数,自定义函数)
	iterable : 可迭代性对象 (容器类型数据,range对象,迭代器)
返回值:
	迭代器
"""

# (1) 把列表中的元素都变成整型
lst = ["1","2","3","4"]
lst_new = []
for i in lst:
	lst_new.append(int(i))
print(lst_new)

# 用map改写
from collections import Iterator,Iterable
it = map(int,lst) # map 返回迭代器
print(isinstance(it,Iterator))
"""
代码解析:
	第一次调用迭代器
		先把列表中的第一个元素"1"拿出来扔到int中做强转,变成整型1返回出来
	第二次调用迭代器
		先把列表中的第一个元素"2"拿出来扔到int中做强转,变成整型2返回出来
	第三次调用迭代器
		先把列表中的第一个元素"3"拿出来扔到int中做强转,变成整型3返回出来
	第四次调用迭代器
		先把列表中的第一个元素"4"拿出来扔到int中做强转,变成整型4返回出来
"""
# 1.调用迭代器 next
print(next(it))
print(next(it))
print(next(it))
print(next(it))
# print(next(it)) # error

# 2.调用迭代器 for
print("<======>")
it = map(int,lst)
for i in it:
	print(i)
	
# 3.调用迭代器 for + next
print("<======>")
it = map(int,lst)
for i in range(3):
	print(next(it))
	
# 4.强转迭代器 => 列表 (常用)
it = map(int,lst)
print(list(it))
# (2) [1,2,3,4] => [2,8,24,64]
# print(1 * 2 ** 1)  <=> 1 << 1
# print(2 * 2 ** 2)  <=> 2 << 2
lst = [1,2,3,4]
lst_new = []
for i in lst:
	lst_new.append(i << i)
print(lst_new)
	
# map改写
def func(n):
	print(1111)
	return n << n
	
it = map(func,lst) # 只调用map函数时,func函数不会被调用
print(list(it))
"""
强调:
	只有在调用迭代器的时候,才会真正触发map函数中的所有内容;不调用不触发;
	强转迭代器时,把可以调用的所有数据都放到列表中
注意点: 形参和返回值必须写;
"""
# (3) 已知一个字典,给你一个列表["a","b","c"] => [97,98,99]
# 字典的键值翻转操作
dic = {97:"a",98:"b",99:"c"}
dic_new = {}
for k,v in dic.items():
	# print(k,v) # 97 a | 98 b | 99 c
	dic_new[v] = k # dic_new["a"] = 97
print(dic_new)

lst = ["a","b","c"]
lst_new = []
for i in lst:
	lst_new.append(dic_new[i])
print(lst_new)

# map改写
print("<========================>")
lst = ["a","b","c"]
lst = ["c","b","a"]
lst = ("c","b","a")
# func 实现字典的翻转,通过给与a,b,c三个键,得到对应的ascii码,通过list强转得到列表
def func(n):
	print(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]

		
it = map(func,lst)
print(list(it))

2. reduce

"""
reduce(func,iterable)
功能: 计算数据
	把iterable中的前两个数据扔到func函数中做计算,把计算的结果和iterable中第三个值在继续扔到func中做计算
	以此类推 ... 
	最后返回计算的结果 
参数: 
	func: 自定义函数
	iterable : 可迭代对象 (容器类型数据 range对象 迭代器)
返回值:
	计算的结果
"""

案例:

# (1) [7,7,5,8] => 7758
lst = [7,7,5,8]
# 方法一
strvar = ""
for i in lst:
	strvar += str(i)
res = int(strvar)
print(res , type(res))

# 方法二
"""
7 * 10 + 7 = 77
77 * 10 + 5 = 775
775 * 10 + 8 = 7758
"""
# 1.先变成迭代器
it = iter(lst)
# 2.取出两个值
num1 = next(it)
num2 = next(it)
print(num1,num2)
# 做计算
total = num1 * 10 + num2
print(total) # 77
# 3.把计算的结果在和剩下的数据做计算
for num in it:
	total = total * 10 + num
# 4.返回最后的结果
print(total , type(total))

# reduce改写
'''从...functools模块, 引入 .. reduce方法'''
from functools import reduce
lst = [7,7,5,8]
def func(x,y):
	# print(x,y)
	return x * 10 + y
res = reduce(func,lst)
print(res)

# 使用lambda 进行改造
print(reduce(lambda x,y: x*10 + y,lst))
# (2) "123" => 123 不使用int的情况下实现该操作;
strvar = "123"
def func(x,y):
	return x * 10 + y # 字符串的拼接

# 把字符串"123" 处理成数字的123
def func2(n):
	# dic = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}
	dic = {}
	for i in range(10):
		dic[str(i)] = i	
	return dic[n]

it = map(func2,strvar)
# res = reduce(func,it)
# print(res,type(res))
# 简写
print(reduce(lambda x,y: x*10 + y,it))

3. filter

"""
filter(func,iterable)
功能: 过滤数据
	在自定义的函数中,
		如果返回True, 该数据保留
		如果返回False,该数据舍弃				
参数:
	func: 自定义函数
	iterable : 可迭代对象 (容器类型数据 range对象 迭代器)
返回值:
	迭代器
"""
# 1.只要列表中所有的偶数
lst = [1,2,34,5,65,6,56,7,56,756,7567,11]
lst_new = []
for i in lst:
	if i % 2 == 0 :
		lst_new.append(i)
print(lst_new)

# filter改写
def func(n):
	if n % 2 == 0:
		return True
	else:
		return False
it = filter(func,lst)
print(list(it))

# 使用lambda 改写
it = filter(lambda n :True if n % 2 == 0 else False , lst)
print(list(it))
print(list(filter(lambda n :True if n % 2 == 0 else False , lst)))

4. sorted

"""
sorted(iterable, *, key=函数, reverse=False)
功能:排序数据
参数:
	iterable : 可迭代对象 (容器类型数据 range对象 迭代器)
	key      : 指定函数(自定义/内置)
	reverse  : 是否倒序
返回值:
	列表
"""
# 1.从小到大
tup = (-90,89,78,3)
res = sorted(tup)
print(res,type(res)) # list

# 2.从大到小
res = sorted(tup,reverse = True)
print(res,type(res))

# 3.按照绝对值进行排序
tup = (-90,-100,1,2)
res = sorted(tup,key=abs)
print(res)
"""
1 => abs(1) => 1
2 => abs(2) => 2
-90 => abs(-90) => 90
-100 => abs(-100) => 100
"""

# 4.按照自定义函数进行排序
tup = (19,23,42,87)
"""
42 % 10 2 => 42
23 % 10 3 => 23
87 % 10 7 => 87
19 % 10 9 => 19
"""
def func(n):
	print(n)
	return n % 10
lst = sorted(tup,key = func) # 必须要用key指定
print(lst)

# 5.任意的容器类型数据都可以通过sorted排序
container = "abc"
container = [1,2,3]
container = (1,2,3)
container = {"你好","王一","你真帅"}
container = {"caixukun","xiaozhan","zhaoshenyang","wangyibo"}
container = {"ww":"英俊帅气","zxy":"猥琐抠脚","zwl":"斯文败类"} # 排的是字典的键
print(sorted(container))

"""
# 总结:
sorted (推荐使用sorted)
	(1) 可以排序所有的容器类型数据
	(2) 返回一个新的列表
sort
	(1) 只能排序列表
	(2) 基于原来的列表进行排序
"""

推导式(comprehensions)

"""
推导式 : 通过一行循环判断遍历出一些列数据的方法叫做推导式
通过一行循环判断,遍历出一系列数据的方式是推导式
语法: val for val in Iterable (把想要的值写在 for的左侧)
里面是一行循环判断!根据套在推导式外层的符号判断具体是什么类型的推导式

推导式种类三种:
    [val for val in Iterable]  列表推导式
    {val for val in Iterable}  集合推导式
    {a:b for a,b in iterable}  字典推导式
"""

1.推导式基本语法

lst = []
for i in range(1,51):
    lst.append(i)
print(lst)

# 改写推导式
lst = [  i for i in range(1,51)  ]
print(lst)

# 小练习
# 1.[1,2,3,4,5] => [2,4,6,8,10]
lst = [ i*2 for i in range(1,6) ]
print(lst)

2.带有判断条件的推导式

"""注意点:for后面紧跟的判断条件只能是 单项分支 ."""
"""[1,2,3,4,5,6,7,8,9,10] => [1,3,5,7,9 ... ]"""
lst = [1,2,3,4,5,6,7,8,9,10]
lst_new = []
for i in lst:
    if i % 2 == 1:
        lst_new.append(i)
print(lst_new)

# 改写推导式
lst = [ i for i in lst if i % 2 == 1 ]
print(lst)

3.多循环推导式

lst1 = ["孙杰龙","陈露","曹静怡"]
lst2 = ["王志国","邓鹏","合理"]
lst_new = []
for i in lst1:
    for j in lst2:
        lst_new.append(i+"♡♢"+j)
print(lst_new)

# 改写推导式
lst = [ i+"♡♢"+j for i in lst1 for j in lst2 ]
print(lst)

4.带有判断条件的多循环推导式

lst_new = []
for i in lst1:
    for j in lst2:
        if lst1.index(i) == lst2.index(j):
            lst_new.append(i+"♡♢"+j)
print(lst_new)

# 改写推导式
lst = [i+"♡♢"+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
print(lst)

# 案例
lst = []
for x in range(6):
    if x % 2 == 0 :
        for y in range(6):
            if y % 2 == 1:
                lst.append( (x,y)  )
print(lst)

# 推导式
lst = [ (x,y) for x in range(6) if x % 2 == 0 for y in range(6) if y % 2 == 1 ]
print(lst)

集合推导式

"""
案例:
	满足年龄在18到21,存款大于等于5000 小于等于5500的人,
	开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)	
	把开卡的种类统计出来
"""
lst = [
    {"name":"赵沈阳","age":18,"money":3000},
    {"name":"赵万里","age":19,"money":5200},
    {"name":"赵蜂拥","age":20,"money":100000},
    {"name":"赵世超","age":21,"money":1000},
    {"name":"王志国","age":18,"money":5500},
    {"name":"王永飞","age":99,"money":5500}
]
setvar = set()
for i in lst:
    print(i) # {'name': '赵沈阳', 'age': 18, 'money': 3000}
    if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:
        res = "尊贵VIP卡老{}".format(i["name"][0])
    else:
        res = "抠脚大汉卡老{}".format(i["name"][0])
    # 添加到集合中
    setvar.add(res)
print(setvar)

# { 三元运算符 + 推导式 }
# 三运运算符 + 推导式
setvar = { "尊贵VIP卡老{}".format(i["name"][0]) if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500 else "抠脚大汉卡老{}".format(i["name"][0]) for i in lst }
print(setvar)

字典推导式

1. enumerate

"""
enumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
参数:
    iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 
    start:  可以选择开始的索引号(默认从0开始索引)
返回值:迭代器
"""

# 基本语法
from collections import Iterator,Iterable
lst =["王一","吕洞宾","何仙姑","铁拐李","张国老","曹国舅","蓝采和","韩湘子"]
it = enumerate(lst)
it = enumerate(lst,start=100)
print(isinstance(it,Iterator)) # True

# next 
print( next(it) )

# for + next (推荐,数据较大时使用)
for i in range(3):
    print(next(it))
    
# for
for i in it:
    print(i)

# list 强转迭代器
print(list(it))

# (1) 字典推导式 配合 enumerate 来实现
dic = {k:v for k,v in enumerate(lst,start=100)}
print(dic) # {100: '王一'}
"""
(100, '王一')
(101, '吕洞宾')
(102, '何仙姑')
(103, '铁拐李')
(104, '张国老')
(105, '曹国舅')
(106, '蓝采和')
(107, '韩湘子')
"""

# (2) 使用dict强转迭代器,瞬间得到字典
dic = dict( enumerate(lst,start=100) )
print(dic)

2. zip

"""
特点:按照索引配对
zip(iterable, ... ...)
    功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
    iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 
返回: 迭代器
"""
# 基本语法
# lst1 = ["孙开启","王永飞","于朝志"]
# lst2 = ["薛宇健","韩瑞晓","上朝气"]
# lst3 = ["刘文博","历史园","张光旭"]

# 在索引下标同时存在时,才会进行配对,否则舍弃.
lst1 = ["孙开启","王永飞","于朝志"]
lst2 = ["薛宇健","韩瑞晓"]
lst3 = ["刘文博"]

it = zip(lst1,lst2,lst3)
print(list(it)) # [("孙开启","薛宇健","刘文博")]

# (1) 字典推导式 配合 zip 来实现
lst_key = ["ww","axd","yyt"]
lst_val = ["王维","安晓东","杨元涛"]

# ('ww', '王维'), ('axd', '安晓东'), ('yyt', '杨元涛')
dic = {k:v   for k,v in zip(lst_key , lst_val) }
print(dic)

# (2) 使用dict强转迭代器,瞬间得到字典
dic = dict( zip(lst_key , lst_val) )
print(dic)

生成器

元组推导式是生成器(generator)

"""
#生成器本质是迭代器,允许自定义逻辑的迭代器

#迭代器和生成器区别:
	迭代器本身是系统内置的.重写不了.
    而生成器是用户自定义的,可以重写迭代逻辑

#生成器可以用两种方式创建:
    (1)生成器表达式  (里面是推导式,外面用圆括号)
    (2)生成器函数    (用def定义,里面含有yield)
"""

1. 生成器表达式 (里面是推导式,外面用圆括号)

gen = ( i for i in range(10) )
print(gen) # <generator object <genexpr> at 0x00>

# 判断类型
from collections import Iterator,Iterable
print(isinstance(gen,Iterator)) # True

# 1.next 调用生成器
print(next(gen))
print(next(gen))

# 2.for + next 调用生成器
for i in range(3):
    print(next(gen))
    
# 3.for 调用生成器所有数据
for i in gen:
    print(i)
   
# 4.list强转生成器,瞬间得到所有数据
gen = ( i for i in range(10) )
print(list(gen))

# print(next(gen)) # error  # StopIteration

2. 生成器函数

"""
# yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
		   而return直接终止函数,每次重头调用.
yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用
"""

(1) 基本语法

def mygen():
    print("111")
    yield 1
    
    print("222")
    yield 2
    
    print("333")
    yield 3
   
# 初始化生成器函数  => 返回生成器对象 => 简称生成器
gen = mygen()

# 第一次调用
res = next(gen)
print(res) # 1
# 第二次调用
res = next(gen)
print(res) # 2
# 第三次调用
res = next(gen)
print(res) # 3
# 第四次调用,会报错
"""
# StopIteration error 
res = next(gen)
print(res)
"""
"""
# 第一次调用
print("111")  yield 1 保存当前第2行代码的状态,把1返回,并且等待下一次调用
# 第二次调用
从上一次保存的位置2行往下走, print("222") yield 2 保存当前第5行代码的状态,把2返回,并且等待下一次调用
# 第三次调用
从上一次保存的位置5行往下走, print("333") yield 3 保存当前第8行代码的状态,把3返回,并且等待下一次调用
# 第四次调用
因为没有更多的yield 返回数据,所有停止迭代.出现报错异常.
"""

(2) 优化生成器代码

"""生成器应用的场景是在大数据的范围中使用,切记不可直接用for遍历所有,可能无法短时间内获取所有数据"""
def mygen():
    for i in range(1,101):
        yield i
# 初始化生成器函数 => 生成器
gen = mygen()
# 需要多少数据,就取多少数据,防止占用大内存
for i in range(30):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

for i in range(40):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

(3) send的使用方式 (给上一个yield发送数据)

"""
# next和send区别:
	next 只能取值
	send 不但能取值,还能发送值
# send注意点:
	第一个 send 不能给 yield 传值 默认只能写None
	最后一个yield 接受不到send的发送值
"""
def mygen():
    print("start")
    
    res = yield "内部1"
    print(res,"<==内部==>")
    
    res = yield "内部2"
    print(res,"<==内部==>")
    
    res = yield "内部3"
    print(res,"<==内部==>")
    
    print("end")
    
# 初始化生成器函数 => 生成器
gen = mygen()
# 第一次调用生成器
"""
第一次调用生成器时,因为没有遇到yield保存的代码位置,
无法发送数据,默认第一次只能发送None
"""
res = gen.send(None) # 不传None会报错
print(res,"<==外部==>")

# 第二次调用生成器
res = gen.send("100")
print(res,"<==外部==>")

# 第三次调用生成器
res = gen.send("200")
print(res,"<==外部==>")

# 第四次调用生成器
"""
# error, print("end")后面没有yield,会报错
res = gen.send("300")
print(res,"<==外部==>")
"""
"""
使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置
res = gen.send(None)  走到mygen生成器函数中
print("start") 
res = yield "内部1"  执行第4行 ,保存退出,记录当前代码位置,将 "内部1" 返回
在22行接受数据  res = "内部1"  print(内部1,"<==外部==>")

第二次调用生成器
res = gen.send("100") 把100这个数据发送给上一次代码保存的位置4行进行接收. => 导致 4行 res = 100
打印5行  print(100 ,"<==内部==>")
执行7行  res = yield "内部2"  保存退出,记录当前代码位置,将 "内部2" 返回
执行26行 res = gen.send("100") => "内部2" print("内部2","<==外部==>")

....
依次类推 ... 
到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止;
"""

(4) yield from 的使用

"""将一个可迭代对象变成一个迭代器返回	"""
def mygen():
    lst = ["张磊","李亚峰","刘一峰","王同培"]
    yield from lst
    
# 初始化生成器函数
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
# print(next(gen)) # StopIteration

(5) 案例: 斐波那契数列

# (5) 斐波那契数列
"""使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印"""
"""1 1 2 3 5 8 13 21 34 .... """

def mygen(maxval):
    a,b = 0,1
    i = 0
    while i < maxval:
        # print(b) 
        yield b
        a,b = b,a+b
        i += 1
# mygen(10)
gen = mygen(10)

# 第一次获取
for i in range(3):
    print(next(gen))

# 第二次获取
for i in range(5):
    print(next(gen))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值