
基础语法你会了但离 写优雅的 Python 还差几个高级武器。老哥这篇把拷贝、迭代器、生成器、闭包、装饰器一次补齐。一、浅拷贝 vs 深拷贝先分清三种 复制直接赋值只是引用的别名不产生拷贝浅拷贝拷贝父对象但内部子对象还是共享只有第一层独立深拷贝父对象和子对象全都独立拷贝。浅拷贝的三种方式切片[:]、工厂函数list()/set()、copy.copy()。用内存地址看深浅拷贝的区别核心可变类型的子对象是否独立import copy list1 [1, 2, 3, [100, 200, 300]] list2 copy.copy(list1) # 浅拷贝 print(id(list2[3]) id(list1[3])) # True 子列表还是同一个 list1[3].append(400) # 改子列表 print(list2) # [1, 2, 3, [100, 200, 300, 400]] 浅拷贝也被改了 list3 copy.deepcopy(list1) # 深拷贝 print(id(list3[3]) id(list1[3])) # False 子列表独立了 list1[3].append(500) print(list3) # 深拷贝不受影响特殊情况数字、字符串等 原子类型 无法拷贝copy 后地址不变只含原子类型的元组深拷贝也不会变地址不变。二、迭代器记住位置、往前遍历迭代器是一个能记住遍历位置的对象只能往前不会后退。字符串、列表、元组都能创建迭代器。用iter()创建、next()取下一个取完抛StopIterationlst [1, 2, 3] it iter(lst) print(next(it)) # 1 print(next(it)) # 2 print(next(it)) # 3 print(next(it)) # StopIteration判断可迭代 / 迭代器from collections.abc import Iterable, Iterator print(isinstance([], Iterable)) # True 列表可迭代 print(isinstance([], Iterator)) # False 但本身不是迭代器 print(isinstance((x for x in range(10)), Iterator)) # True 生成器是迭代器自定义迭代器实现__iter__()返回自己和__next__()取元素取完抛StopIterationclass Reverse: def __init__(self, data): self.data data self.index len(data) def __iter__(self): return self def __next__(self): if self.index 0: raise StopIteration self.index - 1 return self.data[self.index] for char in Reverse([2, 3, 5, 7]): print(char) # 7 5 3 2三、生成器按需产生值省内存生成器generator是创建迭代器的简单工具用yield替代return。每次遇到yield暂停、保存状态下次从暂停处继续。最大优势按需生成避免一次性占用大量内存。两种创建方式# 方式一推导式注意是圆括号 gen (x for x in range(5)) print(gen) # generator object ... for x in gen: print(x) # 方式二yield 函数 def fibo(): # 斐波那契 a, b 0, 1 while True: yield b a, b b, a b f fibo() print(next(f)) # 1 print(next(f)) # 1 print(next(f)) # 2send()向生成器 发送 值实现两个任务交替执行def gen(): task_id 0 int_value 0 char_value A while True: match task_id: case 0: task_id yield int_value # 返回并接收 send 的值 int_value 1 case 1: task_id yield char_value char_value chr(ord(char_value) 1) case _: task_id yield g gen() print(next(g)) # 0 print(g.send(1)) # A print(g.send(0)) # 1 print(g.send(1)) # B注意第一次启动生成器要用send(None)此时没有 yield 可接收值。四、闭包函数 记住 外层变量函数执行完内部变量本应销毁。但闭包能让外层函数的变量被保存、重复使用同时避免全局变量污染。构建闭包三条件外层函数定义内层函数、内层用到外层变量、外层把内层返回。def linear(a, b): # 外层 def inner(x): # 内层 return a * x b # 用到外层变量 a、b return inner # 返回内层 y1 linear(1, 1) print(y1(5)) # 6 虽然 linear 已结束但 a、b 还在 # 查看闭包保存的值 print(y1.__closure__[0].cell_contents) # 1 print(y1.__closure__[1].cell_contents) # 1五、装饰器不改原函数动态加功能装饰器接收一个函数返回一个包装后的新函数从而不修改原代码就给函数加功能。最基础的装饰器让sqrt先求绝对值负数也能开根号from math import sqrt def decorator(f): def inner(x): x abs(x) # 加功能先取绝对值 return f(x) return inner decorator # 等价于 func decorator(func) def func(x): return sqrt(x) print(func(-4)) # 2.0多层装饰器离函数最近的先装饰从内到外get_integer get_absolute def func(x): return sqrt(x)带参数的装饰器如 开 n 次方def times(n): def get_absolute(f): def inner(x): x abs(x) for i in range(n): x f(x) return x return inner return get_absolute times(2) # 开两次方 def func(x): return sqrt(x) print(func(-16)) # 2.0类装饰器实现__call__()的类也能当装饰器class DecoratorClass: def __init__(self, f): self.f f def __call__(self, x): x abs(x) return self.f(x) DecoratorClass def func(x): return sqrt(x) print(func(-4)) # 2.0老哥收尾一句话总结这批 进阶神器浅拷贝共享子对象、深拷贝全独立迭代器记住位置只能往前生成器用 yield 按需生成省内存闭包记住外层变量装饰器不改原函数就能加功能。下一篇讲进程与线程—— 让程序 多任务并行。有问题随时回来找老哥。