Day09
迭代器和生成器
一、迭代
迭代在Python中就是属于可以做for循环遍历的对象,被叫做可迭代对象
二、可迭代对象
可迭代对象分为容器和迭代器两种,迭代器又有生成器分支
三、迭代器
性质
- 使用print无法查看迭代器中的元素
- 使用len方法也无法查看其中元素个数
- 迭代器(iterator)
- 迭代器类似数据结构中的队列(先进先出),迭代器中的元素被取出,即消失
- 任何容器型数据类型都可以属于iter方法转为迭代器
str1 = 'hello'
str1_iter = iter(str1)
print(str1_iter, type(str1_iter))
list1 = [1, 2, 3]
list_iter = iter(list1)
print(list_iter, type(list_iter))
四、如何获取迭代器中的元素
方法一:for循环遍历
方法二:next()
print(next(str1_iter))
print(next(str1_iter))
for i in str1_iter:
print(i)
五、迭代器的作用
元素被全部取出,迭代器消失,迭代器所占内存被释放,程序就可以减少内存占用
六、生成器(generator)
性质
- 生成器是为了生成迭代器(生成器就是迭代器,但是迭代器不一定是生成器)
- 生成器是一个函数
- 调用生成器函数时,函数不执行,只有在获取元素时生成器函数才执行,并且是获取一个元素才能够让生成器函数执行一次
- 生成器函数返回内部结果使用yield代替return(可以同时存在)
- yield执行几次生成器就产生几个元素
def myGenerator():
print('123')
yield 100
yield 200
if 100 > 200:
yield 300
return 1
yield 400
f = myGenerator()
print(f)
print(next(f))
for i in f:
print(i)
七、yield和return的异同
- return被触发,函数立即结束;yield不会结束函数执行
- return和yield都可以将函数内部结果返回到外部
- return和yield后面都是跟表达式
练习:使用生成器创建Python001–Python999学号
def GenerateId():
for i in range(1,1000):
yield f'Python{i:0>3}'
f = GenerateId()
print(next(f))
# for i in f:
# print(i)
for _ in range(100):
print(next(f))
匿名函数
一、概念
Python中有一个lambda表达式,lambda有匿名的意思,并且lambda表达式就是简化的函数,所以叫匿名函数
二、理解
匿名函数和普通函数的关系可以理解为单分支结构和三目运算符的关系
三、匿名函数语法
匿名函数在语法上就是有着单一的严格限制的固定语法,在语义上是普通函数的语法糖
语法糖(糖衣语法):一位英国的计算机学家提出的概念:语法糖就是对已经存在的语法的简化
语法糖能提高代码的可读性,但是不影响其功能
例:计算两个数字的和
def numSum(num1, num2):
return num1 + num2
print(numSum(10, 20))
numSumLambda = lambda num1, num2: num1 + num2
print(numSumLambda(10, 20))
语法:
函数名 = lambda 形参:返回值
函数名(实参)
练习:1.使用匿名函数计算1–100的和
2.使用匿名函数判断年份是否是闰年
# def NumSum(start = 1,end = 100):
# n = 0
# for i in range(start,end + 1):
# n += i
# return n
# print(NumSum())
sumLambda = lambda start,end:sum([i for i in range(start,end+1)])
print(sumLambda(1,100))
LeapYearLambda = lambda year:f'{year}是闰年' if(year % 4 == 0 and year % 100 != 0) or year % 400 == 0 else f'{year}是平年'
print(LeapYearLambda(2022))
并不是所有的普通函数都可以转为匿名函数
递归调用
一、递归
递归就是一种循环的思想
函数之间是相互调用的过程,递归是对于函数来说的,但是递归是一种特殊的函数调用(自己调用自己)
二、迭代(递推)思维和递归思维
递推思维:斐波那契数列:根据已有的数据推算规律(正向的推算)
递归思维:根据规则逆向推算
三、递归注意事项
递归虽然是循环的思想,但是要注意循环结束的条件,不然就陷入了死循环
著名的计算机学家说过:迭代是人,递归是神
练习:斐波那契数列
a = 1
b = 1
N = 50
for i in range(N - 2):
median = a + b
a , b = b , median
print(b)
# 递归思想:
def fib(N):
if N == 1 or N == 2:
return 1
else:
return fib(N-1) + fib(N - 2)
print(fib(9))
# 迭代运算过程:
# fib(9) = fib(8) + fib(7)
# fib(8) = fib(7) + fib(6)
# fib(7) = fib(6) + fib(5)
# fib(6) = fib(5) + fib(4)
# fib(5) = fib(4) + fib(3)
# fib(4) = fib(3) + fib(2)
# fib(3) = fib(2) + fib(1)
如何写出递归思想的代码
- 知道最终结果的计算规律
- 从需要算的结果往前推
- 了解递归结束的条件
- 学会自己调用自己的方式
练习:使用递归计算N的阶乘
def Factorial(N):
if N == 1:
return 1
else:
return N * Factorial(N - 1)
print(Factorial(6))
可以使用循环解决的问题就能使用递归
但是递归使用时需要谨慎,如果涉及计算量很大,有一个拓栈和压栈的过程,拓栈时容易内存溢出
栈:先进后出
高阶函数
一、高阶函数
将一个函数当做另一个函数的参数叫做高阶参数
print(max)
def func1():
print('这是一个函数')
print(func1)
func1()
a = func1
a()
# 自定义函数相当于是定义了一个数据类型为function的变量
def func2(func):
print('这是另一个函数')
func()
func2(func1)
###二、Python常用的高阶函数
max、min、sorted、map、reduce
- max、min:获取容器中最大(最小)的元素
nums = [1, 7, 26, 66, 1314]
print(max(nums))
用法:
max(容器,key=函数):按照函数定义的方式获取容器中的最大值
要求:
a.函数有且仅有一个形参
b.必须要有返回值
例:按照数字中个位数的大小取值(找出个位数最大的数字)
def unitNum(num):
return num % 10
print(max(nums, key=unitNum))
print(max(nums, key=lambda num: num % 10))
print(min(nums, key=unitNum))
- sorted(容器,key=函数):按照函数的指定形式对容器中元素排序
nums = [1, 7, 26, 52, 1314]
print(sorted(nums, key=lambda num: num % 10))
- reduce:根据传递的容器对容器中每个元素做累积
用法:
reduce(函数,容器,初始值)
要求:
a. 函数要有两个形参:第一个形参开始指向初始值,然后再指向每次累积的结果;第二个形参指向容器中每个元素
b. 必须要有返回值
from functools import reduce
nums = [1, 7, 26, 52, 1314]
# 对列表中元素做累乘
print(reduce(lambda total, num: total * num, nums, 1))
- map:根据容器产生一个新的序列
用法:
map(函数,容器1,容器2,…)
要求:
a. 函数有N(容器数量)个形参
b. 必须要有返回值
map函数的结果是一个可迭代对象,可以将这个迭代对象使用构造器语法转换为列表、元组、集合等容器
names = ['小A','小B','小C']
chinese = [90,95,80]
english = [60,70,80]
# {'name': '小A', 'chinese': 90, 'english': 60}
map_lit = map(lambda a,b,c:{'name':a,'chinese':b,'english':c},names,chinese,english)
print(map_lit)
# for i in map_lit:
# print(i)
print(list(map_lit))