1、装饰器定义
函数本身也是对象,能赋值给变量,通过变量名称可以调用函数的功能。此外能通过__name__
属性拿到函数的名称。
1 2 3 4 5 6 def fun1 (): print ("fun1" ) f1 = fun1 f1.__name__
装饰器是在不改变原函数条件下,为原函数调用前增加新的功能。装饰器其实是一个高阶函数,高阶函数hightfunc
接受一个函数对象func
,在高阶函数内部定义一个新的函数wrapper
,新的函数wrapper
在调用func
函数对象前后执行一定的操作,之后返回func
,整个告诫高阶函数再返回wrapper
1 2 3 4 5 6 7 8 9 10 def log (func ): def wrapper (): print (f"call {func.__name__} " ) return func return wrapperdef fun1 (): print ("fun1" ) log(fun1)()
写成语法糖的形式
1 2 3 4 5 6 7 8 9 10 11 def log (func ): def wrapper (): print (f"call {func.__name__} " ) return func return wrapper@log def fun1 (): print ("fun1" ) fun1()
2、装饰器有参函数无参
使用装饰器时,传入变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import loggingdef log (level='debug' ): def decorator (func ): def wrapper (): func() if level == 'warning' : logging.warning("{} is called" .format (func.__name__)) else : logging.debug("{} is called" .format (func.__name__)) return func return wrapper return decorator@log(level="warning" ) def func (): print ("func()调用了" ) func()
3、装饰器和函数均有参
需要使用*args, **kwargs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import loggingdef log (level='debug' ): def decorator (func ): def wrapper (*args, **kwargs ): ret = func(*args, **kwargs) if level == 'warning' : logging.warning("{} is called" .format (func.__name__)) else : logging.debug("{} is called" .format (func.__name__)) return ret return wrapper return decorator@log(level="warning" ) def func (n,m ): print (f"from func(), n={n} ,m={m} " ) func(0 ,2 )
对于*args, **kwargs
我了解的还不多,这里不做过多介绍。
*args (Non-Keyword Arguments)
相当于列表['Hello'``, ``'Welcome'``, ``'to'``, ``'GeeksforGeeks']
**kwargs (Keyword Arguments)
相当于字典{first='Geeks', mid='for', last='Geeks'}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 list = ["apple" ,"banana" ,"Pomelo" ]def func (*argv ): for arg in argv: print (arg+" " ) func(*list ) dic = {"1" :"apple" ,"2" :"banana" ,"3" :"Pomelo" }def func (**kwargs ): for key,value in kwargs.items(): print (key+"=" +value) func(**dic)list = ["apple" ,"banana" ,"Pomelo" ] dic = {"1" :"apple" ,"2" :"banana" ,"3" :"Pomelo" }def func (*argv,**kwargs ): for arg in argv: print (arg+" " ) for key,value in kwargs.items(): print (key+"=" +value) func(*list ,**dic)
4、类方法装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import timedef decorator (func ): def wrapper (self, *args, **kwargs ): start_time = time.time() ret = func(self, *args, **kwargs) end_time = time.time() print ("%s.%s() cost %f second!" % (self.__class__, func.__name__, end_time - start_time)) return ret return wrapperclass TestDecorator (): @decorator def mysleep (self, n ): time.sleep(n) obj = TestDecorator() obj.mysleep(1 )
5、装饰器类
会调用__init__
和__call__
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Tracer (): def __init__ (self, func ): self.func = func self.calls = 0 def __call__ (self, *args, **kwargs ): self.calls += 1 print ("call %s() %d times" % (self.func.__name__, self.calls)) return self.func(*args, **kwargs)@Tracer def test_tracer (val, name="default" ): print ("func() name:%s, val: %d" % (name, val))for i in range (2 ): test_tracer(i, name=("name" + str (i))) >>> call test_tracer() 1 times func() name:name0, val: 0 call test_tracer() 2 times func() name:name1, val: 1
6、 带参数装饰器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Tracer (): def __init__ (self, arg0 ): self.arg0 = arg0 self.calls = 0 def __call__ (self, func ): def wrapper (*args, **kwargs ): self.calls += 1 print ("arg0:%d call %s() %d times" % (self.arg0, func.__name__, self.calls)) return func(*args, **kwargs) return wrapper@Tracer(arg0=0 ) def test_tracer (val, name="default" ): print ("func() name:%s, val: %d" % (name, val))for i in range (2 ): test_tracer(i, name=("name" + str (i))) >>> arg0:0 call test_tracer() 1 times func() name:name0, val: 0 arg0:0 call test_tracer() 2 times func() name:name1, val: 1
7、内置装饰器
7.1 staticmethod
类的静态函数装饰器,可通过类名直接调用
1 2 3 4 5 6 7 8 9 10 11 12 13 class C (): @staticmethod def static_method (): print ("This is a static method!" ) C.static_method() c = C() c.static_method() >>> This is a static method! This is a static method!
7.2 classmethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class C (): @classmethod def class_method (cls ): print ("This is " , cls)class B (C ): pass C.class_method() c = C() c.class_method() B.class_method() >>> This is <class '__main__.C' > This is <class '__main__.C' > This is <class '__main__.B' >