装饰器:以某种方式增强函数。
两大特性:1、可以将被装饰的函数替换成其他函数。
2、在加载模块时立即执行。
案例1
def make_avarage():
count=0
total=0
def averager(new_value):
count+=1
total+=new_value
return total/count
return averager
这里会报错,averager里面是一个新的 count、total变量
案例2
使用nolocal作用:将变量标记为自由变量,
def make_avarage():
count=0
total=0
def averager(new_value):
nonlocal count,total
count+=1
total+=new_value
return total/count
return averager
案例3
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sun May 3 23:27:22 2020 @author: root """ promos=[] def promotion(promo_func): promo.append(promo_func) return promo_func @promotion def FidelityPromo(order): return order.total()*0.05 if order.customer.fidelity>=1000 else 0 @promotion def BulkItemPromo(order): discount = 0 for item in order.cart: if item.quantity>=20: discount+=item.total()*0.1 return discount @promotion def LargeOrderPromo(order): discount_items = {item.product for item in order.cart} if len(discount_items)>=10: return order.total()*0.07 return 0 def best_promo(order): return max(promo(order) for promo in promos)
二、@property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用
#@ property
#将一个方法伪装成属性,被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式,实现一个实例属性的
getter
setter
d elete
三种方法的内部逻辑,具体含义看示
class Data: def __init__(self): self.number = 123 @property def operation(self): return self.number
@operation.getter
def operation(self):
return self.number @operation.setter def operation(self, number): self.number = number @operation.deleter def operation(self): del self.number
案例1----普通写法
class Student(object):
def get_score(self):
return self._score
def set_score(self,value):
if not isinstance(value,int):
raise ValueError('pppppp')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
Python内置的@property装饰器就是负责把一个方法变成属性调用
案例1----装饰器写法
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('pppppp')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
s=Student()
s.score=60
s.score=9999
print (s.score)
三、类装饰器:类装饰器使用地方较少,核心是通过复写类的回调方法call.
装饰器应用场景:
1、引入日志
2、函数执行时间统计
3、执行函数前预备处理
执行函数后清理功能
权限校验等场景
缓存
方法:__call__
__call__ 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
class Add:
def __init__(self, fn):
print("初始化")
self.num = 44
self.fn = fn
def __call__(self, *args, **kwargs
):
print("类装饰器开始工作")
return self.fn(self.num)
@Add
def test(n):
return 4+n
if __name__ == '__main__':
num = test()
print(num)
结果:
初始化
<function test at 0x7f95f883bc20>
类装饰器开始工作
44
48
<function test at 0x7f95f883bc20>
类装饰器开始工作
44
48
案例1
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon May 4 22:11:44 2020 @author: root 简单注册表 """ funcs = [] def register(func): funcs.append(func) return func @register def a(): return 3 @register def b(): return 5 def c(): return 8 # 访问结果 result = [func() for func in funcs] print(funcs) print(result) # [<function a at 0x7f95f8837050>, <function b at 0x7f95f8837290>] # [3, 5]
案例2
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May 4 22:14:37 2020
@author: root
注册表隔离(使用类的不同实例)
"""
class Registry(object):
def __init__(self):
self._funcs=[]
def register(self,func):
self._funcs.append(func)
def run_all(self):
return [func() for func in self._funcs]
r1=Registry()
r2=Registry()
@r1.register
def a():
return 3
@r2.register
def b():
return 5
案例3
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon May 4 22:30:41 2020 @author: root 用户验证 """ from functools import wraps class User(object): def __init__(self, username, email): self.username = username self.email = email class AnonymousUser(object): def __init__(self): self.username = self.email = None def __nonzero__(self): # 将对象转换为bool类型时调用 return False def requires_user(func): @wraps(func) def inner(user, *args, **kwargs): # 由于第一个参数无法支持self, 该装饰器不支持装饰类 if user and isinstance(user, User): return func(user, *args, **kwargs) else: raise ValueError("非合法用户") return inner a=User('teddy', '120@163.com') print (a)
案例3
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon May 4 22:36:47 2020 @author: root 异常捕获 """ import json from functools import wraps class Error1(Exception): def __init__(self, msg): self.msg = msg def __str__(self): return self.msg def json_output(func): @wraps(func) def inner(*args, **kwargs): try: result = func(*args, **kwargs) except Error1 as ex: result = {"status": "error", "msg": str(ex)} return json.dumps(result) return inner # 使用方法 @json_output def error(): raise Error1("该条异常会被捕获并按JSON格式输出")
案例3
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon May 4 22:40:47 2020 @author: root 日志管理 "" import time import logging from functools import wraps def logged(func): @wraps(func) def inner(*args, **kwargs): # *args可以装饰函数也可以装饰类 start = time.time() result = func(*args, **kwargs) exec_time = time.time() - start logger = logging.getLoger("func.logged") logger.warning("{} 调用时间:{:.2} 执行时间:{:.2}s 结果:{}".format(func.__name__, start, exec_time, result))
资源清理#import pymysql class DBConnection(object): def __init__(self, *args, **kwargs): self.args,self.kwargs = args, kwargs def __enter__(self): self.conn = pymysql.connect(*args, **kwargs) return self.conn.cursor() def __exit__(self, exc_type, exc_instance, trackback): self.conn.close()
案例来源:https://www.cnblogs.com/superhin/p/11454823.html