慕课网课程笔记,网上文章总结
1.Python装饰器之函数作用域LEGB
LEGB(L>E>G>B):
- L:local 函数内部作用域(局部名字空间)
- E:enclosing 函数内部与内嵌函数之间(直接外围空间)
- G:global 全局作用域
- B:build-in 内置作用域
-- enclosing 作用域示例
def func(val):
-- 局部/内部作用域
passline = 90
def in_func():
-- val就是enclosing作用域
print(val)
in_func()
func(89)
总结:就近原则
2.Python装饰器之闭包
闭包:内部函数对enclosing作用域地变量进行引用。
简单点说,就是内部的函数调用外界的变量,外界的变量变了,内部的变量也就变了。我们要注意的就是返回和传入的对象,是函数,注意掌握变量的作用范围。(同时,为了在外部调用内部的函数,做法就是将内部函数返回。)
函数实质与属性:
- 函数是一个对象
- 函数执行完后内部变量回收
- 函数属性
- 函数返回值
--
passline= 68
def func(val):
-- 打印出val 空间值
print("%x"%id(val))
if val >= passline:
print('pass')
else:
print('failed')
def in_func(): # val会添加为函数in_func的属性
-- val就是enclosing作用域
print(val)
in_func()
-- 返回内部函数
return in_func
-- 将返回的内部函数变量赋给f
f = func(89)
-- 调用内部函数
f()
print(f.__closure__)
-- 打印结果
((int object at oxoooooo5FCCC1B0),)
89
89
((int object at oxoooooo5FCCC1B0),)
附注:从结果可以看出,引用的外部变量(val)会添加到函数的属性中。
def set_passline(passline):
def cmp(val): #外部变量passline会添加到函数cmp的属性中
if val>=passline:
print('pass')
else:
print('failed')
return cmp
func_100=set_passline(60)
func_150=set_passline(90)
func_100(89)
func_150(89)
-- 返回的是cmp函数,func_100=cmp,然后传值再比较
闭包作用:
- 封装
- 代码复用
-- 上面参数是数值/变量,如果是函数怎么样?
-- *arg表示可变长参数
def my_sum(*arg):
return sum(arg)
def my_average(*arg):
return sum(arg)/len(arg)
print(my_sum(1,2,3,4,5))
print(my_average(1,2,3,4,5))
-- 闭包
def my_sum(*arg):
return sum(arg)
def my_average(*arg):
return sum(arg)/len(arg)
def dec(func):
def in_dec(*arg): #my_sum、my_average作为func参数传入时,会成为in_dec函数的属性
if len(arg) == 0;
return 0
for val in arg:
if not ininstance(val,int)
return 0
# 这句话作用是对传入的arg,进行调用my_sum/my_average
return func(*arg)
return in_dec
my_sum = dec(my_sum) #此时返回的my_sum就是in_dec
my_sum(1,2,3,4,5)
my_average = dec(my_average) #此时返回的my_a verage就是in_dec
my_average(1,2,3,4,5)
闭包的作用:在函数中定义一个函数并返回该函数自身,用来处理数据。。
3.Python装饰器
装饰器:
- 装饰器用来装饰函数
- 返回一个函数对象
- 被装饰函数标识符 指向 返回的函数对象(例如@dec返回的in_dex,使得my_sum=in_dec)
- 语法糖 @deco
装饰器实质就是对闭包的一个使用。
-- 装饰器(就是对闭包的一种使用)
def dec(func):
print('call dec')
def in_dec(*arg): #my_sum、my_average作为func参数传入时,会成为in_dec函数的属性
print('in dec arg=', arg)
if len(arg) == 0;
return 0
for val in arg:
if not ininstance(val,int)
return 0
return func(*arg)
return in_dec
@dec
def my_sum(*arg):
return sum(arg)
-- 输出结果
call dec
@dec
def my_sum(*arg):
print('in my_sum')
return sum(arg)
print(my_sum(1,2,3,4,5))
--输出结果
call dec
in dec arg = (1,2,3,4,5)
in my sum
15
装饰器自动执行@dec,调用dec这个函数,返回函数in_dec
,被函数my_sum
接收。
@dec 对应 dec(my_sum)
,返回函数in_dec
然后,此时my_sum = in_dec
,相对于上一节 my_sum = dec(my_sum)
然后此时my_sum()
就是调用内部函数in_dec()
,然后顺序执行,in_dec()内部的return func()
其中就是func()就是my_sum()
,因为函数调用时候my_sum()
作为in_dec()
一个属性保存了。
为什么要有return func(*arg)
?
因为装饰器存在的目的是为本来要进行的函数(sum,average)进行包装,包装的意思一方面是多进行一些操作,另一方面是对一些函数具有想同逻辑的进行抽象,如果没有return操作,那就是包装袋里没有实物,就失去了本来的意义。
装饰器另一简单示例(基础示例,对于理解装饰器很有用):
def deco(func):
def in_dec0():
print ('in deco')
func()
print('call deco')
return in_deco
@deco
def bar():
print('in bar')
-- 输出结果
call deco
# 调用返回的bar()
bar()
-- 输出结果
in deco
in bar
函数运行过程如下:
可以看看这篇文章:https://blog.csdn.net/dreamcoding/article/details/8611578
def deco(func):
def in_dec0(x,y):
print ('in deco')
func(x,y)
print('call deco')
return in_deco
@deco
def bar(x,y):
print('in bar',x+y)
# 调用
bar(1,2)
-- 输出结果
in deco
in bar 3
第一步:deco(bar),返回一个对象in_deco
第二步:重新赋值 bar = in_deco
第三步:调用bar()时,实际上是调用in_deco()
,in_deco()
处理时有用到bar()函数