装饰器模式可以以透明的方式动态的将功能添加到一个对象之中
可使用的场景:
可以用到装饰器的地方有很多,简单的举例如以下场景
- 引入日志
- 同击函数运行时间
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
例子
1 2 3 4 5 6 7 8 9 10 11
| def func(func): def print1(): print('装饰器进来了') func() return print1
@func def gointo(): print("gogogog")
gointo()
|
等价于
1 2 3 4 5 6 7 8 9 10 11
| def func(func): def print1(): print('这是装饰器里面') func() return print1
def gointo(): print("gogogog")
gointo = func(gointo) gointo()
|
使用装饰器装饰无返回值、无参数的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def func(func): def print1(): print('装饰器进来了') func() return print1
@func def gointo(): print("gogogog")
gointo()
>>>这是装饰器里面 >>>gogogog
|
使用装饰器装饰无返回值、有参数的函数
1 2 3 4 5 6 7 8 9 10 11 12
| def func(func): def print1(num): print('这是装饰器里面') func(num) return print1 @func def gointo(num): print("{}".format(num))
gointo(100) >>>这是装饰器里面 >>>100
|
使用装饰器装饰不定长参数的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def func(func): def print1(num,*args,**kwargs): print('这是装饰器里面') func(num,*args,**kwargs) return print1 @func def gointo(num,*args,**kwargs): print("{}".format(num)) print("{}".format(args)) print("{}".format(kwargs))
gointo(100,241,113,421,mama='lala') >>>100 >>>(241, 113, 'sfsa', 421) >>>{'mama': 'lala'}
|
通用装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def func(func): def print1(num,*args,**kwargs): print('这是装饰器里面') return func(num,*args,**kwargs) return print1 @func def gointo(num,*args,**kwargs): print("{}".format(num)) print("{}".format(args)) print("{}".format(kwargs)) return "ok"
s = gointo(100,241,113,'sfsa',421,mama='lala') print(s) >>>100 >>>(241, 113, 'sfsa', 421) >>>{'mama': 'lala'} >>>ok
|
使用多个装饰器装饰一个函数
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
| def func1(func): print('装饰器1') def print1(num,*args,**kwargs): print('这是装饰器里面1') return func(num*2,*args,**kwargs) return print1
def func2(func): print('装饰器2') def print1(num,*args,**kwargs): print('这是装饰器里面2') return func(num*3,*args,**kwargs) return print1
@func1 @func2 def gointo(num,*args,**kwargs): print("{}".format(num)) print("{}".format(args)) print("{}".format(kwargs)) return "ok"
s = gointo(100,241,113,'sfsa',421,mama='lala') print(s) 装饰器2 装饰器1 这是装饰器里面1 这是装饰器里面2 >>>600 >>>(241, 113, 'sfsa', 421) >>>{'mama': 'lala'} >>>ok
|
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
| def biggest(): def middle(mid): def small(*args,**kwargs): level = args[0] if level == 1: print("---一级警戒---") elif level == 2: print("---二级警戒---") return mid() return small return middle
@biggest() def run1(): print("---run1---") return "ok" @biggest() def run2(): print("---run2---") return "ok"
run1(1) run2(2) >>>---一级警戒--- >>>---run1--- >>>---二级警戒--- >>>---run2---
|
拓展:
funcyools
函数被装饰后函数名和属性已经改变,使用functools.wraps()来保留原有的函数属性和名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import functools def run(i): def wrapper(): return i() return wrapper
@run def test(): print('lala') return 'ok' if __name__ == "__main__": funcname = test() print(funcname) print("函数名称:{}".format(test.__name__)) >>>lala >>>ok >>>函数名称:wrapper
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import functools def run(i): @functools.wraps(i) def wrapper(): return i() return wrapper
@run def test(): print('lala') return 'ok' if __name__ == "__main__": funcname = test() print(funcname) print("函数名称:{}".format(test.__name__))
>>>lala >>>ok >>>函数名称:test
|
@staticmethod和@classmethod
在我们想使用某个类的方法时,一般需要实例化一个对象再通过对象调用方法,使用了@staticmethod和@classmethod之后,就省去了实例化生成对象的过程。有利于代码整洁、执行效率更高(类似c++里面的静态方法)。
@staticmethod
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
| class Single: __instance = None def __init__(self): print("__init__被执行啦")
@staticmethod def getinstance(): return '这是静态方法里面'
s = Single() print(s.getinstance()) print('------') print(Single.getinstance())
>>>__init__被执行啦 >>>这是静态方法里面 >>>------ >>>这是静态方法里面
|
@classmethod
与@staticmethod不同,该装饰器需要cls类参数,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class LOL(object): def __init__(self, name): self.name = name
def nuokesasi(self): print(self.name, '诺手') return 'ok1'
@classmethod def demaxiya(cls): print('盖伦') return 'ok2'
palyer = LOL('选择英雄:') print(palyer.nuokesasi(), palyer.demaxiya()) >>>选择英雄: 诺手 >>>盖伦 >>>ok1 ok2
|
使用@classmethod来装饰类方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class LOL(): def __init__(self, name): self.name = name
def nuokesasi(self): print(self.name, '诺手')
@classmethod def demaxiya(cls): print('盖伦')
LOL.demaxiya() LOL.nuokesasi()
>>>盖伦 >>>Traceback (most recent call last): >>> File "f:/pythonpachong/笔记/单例设计模式/测试代码.py", line 196, in <module> >>> LOL.nuokesasi() >>>TypeError: nuokesasi() missing 1 required positional argument: 'self'
|
@property
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class LOL(object): def __init__(self, name): self.__name = name
@property def demaxiya(self): return self.__name
@demaxiya.setter def demaxiya(self, value): self.__name = value
test = LOL(name='诺手') print(test.demaxiya) test.demaxiya = '德玛' print(test.demaxiya) >>>诺手 >>>德玛
|