一、闭包:局部变量往往随着函数开始调用而产生,执行结束而消亡。
闭包可以保存函数内的变量,不会随着调用完函数而被销毁。
闭包构成条件:1.有嵌套;2.有引用;3.有返回值。
注意:1.函数名本身记录的是内存地址;2.如果内部函数要改变外部变量,需要nonlocal声明,但注意重新运行函数时还是最初的函数值,除非使用了内部函数,才会重新改变。
闭包:
def outer(c):
a=int(input('value:'))
b=2
def inner(num): #有嵌套
num=num+a+b+c #有引用
print(num)
return inner #有返回
f=outer(3)
f(1)
f(2)
f(3)
声明nonlocal,改变外部变量b
def outer():
b=2
print(b)
def inner(num): #有嵌套
nonlocal b
b=10
num=num+b #有引用
print(num)
return inner #有返回
f=outer()
f(1)
outer()
二、装饰器:用来给原有函数在不改变自身情况下,增加额外功能。
装饰器有两种调用方式:1.原生方法调用;2.语法糖形式。另外,可以同时调用多个装饰器,当调用多个装饰器时,距离函数近的先装饰,然后把装饰好的结果传递给下一个装饰器,但打印是从外到内执行(反着来)。
注意:1.装饰器需要能够接收原有函数形参,定义装饰器时常常用*args和**kwargs作形参;2.装饰器每次只能传入一个参数,如果有多个参数,不然再嵌套函数(参看下面例子:装饰器工厂),不然可用原生方法(原生方法一次可以传入多个参数)。
定义装饰器&原生方法调用:
def outer(func):
def inner():
print('外部函数启动') #额外功能
func() #调用原有函数
return inner #此处返回的是原有函数
def comment(): #定义原有函数
print('内部函数启动:开始评论')
comment=outer(comment) #调用装饰器的原生方法
comment() #此处调用的是内部函数
定义装饰器&语法糖形式,运用了*args和**kwargs。
def outer(func):
def inner(*args,**kwargs): #*代表的是解包
print('外部函数启动') #额外功能
func(*args,**kwargs) #调用原有函数
return inner #此处返回的是原有函数
@outer #调用装饰器
def comment(name): #定义原有函数
print(f'内部函数启动:开始评论{name}')
comment('bob') #此处调用的是内部函数
同时定义和调用多个装饰器
def outer1(func):
def inner(*args,**kwards):
print('第一个装饰器')
func(*args,**kwards)
return inner
def outer2(func):
def inner(*args,**kwards):
print('第二个装饰器')
func(*args,**kwards)
return inner
@outer1 #后装饰,先打印,打印结果为“第一个装饰器”
@outer2 #先装饰,后打印,打印结果:“第二个装饰器”
def get_sum(*args,**kwards):
sum=0
for i in args:
sum+=i
for i in kwards.values():
sum+=i
print(sum)
return sum
get_sum(1,2,3,A=2,B=1,C=3) #最后打印结果
附加分享:装饰器工厂
def ooouter(name):
def oouter(flag):
def outer(func):
def inner():
if flag=="*":
print(f'{name}正在走路')
elif flag=="#":
print(f'{name}正在骑车')
elif flag=="@":
print(f'{name}正在开车')
func()
return inner
return outer
return oouter
dec=ooouter("小红")("#")
@dec
def play1():
print('要去学校')
dec=ooouter('小明')('@')
@dec
def play2():
print('要去上班')
play1()
play2()
三、赋值、变量传递、浅拷贝和深拷贝
赋值:直接将值赋给变量,如:a=1;
变量传递:将a变量的值赋给b变量,如:b=a;
浅拷贝:拷贝了最外围的对象本身,内部元素仅仅拷贝了一个引用,表现形式:copy(a);
深拷贝:拷贝出来一个全新的对象,不再与原来对象有任何关联,表现形式:deepcopy(a);
数据分为可变类型和不可变类型,对于不可变类型,再赋值给新变量名、变量传递、浅拷贝和深拷贝都只是引用地址传递,不开辟新的空间;
对于可变类型来说:1.除了变量传递不会开辟新的空间,只是引用地址传递外,再赋值给新变量名、浅拷贝和深拷贝都会开辟新的空间;2.浅拷贝和深拷贝的不同主要体现在:对于含有多层的可变类型数据,浅拷贝只拷贝了最外层,第二层及以上的值照样是引用地址传递,所以当第二层及以上的值发生变化时,浅拷贝结果也会发生相应变化(藕断丝连),而深拷贝是完全脱离了原来数据变量,绝不变化(恩断义绝)。
注意:在面对只有一层的可变类型数据时,浅拷贝和深拷贝没有差别:都开辟了新的空间,并都不受原来变量影响。
针对可变类型数据,赋值与变量传递的不同
a=[1,2,3] #赋值
b=[1,2,3] #再赋值给新变量名
c=a #变量传递
print(id(a),id(b),id(c)) #c和a的id一样,但都和b的id不一样(c只是引用地址传递,b开辟了新空间)
对于不可变类型:数值、字符串、元组;
无论再赋值给新变量名、还是变量引用、浅拷贝和深拷贝,都只是引用地址传递。
from copy import copy,deepcopy #先导入函数
#数值型
a1=1 #赋值
b1=copy(a1) #浅拷贝
c1=deepcopy(a1) #深拷贝
d1=a1 #变量传递
e1=1 #再赋值给新变量名
print(a1,b1,c1,d1,e1) #值都一样
print(id(a1),id(b1),id(c1),id(e1)) #id都一样
#字符串型
a2='123'
b2=copy(a2)
c2=deepcopy(a2)
d2=a2
e2='123'
print(a2,b2,c2,d2,e2) #值都一样
print(id(a2),id(b2),id(c2),id(e2) #id都一样
#元组型
a3=(1,2,3)
b3=copy(a3)
c3=deepcopy(a3)
d3=a3
e3=(1,2,3)
print(a3,b3,c3,d3) #值都一样
print(id(a3),id(b3),id(c3)) #id都一样
不可变类型数据:列表、集合、字典
#列表型
a4=[1,2,3] #赋值
b4=copy(a4) #浅拷贝
c4=deepcopy(a4) #深拷贝
d4=a4 #变量传递
e4=[1,2,3] #再赋值给新变量名
print(a4,b4,c4,d4,e4) #值都一样
print(id(a4),id(b4),id(c4),id(e4)) #除了变量传递的d4的id与a4一样,其它都不一样
#集合型(同列表情况)
a5={1,2,3}
b5=copy(a5)
c5=deepcopy(a5)
d5=a5
e5={1,2,3}
print(a5,b5,c5,d5,e5)
print(id(a5),id(b5),id(c5),id(e5))
#字典型(同列表情况)
a6={1:'a',2:'b',3:'c'}
b6=copy(a6)
c6=deepcopy(a6)
d6=a6
e6={1:'a',2:'b',3:'c'}
print(a6,b6,c6,d6,e6)
print(id(a6),id(b6),id(c6),id(d6),id(e6))
**#深浅拷贝的不同点:以列表为例**
a=[1,2,[3,4,['tom','linda']]] #赋值于a
b=copy(a) #浅拷贝,赋值于b
c=deepcopy(a) #深拷贝,赋值于c
print(a,b,c) #a,b,c此时值都为[1,2,[3,4,['tom','linda']]]
print(id(a),id(b),id(c)) #三者id各不相同
#改变第二层
a[2][0]=5 #将第二层的3改为5
print(a,b,c) # 此时b受到影响,变得和a值一样,c不受影响
print(id(a),id(b),id(c))
#改变第三层
a[2][2][0]='july' #将第三层'tom'改为'july'
print(a,b,c) #此时b受到影响,变得和a值一样,c照常不受影响
print(id(a),id(b),id(c))
输出结果
#最初结果:
[1, 2, [3, 4, ['tom', 'linda']]] [1, 2, [3, 4, ['tom', 'linda']]] [1, 2, [3, 4, ['tom', 'linda']]]
2911905060168 2911905061064 2911904581384
#改变第二层后的结果
[1, 2, [5, 4, ['tom', 'linda']]] [1, 2, [5, 4, ['tom', 'linda']]] [1, 2, [3, 4, ['tom', 'linda']]]
2911905060168 2911905061064 2911904581384
#改变第三层后的结果
[1, 2, [5, 4, ['july', 'linda']]] [1, 2, [5, 4, ['july', 'linda']]] [1, 2, [3, 4, ['tom', 'linda']]]
2911905060168 2911905061064 2911904581384