什么是装饰器?---python中的装饰器是指任何可以修改函数或类的可调用对象。 当一个函数或类被调用时,它被传递给装饰器,装饰器返回一个修改过的函数/类。
先看几个实例,了解python函数的一些特点。
实例1:
def first_func(value): # 测试函数 print(value) new_name = first_func # python中函数可以有多个名称,还可以将函数分配给一个或多个变量 first_func('午餐肉') # 函数名调用 new_name('火腿') # 函数别名调用
结果为:
午餐肉
火腿
实例2:可以使用python内置的函数如map和filter来实现:
def mult(x, y):return x * y # 返回x,y乘积 def div(x, y): return x / y # 返回x,y相除 def math(func, x, y): result = func(x, y) # 把x,y通过func函数进行处理,函数名可以作为参数传递 return result print(math(mult, 4, 2)) print(math(div, 4, 2))
结果:
8 2.0
实例3:函数可以嵌套在其他函数中:
def person(name): def greetting(): return "你好,我在和你打招呼," greet = greetting() + name + "!" # 调用内部函数greetting和参数name及“!”组合 return greet print(person('小强'))
你好,我在和你打招呼,小强!
实例4:函数可以作为其他函数的参数(因为函数是对象,因此可以用作参数。python一切皆对象):
def greeting(name): return '唐' + name def call_me(func): # 接收其他函数作为参数 nickname = '伯虎' return func(nickname) print(call_me(greeting))
唐伯虎
实例5:函数可以返回函数:
def func_1(): def saying(): return '发生什么事了?' return saying a = func_1() print(a()) # 这里注意,是a()而不是a;a是返回的函数名,a()执行内部函数
发生什么事了?
实例6:嵌套函数可以访问其父函数的作用域,这称为闭包。必须注意,这种访问是只读的。嵌套函数不能改变外部作用域。
def func_1(name): def greeting(): return '你好,我是' + name return greeting greet = func_1('马保国') print(greet())
你好,我是马保国
试着改变父函数作用域的值,报错,因为输入的函数func_2只是其传递给greeting函数,并不是变量:
def func_2(name): test=100 def greeting(): test +=100 return '你好,我是' + name return greeting greet = func_2('马保国') print(greet())
G:\pyprojects\python.exe G:/pyprojects/hello.py Traceback (most recent call last): File "G:/pyprojects/hello.py", line 17, in <module> print(greet()) File "G:/pyprojects/hello.py", line 12, in greeting test +=100 UnboundLocalError: local variable 'test' referenced before assignment Process finished with exit code 1
有以上基础,即可以讨论装饰器了。
装饰器将一个函数包装在另一个函数中,该函数以某种方式修改原始函数,如添加功能、修改参数或结果等等。
装饰器主要工作是在其中定义wrapper函数。wrapper英文意思为包装纸,包装材料。形象的描述。
wrapper()函数是一个嵌套的函数,进行实际执行修改工作,尽管调用的是装饰器的名称。
def fun_decorator(func): # 装饰器函数 def wrapper(): # 实际工作区 print("这里是装饰器进行装饰的功能区域") for i in range(10): print(i) print('装饰结束,返回原功能') print(func()) return wrapper def test(): # 测试函数,测试装饰器功能 text = "我是马保国,浑元形意门掌门人" return text test = fun_decorator(test) # 通过此句test已经被fun_decorator装饰 test() # 调用,查看结果
结果:
G:\pyprojects\venv\Scripts\python.exe G:/pyprojects/hello.py 这里是装饰器进行装饰的功能区域 0 1 2 3 4 5 6 7 8 9 装饰结束,返回原功能 我是马保国,浑元形意门掌门人 Process finished with exit code 0
查看结果可知,原简单的test函数,确实被增加了功能。
其实可以通过语法糖@,来替代行:test = fun_decorator(test)的功能。
语法糖是指:编程语言中一种特殊的语法,旨在通过其使代码更易于读写,令程序员更加轻松。
def fun_decorator(func): # 装饰器函数 def wrapper(): # 实际工作区 print("这里是装饰器进行装饰的功能区域") for i in range(10): print(i) print('装饰结束,返回原功能') print(func()) return wrapper @fun_decorator def test(): # 测试函数,测试装饰器功能 text = "我是马保国,浑元形意门掌门人" return text test() # 调用,查看结果
运行后结果一致。所以只需在待测试函数上一行加 @装饰器函数,就可达到目的。
装饰器的工作原理:当一个带有修饰器的函数被调用时,装饰器函数会捕捉这个调用,执行其工作。完成装饰器函数的工作后,移交给原始函数,从而进行后续任务。从本质上说,
装饰器劫持了函数调用,修改原始的结果,并将修改结果替换为原始函数提供的结果。
如果一个被修饰后的函数被赋值给一个变量,那么这个变量每次可以用被修饰后的函数功能,而不是原始的函数。
装饰器显然可以应用到多个函数中去,实现复用的功能。否则还不如直接将功能写入某个函数中。
综合实例:
import math def arg_check(func): def wrapper(num): # 通过装饰器来实现判断参数合法性 if type(num) != int: raise TypeError('参数不是整数!') elif num <= 0: raise ValueError('参数不是正数!') else: return func(num) return wrapper @arg_check def circle_measures(radius): # 给出半径算出圆属性 zhouchang = 2 * math.pi * radius # 圆周长 area = math.pi * radius * radius # 圆面积 zhijing = 2 * radius # 直径 return (zhijing, zhouchang, area) a, b, c = circle_measures(6) print('直径为:', a, '\n周长为:', b, '\n面积为:', c)
结果:
G:\pyprojects\venv\Scripts\python.exe G:/pyprojects/zhuangshiqi.py 直径为: 12 周长为: 37.69911184307752 面积为: 113.09733552923255 Process finished with exit code 0
# 装饰器检查值是否为整数,是否为正数,如果满足要求,允许函数完成,否则报错
浙公网安备 33010602011771号