装饰器语法糖运用
前言:函数名是一个特性的变量,可以作为容器的元素,也可以作为函数的参数,也可以当做返回值。
闭包定义:
内层函数对外层函数(非全局)变量的引用,这个内层函数就可以成为闭包
在Python中我们用
__closure__
来检查函数是否是闭包def func1():name = '张三'def func2():print(name) # 能够访问到外层作用域的变量func2()print(func2.__closure__) # (<cell at 0x1036c7438: str object at 0x10389d088>,)func1() print(func1.__closure__) # None
装饰器
前言:软件设计原则:开闭原则,又称开放封闭原则
- 指对扩展代码的功能是开放的,但对修改源代码是封闭的,
def create_people():print('女娲真厉害,捏个泥吹口气就成了人!')def a(func):def b():print('洒点水')func()return bret = a(create_people) ret()
通过装饰器语法等同于
def a(func):def b():print('洒点水')func()return b@a # 装饰器语法糖的作用就是上述函数ret() def create_people():print('女娲真厉害,捏个泥吹口气就成了人!')create_people()
装饰带返回值的函数,即return出被装饰函数的执行结果
def foo(func): # 接收的参数是一个函数名def bar(): # 定义一个内层函数print("这里是新功能...") # 新功能r = func() # 在内存函数中拿到被装饰函数的结果return r # 返回被装饰函数的执行结果return bar# 定义一个有返回值的函数 @foo def f1():return '嘿嘿嘿'# 调用被装饰函数 ret = f1() # 调用被装饰函数并拿到结果 print(ret)
装饰带参数的函数
def func1(func): # 接收的参数为一个函数名def inner(*args, **kwargs): # 这里需要定义和被装饰函数相同的参数print("新功能") # 新功能ret = func(*args, **kwargs) #被装饰的函数和参数print("新功能") return retreturn inner# 定义一个需要俩个参数的函数 @func1 def func(a, b):return a + bret = func(3, 5) print(ret)
带参数的装饰器 即在装饰器外在写一层函数,从而使其带参数
def d(a=None): # 定义一个外层函数,给装饰器传参数def func1(func): # 接收的是一个函数名def inner(*args, **kwargs): # 被装饰的函数,和参数if a:print(f"欢迎来到{a}") #添加新功能else:print("欢迎来到王者荣耀") func(*args, **kwargs)return innerreturn func1# @d("英雄联盟") # def func(st): # print(st) # func("敌军还有三十秒到达战场")# 欢迎来到英雄联盟# 敌军还有三十秒到达战场@d() def func(st):print(st) func("敌军还有三十秒到达战场") # 欢迎来到王者荣耀 # 敌军还有三十秒到达战场
装饰器修复技术
定义:被装饰的函数最终都会失去本来的__doc__等信息, Python给我们提供了一个修复被装饰函数的工具。
from functools import wraps #导入 print(f1.__doc__) print(f1.__name__)
多个装饰器装饰同一函数
from functools import wrapsdef wrapper2(func):@wraps(func)def inner(*args, **kwargs):r = func(*args, **kwargs)return f"<2>{r}</2>"return innerdef wrapper1(func):@wraps(func)def inner(*args, **kwargs):r = func(*args, **kwargs)return f"<1>{r}</1>"return inner@wrapper2 @wrapper1 def func(a):return aprint(func("Hello World!!")) #<2><1>Hello World!!</1></2>
def foo1(func):print("d1")def inner1():print("inner1")return "<i>{}</i>".format(func())return inner1def foo2(func):print("d2")def inner2():print("inner2")return "<b>{}</b>".format(func())return inner2@foo1 @foo2 def f1():return "Hello Andy"# f1 = foo2(f1) ==> print("d2") ==> f1 = inner2 # f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1ret = f1() # 调用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i> print(ret)
类装饰器
class D(object):def __init__(self, a=None):self.a = aself.mode = "装饰"def __call__(self, *args, **kwargs):if self.mode == "装饰":self.func = args[0] # 默认第一个参数是被装饰的函数self.mode = "调用"return self# 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)if self.a:print("欢迎来到{}页面。".format(self.a))else:print("欢迎来到首页。")self.func(*args, **kwargs)@D() def index(name):print("Hello {}.".format(name))@D("电影") def movie(name):print("Hello {}.".format(name))if __name__ == '__main__':index('张三')movie('张三')
装饰类
# 定义一个类装饰器 class D(object):def __call__(self, cls):class Inner(cls):# 重写被装饰类的f方法def f(self):print('Hello 张三.')return Inner@D() class C(object): # 被装饰的类# 有一个实例方法def f(self):print("Hello world.")if __name__ == '__main__':c = C()c.f()