智泊Python–Day10
Day10 是函数主题的收尾,并引出 Python 的「惰性计算」体系。先讲递归(函数自己调用自己,靠临界值收口),再讲列表 / 字典 / 集合推导式(一行 for 生成容器),然后重点是生成器和迭代器——这两者都「用到才生成」,能省内存;最后落到工程层面:第三方包怎么装、包 / 模块 怎么组织与导入。记住一句话:生成器 ⊂ 迭代器 ⊂ 可迭代对象。
1.函数递归
递归两大要素:找递推公式 + 设临界值(出口)。阶乘 n! = n * (n-1)!,临界值是 n==1;斐波那契 fib(n)=fib(n-1)+fib(n-2),临界值是 n==1 或 2。下面那个「兔子繁衍」是变体:当月对数 = 上月对数 + 三个月前的新生对数,即 f(n)=f(n-1)+f(n-3),临界 n<=3 返回 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
def fn(n): if n == 1: return 1 else: return n * fn(n-1)
print(fn(5))
def fib(n): if n == 1 or n == 2: return 1 else: s = fib(n-1) + fib(n-2) return s print(fib(5))
def f(n): if n <= 3: return 1 else: s = f(n-1) + f(n-3) return s
print(f(20))
|
2.列表推导式
推导式是「用一行 for 生成容器」的语法糖,比先建空列表再 append 更简洁。列表用 []、字典用 {} 配 键:值、集合用 {}。可以加 if 过滤,也支持多层 for 嵌套。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
nums = [1, 2, 3, 4, 5] print(nums) print("="*20) nums1 = [] for i in range(1, 6): nums1.append(i) i += 1 print(nums1) print("="*20)
nums2 = [i for i in range(1, 6)] print(nums2) nums3 = [i*2 for i in range(1, 6)] print(nums3) nums4 = [i for i in range(1, 6) if i%2 == 1] print(nums4) nums5 = [i for i in range(1, 6) if i%2 == 1 and i != 3] print(nums5)
nums6 = [i for i in range(1, 7) if i%2==0 if i%3 == 0] print(nums6)
nums7 = [i+j for i in range(1, 6) for j in range(1, 6)] print(nums7) print("="*20)
dict1 = {f'key{i}': i*2 for i in range(1, 6)} print(dict1)
set1 = {i for i in range(1, 6)} print(set1)
|
3.生成器和生成器函数
生成器用 () 定义(区别于列表的 []),不一次性算出所有值,而是用到才生成,所以只占一点内存。生成器函数则在函数体内用 yield:每调一次 next(),执行到 yield 就暂停并返回值,下次再从暂停处继续——return 会结束函数,yield 只是暂停。下面用 while True: yield a; a,b=b,a+b 优雅地实现了无限斐波那契序列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
gen = (i for i in range(1, 6)) print(gen)
for i in range(1, 6): print(next(gen))
def gen_fn(): print('我是gen_fn, 你看我会执行吗'), yield 666 print('我是gen_fn, 你看我会执行吗2'), yield 777
gen1 = gen_fn() print(gen1) print(next(gen1)) print(next(gen1))
def gen_fn2(): g = (i for i in range(1, 10**100)) for i in g: yield i
gen2 = gen_fn2() print(gen2) print(next(gen2)) print(next(gen2)) print(next(gen2))
print("="*20) def fib_fn(): a, b = 0, 1 while True: yield a a, b = b, a+b
fib = fib_fn() for i in range(20): print(next(fib))
|
4.迭代器
三者的关系用一句话记:可迭代对象(能放 for 里遍历)⊃ 迭代器(记住遍历位置,能 next)⊃ 生成器(yield 写的迭代器)。注意 list/str/dict/set/生成器都是可迭代对象,但它们本身不是迭代器(isinstance(..., Iterator) 为 False);只有生成器表达式 (i for ...) 才是迭代器。iter() 能把可迭代对象转成迭代器。下面已删除两行与主题无关的自动补全残留导入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
print(10, type(10)) print(isinstance(10, int)) print(isinstance(10, (int ,float,list))) print("="*30)
from typing import Iterator
print(isinstance([1,2,3], Iterator)) print(isinstance({1,2,3}, Iterator)) print(isinstance((1,2,3), Iterator)) print(isinstance((i for i in range(10)), Iterator)) print("="*30)
from typing import Iterable print(isinstance(3, Iterable)) print(isinstance(3.14, Iterable)) print(isinstance("hello", Iterable)) print(isinstance([1,2,3], Iterable)) print(isinstance({1,2,3}, Iterable)) print(isinstance((1,2,3), Iterable)) print(isinstance((i for i in range(10)), Iterable))
print(iter([1,2,3])) print(iter("hello")) print(iter({1,2,3}))
|
5.第三方包的安装
Python 的包分三类:官方内置、自己写的、别人写的第三方包。日常用 pip 管理第三方包,常用命令都列在下面。
6.包和模块
组织代码的层次是:项目 → 包(带 __init__.py 的文件夹)→ 模块(.py 文件)→ 类 → 函数。导入有几种姿势:import 模块、from 模块 import 名字、from 模块 import *、as 起别名(起名后只能用别名)。模块被导入时会自动执行一次其中的顶层代码,且是单例——多次导入只执行一遍。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
from package1.module import name print(name)
import package1.module as m1
|
7.作业
两道大作业:①万年历——综合运用 Day8 的闰年 / 月天数判断,从 1900-01-01 算总天数再推算当月 1 号是星期几,格式化打印整月日历(依赖自定义模块 package1.wnl);②写一个无限序列生成器,从 1 开始每次 +1,用 while True + yield 实现,外层 next() 取前 n 个(原笔记里那行 numpy.f2py 导入与本题无关,已删除)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
def infinite_sequence(): i = 1 while True: yield i i += 1
G2 = infinite_sequence()
import time while True: print(next(G2)) time.sleep(1)
|