装饰器
在不改动源代码的情况下,给函数添加一个额外的功能
def fun():
def inner():
print("额外的功能")
return inner
@fun
def game():
print("这是函数原有的功能")
执行顺序
多个装饰器时:
从下向上
执行
def fun_1(fun):
def func(*args, **kwargs):
print("--我在函数内层--1, 额外的功能-1")
fun()
print("--我在外层")
return func
def fun_2(fun):
def func(*args, **kwargs):
print("--我是函数内层——2, 额外的功能--2")
fun()
print("--我在第二个装饰器外层")
return func
@fun_1
@fun_2
def func_for():
print("--我是第一个函数")
func_for()
# 我在第二个装饰器外层
# 我在外层
# 我在函数内层--1, 额外的功能-1
# 我是函数内层——2, 额外的功能--2
# 我是第一个函数
携带参数
当装饰器携带参数时,参数怎么用,怎么传,这里分不同情况
无参数的函数
from time import ctime
def time_fun(func):
def wrapped_func():
print("%s called at %s" % (func.__name__, ctime()))
func()
return wrapped_func
@time_fun
def foo():
print("I am foo")
foo()
# foo called at Sat Apr 4 17:50:03 2020
# I am foo
被装饰的函数有参数
from time import ctime
def time_fun(func):
def wrapped_func(a, b):
print("%s called at %s" % (func.__name__, ctime()))
print(a, b)
func(a, b)
return wrapped_func
@time_fun
def foo(a, b):
print(a + b)
foo(3, 5)
# foo called at Sat Apr 4 17:50:59 2020
# 3 5
# 8
被装饰的函数有不定长参数
from time import ctime, sleep
def time_fun(func):
def wrapped_func(*args, **kwargs):
print("%s called at %s" % (func.__name__, ctime()))
func(*args, **kwargs)
return wrapped_func
@time_fun
def foo(a, b, c):
print(a + b + c)
foo(3, 5, 7)
sleep(1)
foo(2, 4, 9)
# foo called at Sat Apr 4 17:53:31 2020
# 15
# foo called at Sat Apr 4 17:53:32 2020
# 15
装饰器中的return
from time import ctime, sleep
def time_fun(func):
def wrapped_func():
print("%s called at %s" % (func.__name__, ctime()))
func()
return wrapped_func
@time_fun
def foo():
print("I am foo")
@time_fun
def getInfo():
return '----hahah---'
foo()
sleep(2)
foo()
print(getInfo())
# foo called at Sat Apr 4 17:54:04 2020
# I am foo
# foo called at Sat Apr 4 17:54:06 2020
# I am foo
# getInfo called at Sat Apr 4 17:54:06 2020
# None
装饰器带参数,在原有装饰器的基础上,设置外部变量
from time import ctime, sleep
def time_fun_arg(pre="hello"):
def time_fun(func):
def wrapped_func():
print("%s called at %s %s" % (func.__name__, ctime(), pre))
return func()
return wrapped_func
return time_fun
# 下面的装饰过程
# 1. 调用time_fun_arg("spider")
# 2. 将步骤1得到的返回值,即time_fun返回, 然后time_fun(foo)
# 3. 将time_fun(foo)的结果返回,即wrapped_func
# 4. 让foo = wrapped_fun,即foo现在指向wrapped_func
@time_fun_arg("spider")
def foo():
print("I am foo")
@time_fun_arg("python")
def too():
print("I am too")
foo()
sleep(1)
foo()
too()
sleep(1)
too()
# foo called at Sat Apr 4 18:04:00 2020 itcast
# I am foo
# foo called at Sat Apr 4 18:04:02 2020 itcast
# I am foo
# too called at Sat Apr 4 18:04:02 2020 python
# I am too
# too called at Sat Apr 4 18:04:04 2020 python
# I am too
类装饰器
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s" % func.__name__)
self.__func = func
def __call__(self):
print("---装饰器中的功能---")
self.__func()
@Test
def test():
print("----test---")
# ---初始化---
# func name is test
# ---装饰器中的功能---
# ----test---
- 说明:
- 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
- 并且会把test这个函数名当做参数传递到__init__方法中
- 即在__init__方法中的属性__func指向了test指向的函数
- test指向了用Test创建出来的实例对象
- 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
- 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
- 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
- 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
评论区