python函数的高级1——深拷贝+yeild
一、浅拷贝和深拷贝(copy模块中的区分)
- 区分拷贝和赋值
- 拷贝:将原始的数据复制一份,本质上是在开辟一个空间存储拷贝的数据(两份数据的存储地址是不同的)
- 赋值:仅仅是改变指向数据的变量,数据的存储地址并没有发生变化
- 浅拷贝和深拷贝的不同(只有在嵌套数据类型的时候才有有本质的区别)
-
浅拷贝:对嵌套的可变数据类型:将表层的数据进行,从新开辟一个存储空间进行存储,而深层的数据并不会被重新存储。
-
深拷贝:对于嵌套的可变数据类型:将所有的数据全部进行一次新的存储
- 二者的相同点
- copy.copy(浅拷贝)和copy.deepcopy(深拷贝)对不可变数据类型不会进行拷贝(即:对不可变数据类型使用copy的话,相当于赋值的操作)
- 对于可变数据类型的单层数据(未嵌套数据的数据)两个操作是相同的
二、生成器函数–函数中带有yield的可迭代对象
- yield的含义
yield
是 Python 中的一个关键字,用于定义生成器函数(Generator Function)。- 它的作用是暂停函数的执行,并返回(生成)一个值,但函数的状态会被保留,以便下次调用时从暂停的位置继续执行。
- yield的核心概念
- 当一个函数包含
yield
时,它就不再是普通函数,而是一个生成器函数。 - 调用生成器函数时,它不会立即执行,而是返回一个生成器对象(可迭代对象)。
- 生成器对象可以通过
next()
或for
循环逐步执行,知道生成器对象迭代完毕。
- 暂停与恢复
- 执行到
yield
时,函数会暂停到yield生成器生成的这一步,并返回yield
生成的值。 - 下次调用
next()
时,函数会从上次暂停的位置(yield生成器后的一步)继续执行,直到遇到下一个yield
或函数结束。
- 与 return 的区别
return
会终止函数并返回一个值,函数状态被销毁。yield
会暂停函数,保留所有局部变量,下次继续执行。
-
基本yield的示例用法(创建一个生成器,并用
for
循环自动迭代生成数字)def count_up_to(n):i = 1while i <= n:yield i i += 1 f = count_up_to(5) next(f) # f.send(值),在恢复生成器的时候给生成器内部发送一个值,这个值会当成yelid表达式的返回值 # 自动调用 next() 直到 StopIteration # 每次 next() 都是调用一次生成器 for num in f:print(num) # 输出 1, 2, 3, 4, 5
-
生成器中的send()
-
send()
让生成器能够从外部接收值
generator.send(value)
是 Python 生成器(Generator)的一个重要方法,它允许在恢复生成器执行的同时,向生成器内部发送一个值,这个值会成为当前 yield 表达式的返回值。 -
next(生成器)
==生成器.send("值")
-
第一次调用
send()
必须发送None
,用于激活生成器。
生成器刚开始执行时,还没有yield
可以接收值,所以第一次必须用next(generator)
或generator.send(None)
启动生成器。 -
后续
send()
可以传任意值
生成器会从上次 yield 的位置恢复,并且send(value)
的参数会成为yield
的返回值。 -
生成器结束后再
send()
会抛出StopIteration
和next()
一样,生成器执行完毕后不能继续send()
def echo():print("Start")x = yield "Ready" # 第一次 yieldprint(f"Received: {x}")yield x * 2 # 第二次 yieldgen = echo()# 第一次调用必须用 next() 或 send(None) 启动生成器 print(gen.send(None)) # 输出 "Start",返回 "Ready"# 发送数据并继续执行 print(gen.send(10)) # 输出 "Received: 10",返回 20# 输出 Start Ready Received: 10 20
- yield from 的用法
- 替代 for 循环 + yield,让代码更简洁。
- 支持生成器之间的双向通信(send()、throw()、close())。
- 自动处理 StopIteration,并获取子生成器的返回值。
# 简单的嵌套生成器
def sub_generator():yield 1yield 2def main_generator():yield "Start"yield from sub_generator() # 委托给 sub_generatoryield "End"for item in main_generator():print(item)
# 输出:Start, 1, 2, End
yield
的用途
-
惰性计算(Lazy Evaluation)
适用于大数据处理,避免一次性加载所有数据到内存(如读取大文件)。def read_large_file(file_path):with open(file_path, "r") as file:for line in file:yield line # 逐行生成,不一次性读取全部
-
生成无限序列(如斐波那契数列):
def fibonacci():a, b = 0, 1while True:yield aa, b = b, a + b
-
协程(Coroutine)
yield
可以用于实现简单的协程(协作式多任务)。def coroutine():while True:received = yieldprint(f"Received: {received}")co = coroutine() next(co) # 启动协程(执行到第一个 yield) co.send("Hello") # 输出 "Received: Hello" co.send("World") # 输出 "Received: World"
- yield和return的比较
特性 | yield | return |
---|---|---|
执行方式 | 暂停函数,下次继续执行 | 终止函数 |
返回值 | 每次 yield 生成一个值 | 只返回一次 |
内存占用 | 低(惰性计算,不一次性存储所有数据) | 高(需存储所有结果) |
适用场景 | 大数据处理、无限序列、协程 | 普通函数返回值 |
yield
的核心作用:让函数变成生成器,支持惰性计算和状态保持。