我饿了,你分给我一半面包,这是朋友。你只吃了一口,剩下的面包全给了我 ,这是爱情。你一口没吃,直接把面包给了我 ,这是父母。 所以请珍惜友情、爱情、亲情,没有谁对谁是应该的。要学会感恩知足!懂得珍惜,才会拥有!
Python 是一种对新手很友好的语言。但是,它也有很多较难掌握的高级功能,比如装饰器(decorator)。
如果前面基础知识掌握比较牢固的话,装饰器迎刃而解,没有什么特别难的地方,只需要几个简单的转化、等价,很容易理解装饰器;
在 Python 中,函数是一种非常灵活的结构,我们可以把它赋值给变量、当作参数传递给另一个函数,或者当成某个函数的输出。装饰器本质上也是一种函数,它可以让其它函数在不经过修改的情况下增加一些功能。
Python之装饰器
本章总结:
- 硬编码:死死的写到函数中的,
- 函数传的参数是否符合上面函数定义的要求,那是在调用时候后的问题;
- def logger(fn, *args, *kwargs): # 形参定义 与 ret = fn(args, **kwargs) # 参数解构 区别 ;参数-正不正确由核心代码判断;
- add = logger(add) add赋值重新定义,记录的是inner函数对象,inner传4,5;调用fn() 实质是记录原来的add(4,5)函数;fn用到了外部变量fn,相当于闭包的特性(记录add的引用,尽管add被重新定义);
装饰器(decorator)
动态附加功能的解决方案:
示例1:
业务核心的代码功能+\-
def add(x,y): # z = f(x,y)
return x+y
def sub(x,y):
return x-y
def a(x,y,z):
pass
def b(m,n,*args,x,y,**kwargs):
pass
只关注 附加功能——print 的函数定义;记录函数参数,并不关注函数是否能运行;
def logger(fn,x,y): #位置参数和关键字参数分开;
print("call function {}. x={}, y={}".format(fn.__name__, x, y))
ret = fn(x,y)
return ret
def logger(fn, *args, **kwargs): # 形参定义
print("call function {}. x={}, y={}".format(fn.__name__, *args, **kwargs))
ret = fn(*args, **kwargs) # 参数解构
return ret
print('result = {}'.format(logger(add,4,5))) #add(4,5)
print('result = {}'.format(logger(b,4,5,6,7,x=10,y=13))) # b(4,5,6,7,x=10,y=13)
def add(x,y): # z = f(x,y)
return x+y
示例2:柯里化之后,变成了2层函数;
# def logger(fn,x,y): #位置参数和关键字参数分开;
# print("call function {}. x={}, y={}".format(fn.__name__, x, y))
# ret = fn(x,y)
# return ret
def logger(fn):
def inner(*args,**kwargs):
print("call function {}. x={}, y={}".format(fn.__name__, *args, **kwargs))
ret = fn(*args, **kwargs)
return ret
return inner
logger(add,4,5)
logger(add)(4,5)
fn = logger(add)
ret = add(4, 5)
print(ret)
# add赋值重新定义,记录的是inner函数对象,inner传4,5;调用fn() 实质是记录原来的add(4,5)函数;fn用到了外部变量fn,相当于闭包的特性;(记录add的引用,尽管add被重新定义);
add = logger(add) #inner 原来的add消失了吗?
ret = add(4,5)
----------------------------------------
call function add. x=4, y=5
9
最终形态——装饰器:
def logger(fn):
def inner(*args,**kwargs):
print("call function {}. x={}, y={}".format(fn.__name__, *args, **kwargs))
ret = fn(*args, **kwargs) # 解构,闭包(内外层函数的变量;)
return ret
return inner
@logger # 等价为 add = logger(add) =》 add=inner
#@logger # 注释后相当于一个附加功能消失;
def add(x,y): # z = f(x,y)
return x+y
ret = add(4, 5) # 开始调用;ret=inner(4,5)
print(ret)
--------------------------------------------------
call function add. x=4, y=5
装饰器总结:
1. @logger 新语法的能力:就是将下面的标识符add作为参数传进来;
logger 包装 add ;
def logger(fn):
def wrapper(*args,**kwargs):
print("call function {}. x={}, y={}".format(fn.__name__, *args, **kwargs))
ret = fn(*args, **kwargs) # 解构,闭包(内外层函数的变量;)
return ret
return wrapper
@logger # 等价为 add = logger(add)
def add(x,y): # z = f(x,y)
return x+y
ret = add(4, 5) # inner(4,5)
print(ret)
--------------------------------------------------------------------------------
call function add. x=4, y=5
9
有关装饰器的4个函数核心概念
1. 在Python语言中,函数也是对象,因此可以用一个变量指向函数。示例如下:
def func(param):
print('param is : {}'.format(param))
variable = func
variable('函数赋予变量')
# console
param is : 函数赋予变量
2. 函数可作为入参传递给另一个函数。示例如下:
def func(param):
print('param is : {}'.format(param))
def call(function, param):
function(param)
call(func, '函数作为入参')
#console
param is : 函数作为入参
3. 函数可以嵌套。示例如下:
def func(param):
def inner_func(param):
print('param is : {}'.format(param))
return inner_func(param)
print(func('函数嵌套'))
# console
param is : 函数嵌套
None
当里面的函数没有return时,运行结果为None。代码如下:
def func(param):
def inner_func(param):
print('param is : {}'.format(param))
print(func('函数嵌套'))
# console
None
4. 函数的返回值可以是函数对象。不是内层函数对象的最终返回结果;
def func():
def inner_func(param):
print('param is : {}'.format(param))
return inner_func
res = func()
res('返回函数对象')
print(func())
# console
param is : 返回函数对象
<function func.<locals>.inner_func at 0x10404dcb0>
网友评论