Python开发-026_nolocal_深浅拷贝_yield_from
1 nolocal关键字
我们之前已经了解过global
关键字,它可以将局部作用域的变量变成全局作用域变量
name = 'root'
def outer():
name = "abc"
def inner():
global name # 修改的是全局变量
name = 123
inner()
print(name) # outer作用域中有name 所以还是abc
outer()
print(name) # 123 全局变量被修改为了123
nolocal
关键字修改的是它上一层的局部变量,而且它必须是放在第三层变量,放在第二层不会改变全局变量反而会报错
name = 'root'
def outer():
name = 'abc'
def inner():
nonlocal name
name = 123
inner()
print(name) # 123 nonlocal值修改上一层不修改全局变量
outer()
print(name) # root
2 深浅拷贝
深浅拷贝一般说的都是可变类型:set、list、dict
,不可变类型在进行深浅拷贝都是无意义的
我们使用一张图梳理一下,常用的复制拷贝方式
2.1 赋值
v1 = [1,2,3,4,5]
v2 = v1
print(v1,id(v1)) # [1, 2, 3, 4, 5] 140317387400128
print(v2,id(v2)) # [1, 2, 3, 4, 5] 140317387400128
这样的直接赋值会让v1和v2指向同一块内存地址,对于不可变类型无伤大雅,而对于可变类型,就有可能导致修改v2导致v1也发生变化
v2.append('abc')
print(v1) # [1, 2, 3, 4, 5, 'abc']
2.2 浅拷贝
import copy
v1 = [1,2,3,4,['a','b','c']]
v2 = copy.copy(v1)
print(v1,id(v1)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367616
print(v2,id(v2)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367360
拷贝则与简单直接的赋值不同,它会在内存的另一个区域开辟一块空间存放v2的列表,对于列表本身的运算处理不会影响v1
v2.append(5)
print(v1) # [1, 2, 3, 4, ['a', 'b', 'c']]
print(v2) # [1, 2, 3, 4, ['a', 'b', 'c'], 5]
不过浅拷贝也仅限于此,浅拷贝不会将元素的内存也拷贝过来,所以我们得到的其实是列表外壳的拷贝,而内存中的元素内存地址还是指向原来的内存地址,这就会导致,修改v2中嵌套的列表,会导致v1的值发生变化
print(id(v1[4])) # 140383422721152
print(id(v2[4])) # 140383422721152
# 列表中套的列表中的元素
print(id(v1[4][1])) # 140165184063664
print(id(v2[4][1])) # 140165184063664
v2[4].append(1)
print(v1) # [1, 2, 3, 4, ['a', 'b', 'c', 1]]
print(v2) # [1, 2, 3, 4, ['a', 'b', 'c', 1], 5] # 5是之前修改的
2.3 深拷贝
import copy
v1 = [1,2,3,4,['a','b','c']]
v2 = copy.deepcopy(v1)
print(v1,id(v1)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367616
print(v2,id(v2)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367360
print(id(v1[4])) # 140256185297920
print(id(v2[4])) # 140256185296128
v2[4].append(1)
print(v1) # [1, 2, 3, 4, ['a', 'b', 'c']]
print(v2) # [1, 2, 3, 4, ['a', 'b', 'c', 1]]
深拷贝会将可变元素的内存地址同样拷贝一份放在另一个内存空间,无论怎么修改,他们之间都互不影响
import copy
v1 = [1,2,3,4,['a','b','c']]
v2 = copy.deepcopy(v1)
# 拷贝列表和被拷贝列表的内存空间
print(v1,id(v1)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367616
print(v2,id(v2)) # [1, 2, 3, 4, ['a', 'b', 'c']] 140667964367360
# 可变元素内存空间
print(id(v1[4])) # 140256185297920
print(id(v2[4])) # 140256185296128
# 修改可变元素内部的值
v2[4].append(1)
print(v1) # [1, 2, 3, 4, ['a', 'b', 'c']]
print(v2) # [1, 2, 3, 4, ['a', 'b', 'c', 1]]
2.4 深浅拷贝为什么对不可变类型没有意义?
这是python内部对一个优化方案,对于一个相同的不可变类型(例如字符串),他在创建之初,内存地址的值就无法被改变,任何的操作都不会影响它本身,所以python处于性能考虑在定义两个值相同的不可变类型时,就会指向同一个内存空间
v1 = 'abcdefg'
v2 = 'abcdefg'
print(id(v1)) # 140153775805424
print(id(v2)) # 140153775805424
所以深浅拷贝对于不可变类型没有任何意义,无论怎么拷贝,值相同,指向的内存空间就相同
2.5 元组面对拷贝的处理办法
总所周知,元组是个不可变类型,面对不可变类型,无论拷贝还是赋值,相同的值指向同一块内存空间,但元组也是一个特殊的不可变类型,因为它的内部可以嵌套可变类型
import copy
v1 = (1,2,3,[1,2,3])
v2 = v1
v3 = copy.copy(v1)
v4 = copy.deepcopy(v1)
print(v1,id(v1)) # (1, 2, 3, [1, 2, 3]) 140592533849568
print(v2,id(v2)) # (1, 2, 3, [1, 2, 3]) 140592533849568
print(v3,id(v3)) # (1, 2, 3, [1, 2, 3]) 140592533849568
print(v4,id(v4)) # (1, 2, 3, [1, 2, 3]) 140592533849328 # 内存地址发生改变
# 深拷贝直接将内部的可变类型拷贝了一份
print(id(v1[3])) # 140576830204928
print(id(v4[3])) # 140576830202176
3 yield from
def v1():
yield 1
yield 1
yield from v2()
yield 1
yield 1
def v2():
yield 2
yield 2
for item in v1():
print(item,end=" ")
# 1 1 2 2 1 1
yield from
其实就是在指向生成器的时候,遇到了from
就跳转到另一个生成器继续执行
Python开发-026_nolocal_深浅拷贝_yield_from
http://localhost:8080/archives/5Tmtb8ZY