装饰器
1.装饰器
- 再不修改被装饰对象的源代码和调用方式的的前提下为装饰对象添加额外的功能
1.1装饰器分类
- 分为无参装饰器和有参装饰器
- 无参装饰器
# 无参装饰器模版
def outer(func):
def inner():
'''这里写调用 func 函数之前的逻辑'''
res = func()
'''这里写调用 func 函数之后的逻辑'''
return res
return inner
# 语法糖调用
@outer
def add():
return 1
# 变量赋值调用
add = outer(add)
add()
# 示例
login_user_dict = {'username': 'serein', 'is_admin': True}
user_data_dict = {'serein': {'password': 521, 'role': 'admin'},
'formerly': {'password': 369, 'role': 'normal'}}
def check_admin(func):
def inner():
if login_user_dict['username'] and login_user_dict["is_admin"]:
res = func()
return res
else:
return False,"登陆失败"
return inner
@check_admin
def get_money():
return True,"取款成功"
# 第一种调用方法
# 调用check_admin方法,传入参数get_money
get_money = check_admin(get_money)
get_money() # get_money加()执行inner方法
print(get_money) # 取款成功
# 第二种方法,语法糖,在get_money方法上面加@check_admin
get_money()
- 有参装饰器
# 有参数 装饰器模版
def wrapper_func(tag):
def wrapper(func):
def inner(*args, **kwargs):
# tag : 表明当前需要处理的使用函数的逻辑
if tag == None:
...
# 正常函数内需要的逻辑
return func(*args, **kwargs)
return inner
return wrapper
@wrapper_func(tag=None)
def add():
# 案例1 有参数多个装饰器语法糖叠加使用
user_data = {'username': 'serein', 'password': '521'}
bank_data = {'serein': {'pay_pwd': '521', 'balance': 1000}}
# 先验证登录
def login_auth(func):
def inner(*args, **kwargs):
if user_data['username'] and user_data['password'] == "521":
res = func(*args, **kwargs)
return res
else:
return False, "未登陆"
return inner
# 再验证 输入的金额 ---l 符合数字 / 余额充足
def check_balance(func):
def inner(*args, **kwargs):
name = input("请输入姓名:》》").strip()
balance = input("请输入金额 :>>>> ").strip()
pay_pwd = input("请输入取款密码:》》》").strip()
if not balance.isdigit():
return False, "非法输入"
balance = int(balance)
if balance > bank_data[name]['balance']:
return False, "余额不足"
if pay_pwd != bank_data[name]['pay_pwd']:
return False, "取款密码错误"
return func(name=name, balance=balance, pay_pwd=pay_pwd, *args, **kwargs)
return inner
def add_balance(func):
def inner(*args, **kwargs):
name = input("请输入姓名:》》").strip()
password = input("请输入登陆密码:")
balance = input("请输入充值金额 :>>>> ").strip()
if not balance.isdigit():
return False, "请输入数字金额"
return func(name=name, password=password, balance=balance, *args, **kwargs)
return inner
# # 取款函数里面
@login_auth
@check_balance
def get_balance(*args, **kwargs):
print(kwargs)
name = kwargs.get('name')
balance = kwargs.get('balance')
bank_data[name]['balance'] -= balance
print(bank_data)
@login_auth
@add_balance
def add_balance(*args, **kwargs):
print(kwargs)
name = kwargs.get('name')
balance = kwargs.get('balance')
balance = int(balance)
bank_data[name]['balance'] += balance
print(bank_data)
add_balance()
# 案例2,有参数合并装饰器,语法糖叠加使用
user_data = {'username': 'serein', 'password': '521'}
bank_data = {'serein': {'pay_pwd': '521', 'balance': 1000}}
# 合并装饰器
def Decorator(tag_func=None, tag=None):
# tag-func = login 走登陆装饰器
if tag_func == 'login':
def wraper(func):
def inner(*args, **kwargs):
if user_data['username'] and user_data['password'] == "521":
return func(*args, **kwargs)
return False, "未登陆"
return inner
return wraper
elif tag_func == "balance":
def wraper(func):
def inner(*args, **kwargs):
name = input("请输入用户名")
balance = input("请输入金额")
balance = int(balance)
pay_pwd = ''
if tag != "add_balance":
pay_pwd = input("请输入密码:")
if pay_pwd != bank_data[name]['pay_pwd']:
return False, "密码错误"
if balance > bank_data[name]['balance']:
return False, '余额不足'
return func(name=name, balance=balance, pay_pwd=pay_pwd, *args, **kwargs)
return inner
return wraper
# 取钱
@Decorator(tag_func='login')
@Decorator(tag_func='balance', tag='get_balance')
def get_balance(*args, **kwargs):
print(kwargs)
name = kwargs.get('name')
balance = kwargs.get('balance')
bank_data[name]['balance'] -= balance
print(bank_data)
# 存钱
@Decorator(tag_func='login')
@Decorator(tag_func='balance', tag='add_balance')
def add_balance(*args, **kwargs):
print(kwargs)
name = kwargs.get('name')
balance = kwargs.get('balance')
balance = int(balance)
bank_data[name]['balance'] += balance
print(bank_data)
print(get_balance())
1.2 伪装装饰器
1.2.1查看装饰器(help)
-
可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的doc属性
- 但对于被装饰之后的函数,查看文档注释
import time
# 定义外层函数
def wrapper(func):
# 定义内层函数:通过参数接收外部的值
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
return inner
@wrapper
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page', name)
print(help(home))
'''
打印结果:
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
None
'''
- 在被装饰之后home=wrapper
- 查看home.name也可以发现home的函数名确实是wrapper
- 想要保留原函数的文档和函数名属性,需要修正装饰器
import time
# 定义外层函数
def wrapper(func):
# 定义内层函数:通过参数接收外部的值
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
inner.__doc__ = func.__doc__
inner.__name__ = func.__name__
return inner
@wrapper
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page', name)
print(help(home))
'''
打印结果:
Help on function home in module __main__:
home(*args, **kwargs)
home page function
:param name: str
:return: None
None
'''
1.2.2 伪装装饰器
- functools模块下提供一个装饰器wraps专门用来帮我们实现这件事
import time
from functools import wraps
# 定义外层函数
def wrapper(func):
# 伪装内层函数
@wraps(func)
# 定义内层函数:通过参数接收外部的值
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
return inner
@wrapper
def home(name):
'''
home page function
:param name: str
:return: None
'''
time.sleep(5)
print('Welcome to the home page', name)
print(help(home))
'''
打印结果:
Help on function home in module __main__:
home(name)
home page function
:param name: str
:return: None
None
'''
标签:return,name,func,kwargs,balance,装饰,def
From: https://www.cnblogs.com/Formerly/p/17902011.html