4.5 Python3 进阶 - 闭包 & 装饰器
>>返回主目录
源码
# 闭包应用:计数器
def counter():
numbers = [0]
def add_one():
numbers[0] += 1
print(f'第{numbers[0]}次调用')
return add_one
count1 = counter() # 调用外函数
count1() # 调用count1的闭包函数
count1()
count2 = counter()() # 直接调用外函数的闭包函数
count1()
源码
# 闭包函数,同级之间可以互相进行访问,例如:
def out_fun(num1, num2):
num3 = 10
def inner_fun_1(num4):
num5 = 20
sum_nums = num1 + num2 + num3 + num4 + num5
print('所有数字相加后的结果是:', sum_nums)
def inner_fun_2(num):
inner_fun_1(num)
return inner_fun_2
sum_total_1 = out_fun(1, 2) # 调用out_fun装饰器,返回inner_fun_2赋值给变量sum_total_1
sum_total_2 = out_fun(10, 20) # 调用out_fun装饰器,返回inner_fun_2赋值给变量sum_total_2
sum_total_1(3)
sum_total_1(4)
sum_total_1(5)
sum_total_2(30) # sum_total_1和sum_total_2内存地址相互独立
sum_total_2(40)
源码
import time
# 装饰器定义
# 简单装饰器格式,传入func为函数
def decorator_1(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print(f'原函数执行速度是:{end_time - start_time}')
return wrapper
# 装饰器调用
@decorator_1 # 使用@语法糖,调用装饰器
def func_1():
print('func_1 为原函数')
time.sleep(1)
func_1()
# 使用普通方式调用
# call_func = decorator_1(func_1)
# call_func()
源码
# 万能装饰器
def decorator_2(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print(f'原函数执行速度是:{end_time - start_time}')
return wrapper
@decorator_2
def func_2(name, courses, date_time='2021-06-09'):
courses_str = ''
for i in courses:
courses_str = courses_str + i + ','
print(f'我是{name},今天是{date_time},学习了:{courses_str}的课程')
time.sleep(1)
func_2('Portos', ['Python', '函数', 'decorator'], date_time='2021-06-10')
源码
# 带参数装饰器
def decorator_with_para(*para_list, **para_dict):
def decorator_3(func):
def wrapper(*args, **kwargs):
print('传入的para_list可供内部装饰器使用:', para_list)
print('传入的para_dict可供内部装饰器使用:', para_dict)
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print(f'原函数执行速度是:{end_time - start_time}')
return wrapper
return decorator_3
@decorator_with_para('可变参数', para_dict_data='关键字参数')
def func_3(name, courses, date_time='2021-06-09'):
courses_str = ''
for i in courses:
courses_str = courses_str + i + ','
print(f'我是{name},今天是{date_time},学习了:{courses_str}的课程')
time.sleep(1)
func_3('Portos3', ['Python3', '函数', 'decorator'], date_time='2021-06-10')
源码
# 复合/多层装饰器调用
# 第一个装饰器
def decorate_4(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print(f'原函数执行速度是:{end_time - start_time}')
return wrapper
# 第二个装饰器
def decorate_5(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
print(f'此处调用了装饰器decorate_5')
return wrapper
# 第一个装饰器和第二个装饰器都装饰同一个函数
@decorate_5 # 后装饰的,先调用
@decorate_4 # 先装饰的,后调用
def func_4(name, courses, date_time='2021-06-09'):
courses_str = ''
for i in courses:
courses_str = courses_str + i + ','
print(f'我是{name},今天是{date_time},学习了:{courses_str}的课程')
time.sleep(1)
func_4('Portos4', ['Python4', '函数', 'decorate'], date_time='2021-06-10')
源码
# Author:PortosHan
# Datetime:2021/6/17 21:00
# Project:zbcf_python_lesson_project
# 装饰器调用练习(场景:权限验证)
"""
付款时校验登录权限,练习:
第一步:调用付款函数进行付款;
第二步:校验是否登录;
第三步:没有登录,重新登录后再付款;
第四步:登录成功后,重新调用付款函数进行付款。
"""
import time
is_login = False # 默认没有登录
# 定义一个登录函数,判断是否登录成功
def login():
user_name = input('请输入用户名:')
pwd = input('请输入密码:')
if user_name == 'portos'.lower() and pwd == '123456':
return True
else:
return False
# 定义一个装饰器,判断是否登录
def login_decorator(func):
def wrapper(*args, **kwargs):
print('------校验登录状态------')
global is_login
if is_login:
func(*args, **kwargs)
else:
print('用户没有登录,不能付款,3s后自动跳转到登录页面!')
time.sleep(3)
# 登录成功/失败后,重新赋值全局变量的值
is_login = login()
# 登录成功后,重新调用当前付款函数
func(*args, **kwargs)
return wrapper
# 调用付款函数时,使用装饰器校验是否登录
@login_decorator
def pay(money):
print(f'------付款金额:{money}元------')
print('付款中')
time.sleep(3)
print('------付款成功!------')
pay(1000)
# pay(100)
源码
# 装饰器:批量取消装饰器(直接调用原函数)
def decorate_with_para_7(para_flag):
def decorate_7(func):
def wrapper(*args, **kwargs):
if para_flag:
func(*args, **kwargs)
print('此处是被装饰过的原函数!')
else:
return func(*args, **kwargs)
return wrapper
return decorate_7
@decorate_with_para_7(False)
def func_7():
print('1此处是原函数')
func_7()
源码
from functools import wraps
# wraps装饰器:取消装饰器(直接调用原函数)
def decorate_8(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""被wraps装饰过的函数"""
func(*args, **kwargs)
print(f'此处是被装饰过的原函数!现在函数名是:{wrapper.__name__},文档说明是:{wrapper.__doc__}')
return wrapper
@decorate_8
def func_8():
"""原函数"""
print('2此处是原函数')
# func_8()
func_8.__wrapped__() # 有wraps装饰器时,访问原函数
源码
# 例如:如下两个(或更多)装饰器,装饰同一个函数
def decorate_9(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""1被wraps装饰过的函数"""
func(*args, **kwargs)
print(f'1此处是被装饰过的原函数!现在函数名是:{wrapper.__name__},文档说明是:{wrapper.__doc__}')
return wrapper
def decorate_10(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""2被wraps装饰过的函数"""
func(*args, **kwargs)
print(f'2此处是被装饰过的原函数!现在函数名是:{wrapper.__name__},文档说明是:{wrapper.__doc__}')
return wrapper
def decorate_11(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""3被wraps装饰过的函数"""
func(*args, **kwargs)
print(f'3此处是被装饰过的原函数!现在函数名是:{wrapper.__name__},文档说明是:{wrapper.__doc__}')
return wrapper
@decorate_11
@decorate_10
@decorate_9
def func_9():
"""原函数"""
print('3此处是原函数')
func_9.__wrapped__() # 此时只会略过最外层的包装层decorate_11
func_9.__wrapped__.__wrapped__.__wrapped__() # 若想略过其他层,需继续调用其他层的__wrapped__属性
>>返回主目录
作者: PortosHan
出处: https://www.cnblogs.com/PortosHan/
关于作者:专注于软件测试、测试开发等领域,请多多赐教!
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 原文链接 如有问题,可邮件(bhanzdan@163.com)咨询。