迭代器和生成器
迭代
- 迭代对象指可以被for循环遍历的对象,迭代是指遍历的过程
- 可迭代对象有两个 - 容器和迭代器,迭代器又有生成器分支
迭代器 - iterator
-
性质
- 迭代器中的元素无法被print打印
- 迭代器中元素个数无法用len方法查看
- 迭代器 - iterator
- 迭代类似数据结构中的队列,具有先进先出的特性,元素被取出后即消失
- iter方法可将任何容器型数据类型转为迭代器
str1 = 'hello' str1_iter = iter(str1) # 将字符串类型数据转为迭代器 print(str1_iter, type(str1_iter)) # 打印结果为<str_iterator object at 0x103425fd0> <class 'str_iterator'> list1 = [1, 2, 3] list_iter = iter(list1) # 将列表转为迭代器 print(list_iter, type(list_iter)) # 打印结果为<list_iterator object at 0x103425f40> <class 'list_iterator'>
如何获取迭代器中的元素
-
方法1 - 用for循环遍历
-
方法2 - next( )
# 用for循环遍历 for i in str1_iter: print(i) # 每次输出一个元素 # 输出结果为 h e l l o # next() - 一个一个取 print(next(str1_iter)) # 输出结果为h
迭代器能做什么
- 迭代器的使用,能使元素被取出,释放内存,让程序的内存占用更小
生成器 - generator
-
**性质
** 使用生成器的目的是生成迭代器,可以说生成器是迭代器,但迭代器不一定生成器- 生成器为一个函数
- 函数不会在调用生成器时执行,只有在获取元素时生成器才执行
- 获取一个元素才能够让生成器函数执行一次
- 生成器函数的返回结果用yield代替return
- yield执行几次,生成器就生成几个元素
# 定义一个生成器函数 def myGener(): print('123') yield 100 yield 200 yield 300 if 100 > 200: yield 300 return 1 yield 400 f = myGener() print(f) # 调用时函数不执行,无输出结果 print(next(f)) # 输出元素100 for i in f: print(i) # 打印剩余元素,输出200和300
yield和return区别
-
当return被触发时,执行立即结束,yield则不会结束函数执行
-
return和yield都可将函数的结果返回到外部
-
return和yield后面跟的都是表达式
# 练习:使用生成器创建python001-python999学号 def stu_id(): for i in range(1, 1000): yield f'python{j:0>3}' f = stu_id() print(next(f)) # 打印结果为python001 for _ in range(100): print(next(f)) # 打印结果为python002-python101 # 接着上次的打印,从python002打印100个,到python101结束
匿名函数
-
概念 - 用lambda表达式简化的函数
-
原理 - 普通函数和匿名函数类似于单分支结构和三目运算符的关系
-
匿名函数有严格的固定语法,是普通函数的语法糖(在原有的语法上做简化,能提高代码的可读性,但不影响功能)
# 计算两数字的和 def numSum(num1, num2): # 普通方法 return num1 + num2 print(numSum(10, 20)) # 输出结果为30 # lambda方法 numSumLambda = lambda num1, num2: num1 + num2 print(numSumLambda(10, 20)) # 输出结果为30
-
匿名函数lambda语法
# 函数名 = lambda 形参: 返回值 # 函数名(实参)
# 练习:使用匿名函数计算1-100的和 totalLambda = lambda start, end: sum([i for i in range(start, end+1)]) print(totalLambda(1, 100)) # 输出结果为5050
-
并不是所有的普通函数都可以转为匿名函数
# 练习:使用匿名函数判断年份是否为闰年 isLeapYear = lambda year: [f'{year}年为闰年' if year % 400 == 0 or (if year % 4 == 0 and year % 4 != 0) else f'{year}年不为闰年'] print(isLeapYear(2000)) # 输出结果为2000年为闰年
递归
- 递归是一种循环思想
- 函数的执行是一个相互调用的过程,递归是一种特殊的函数调用,为自己调用自己
迭代(递推)思维和递归思维
-
递推思维 - 根据已有的数据来推算规律 (正向推算),例如斐波那契数列
-
递归思维 - 根据规律逆向推算
-
递归虽为循环思想,但要注意循环结束的条件,不然会造成死循环
# 递归思想 def fib(N): if N == 1 or N == 2: # 斐波那契数列的前两位为1 return 1 else: return fib(N - 1) + fib(N - 2) print(fib(9))
如何写出递归思想的代码
-
知道最终结果的计算规律
-
从需要算的结果往前推
-
了解递归的结束条件
# 练习:用递归计算N的阶乘 def factorial(n): if n == 1: return 1 else: return n * factorial(n-1) print(factorial(10))
-
****能用循环解决的问题就能使用递归解决
-
若计算量较大,使用递归时有拓栈和压栈的过程,拓栈时内存容易溢出****
-
使用for循环不用考虑内存溢出
-
栈的特性是**’ 先进后出 '**
高阶函数
-
定义 - 将一个函数当作另一个函数的参数
def func1(): pass def func2(func): print('这是另一个函数') func() func2(func1) # 打印结果为'这是另一个函数'
-
Python常用高阶函数: max、min、sorted、map、reduce
# max、min调取容器中的最大/最小元素 nums = [10, 55, 67, 666, 900] print(max(nums)) # max(容器, key=函数): 按照函数定义的方式获取容器中的最大值 # 按照数字中个位数的大小取值 def unitNum(num): return num % 10 print(max(nums, key=unitNum)) # 打印结果为67 print(max(nums, key=lambda num: num % 10)) # 打印结果为67 print(min(nums, key=unitNum)) # 打印结果为10 # sorted(容器, key=函数): 按照函数指定的形式对容器中元素排序 nums = [10, 55, 67, 666, 900] print(sorted(nums, key=lambda num: num % 10)) # 打印结果为[10, 900, 55, 666, 67],按照个位数从小到大 # reduce: 对传递的容器中的每个元素做累计 # 语法: reduce(函数, 容器, 初始值) # 函数要求: # a. 函数有两个形参,第一个指向初始值,第二个指向容器中每个元素 # b. 必须有返回值 from functools import reduce # 对列表中元素做积累 nums = [10, 55, 67, 666, 900] print(reduce(lambda total * num, nums, 1)) # reduce性能明显不及for循环,但表达方式更优雅/可读性更强 # map(): 根据容器产生一个新的序列 # 语法: map(函数, 容器1, 容器2, ....) # 函数要求: # a. 函数有N(容器数量)个形参 # b. 有返回值 # map函数产生的结果是一个可迭代对象,可以将可迭代对象使用构造器语法转换为列表、元组、集合等容器 names = ['小明', '小王', '小李'] chinese = [90, 95, 80] english = [60, 70, 80] map_iter = map(lambda a, b, c: {'name': a, 'chinese': b, 'english': c}, names, chinese, english) print(map_iter) # for i in map_iter: # print(i) print(list(map_iter))