day16 阶段总结
课程目标:对第二模块 “函数和模块” 阶段的知识点进行总结和考试,让学员更好的掌握此模块的相关知识。
课程概要:
- 知识补充
- 阶段总结(思维导图)
- 考试题
1.知识补充
1.1 nolocal关键字
在之前的课程中,我们学过global关键字。
name = 'root'
def outer():
name = "海贼王"
def inner():
global name
name = 123
inner()
print(name)
outer()
print(name)
其实,还有一个nolocal关键字,用的比较少,此处作为了解即可。
name = 'root'
def outer():
name = "海贼王"
def inner():
nonlocal name # 让name指向上一级的内存地址
name = 123
inner()
print(name)
outer()
print(name)
name = 'root'
def outer():
name = 'geek'
def func():
name = "海贼王"
def inner():
nonlocal name
name = 123
inner()
print(name)
func()
print(name)
outer()
print(name)
# 多个nonlocal一级一级往上找
name = 'root'
def outer():
name = 'geek'
def func():
nonlocal name
name = "海贼王"
def inner():
nonlocal name
name = 123
inner()
print(name)
func()
print(name)
outer()
print(name)
1.2 yield from
在生成器部分我们了解了yield关键字,其在python3.3之后有引入了一个yield from。
# 遇到 yield from 可以进入到另外的生成器函数中执行,当执行外完毕后继续执行原来的生成器函数。
def foo():
yield 2
yield 2
def func():
yield 1
yield from foo()
yield 1
for item in func():
print(item)
# 输出
1
2
2
1
# 如果只有yield 没有from就只会得到一个生成器对象
def foo():
yield 2
yield 2
def func():
yield 1
yield foo()
yield 1
for item in func():
print(item)
#输出
1
<generator object foo at 0x0000017DC823BC10>
1
1.3 深浅拷贝
-
浅拷贝
-
不可变类型,不拷贝。
# 深浅拷贝一般都是说的可变类型:`set` `list` `dict` (可变类型在进行深浅拷贝时无意义-内部都不会去拷贝,永远是同一块内存地址。) import copy v1 = "海贼王" print(id(v1)) # 2634991171792 v2 = copy.copy(v1) # 浅拷贝 print(id(v2)) # 2634991171792 # 不可变类型,不会拷贝而是指向同一块内存地址
按理说拷贝v1之后,v2的内存地址应该不同,但由于python内部优化机制,内存地址是相同的,因为对不可变类型而言,如果以后修改值,会重新创建一份数据,不会影响原数据,所以,不拷贝也无妨。
-
可变类型浅拷贝:针对拷贝类型,只拷贝第一层。内部的不可变类型&可变类型都不会被拷贝
# 可变类型,只拷贝第一层。 import copy v1 = ["海贼王", "root", [44, 55]] print(id(v1)) # 140405837216896 print(id(v1[2])) # 140405837214592 v2 = copy.copy(v1) print(id(v2)) # 140405837214784 print(id(v2[2])) # 140405837214592
# 浅拷贝 import copy v1 = ["海贼王", "root", [44, 55]] v2 = copy.copy(v1) print(id(v1)) # 2058892622848 print(id(v2)) # 2058892981440 # 可变类型之浅拷贝,列表会重新拷贝一份,注:拷贝的是列表,而不是列表中的数据 print(id(v1[2])) # 2058893546240 print(id(v2[2])) # 2058893546240
-
-
深拷贝
-
不可变类型,不拷贝
import copy v1 = "海贼王" print(id(v1)) # 1888115587280 v2 = copy.deepcopy(v1) # 深拷贝对不可变类型,不会拷贝而是指向同一块内存地址 print(id(v2)) # 1888115587280
特殊的元组:
-
元组元素中无可变类型,不拷贝
import copy v1 = ("海贼王", "root") print(id(v1)) # 1796403825792 v2 = copy.deepcopy(v1) print(id(v2)) # 1796403825792
-
深拷贝,对于可变类型,无论在那一层都会被拷贝,不可变类型永远不会被拷贝
import copy v1 = ("海贼王", "root", [11, [44, 55]]) v2 = copy.deepcopy(v1) print(id(v1)) # 2464296276096 print(id(v2)) # 2464295962240 # 列表指向了一个不可变类型,不会被拷贝,所有内存地址一样 print(id(v1[0])) # 2464296171728 print(id(v2[0])) # 2464296171728 # 列表中的列表,可变类型,无论多少层都会被拷贝,所以内存地址不一样 print(id(v1[2])) # 2464296318400 print(id(v2[2])) # 2464296276864
-
元素的元素中有可变类型,找到所有【可变类型】或【含有可变类型的元组】 均拷贝一份
import copy v1 = ("海贼王", "root", [11, [44, 55], (11, 22), (11, [], 22), 33]) v2 = copy.deepcopy(v1) print(id(v1)) # 1343966889792 print(id(v2)) # 1343972069888 print(id(v1[2])) # 1343971486976 print(id(v2[2])) # 1343972070208 print(id(v1[2][1])) # 1343972071040 print(id(v2[2][1])) # 1343972070848 print(id(v1[2][2])) # 1343966874752 print(id(v2[2][2])) # 1343966874752 print(id(v1[2][3])) # 1343971463232 print(id(v2[2][3])) # 1343972069824
-
-
可变类型,找到所有层级的 【可变类型】或【含有可变类型的元组】 均拷贝一份
import copy v1 = ["海贼王", "root", [11, [44, 55], (11, 22), (11, [], 22), 33]] v2 = copy.deepcopy(v1) print(id(v1)) # 1343966889792 print(id(v2)) # 1343972069888 print(id(v1[2])) # 1343971486976 print(id(v2[2])) # 1343972070208 print(id(v1[2][1])) # 1343972071040 print(id(v2[2][1])) # 1343972070848 print(id(v1[2][2])) # 1343966874752 print(id(v2[2][2])) # 1343966874752 print(id(v1[2][3])) # 1343971463232 print(id(v2[2][3])) # 1343972069824
import copy v1 = ["海贼王", "root", [44, 55]] v2 = copy.deepcopy(v1) print(id(v1)) # 2244897715712 print(id(v2)) # 2244897674112 print(id(v1[2])) # 140563140392256 print(id(v2[2])) # 140563140535744
总结:
- 浅拷贝,针对可变类型只拷贝第一层,内部不可变类型&可变类型都不会被拷贝
- 深拷贝,对于可变类型无论在那一层都会被拷贝,元组中如果有可变类型,也会被拷贝。而不可变类型永远不会被拷贝
- 特殊的元组,浅拷贝,永远不会被拷贝;深拷贝,当元素的元素中都是不可变类型时,永远不会被拷贝,如果元素中有可变类型,元组在深拷贝时也会被拷贝。
-
2.阶段总结
思维导图