装饰器
开放封闭原则
- 开放 : 对扩展是开放的 ( 允许代码扩展、添加新功能 )
- 封闭 : 对 修改 , 源代码 以及 调用方式 是封闭的
初识装饰器
定义:
- 装饰器本身就是一个函数 , 在不改变原被装饰的函数的源代码以及调用方式下,为其添加一个额外的功能。
import time # (格林尼治时间 , 也叫时间截) 测试执行效率
def fun(): #2.00022554397583
time.sleep(2) # 模拟一下网络延迟以及代码的效率
print("欢迎访问博客园主页")
def index(): #2.001535654067993
time.sleep(2) # 模拟一下网络延迟以及代码的效率
print('欢迎访问博客园首页')
def home(): #3.000067710876465
time.sleep(3) # 模拟一下网络延迟以及代码的效率
print(f'欢迎访问主页')
def timer(func): # func = index
def inner():
start_time = time.time()
func()
end_time = time.time()
print(f'此函数的执行效率为{end_time-start_time}')
return inner
timer(fun)()
带返回值的装饰器
import time
def index():
time.sleep(2) # 模拟一下网络延迟以及代码的效率
print('欢迎访问博客园主页')
return '访问成功'
def timer(func): # func = index
def inner():
start_time = time.time()
ret = func() # '访问成功'
end_time = time.time()
print(f'此函数的执行效率为{end_time - start_time}')
return ret # '访问成功'
return inner
index = timer(index) # inner
print(index()) # print(inner())
print(timer(index)()) # '访问成功'
被装饰函数带参数的装饰器
单一参数的装饰器
# 单一参数的装饰器
import time
def index():
time.sleep(2) # 模拟一下网络延迟以及代码的效率
print('欢迎访问博客园主页')
return '访问成功'
def home(name):
time.sleep(3) # 模拟一下网络延迟以及代码的效率
print(f'欢迎访问{name}主页')
def timer(func): # func = home
def inner(name):
start_time = time.time()
func(name) # home(name) == home('太白')
end_time = time.time()
print(f'此函数的执行效率为{end_time-start_time}')
return inner
# 要想timer装饰home函数怎么做?
home = timer(home)
home('太白') # 注意将返回给 inner(name)返回值 会返回给timer(func) None
动态参数的装饰器(举例)
# 动态参数的装饰器
import time
def index():
time.sleep(2) # 延迟两秒执行下面的代码
print("欢迎访问博客园主页")
return "访问成功"
def home(name,age):
time.sleep(3)
print(f"欢迎访问{age}岁的{name}的博客园主页")
def timer(func):
def inner(*args,**kwargs): # 形参位置 *聚合:args = ('太白',18)
star_time = time.time()
func(*args,**kwargs) # 执行位置的*是打散 func('太白',18)
stop_time = time.time()
print(f"此函数的执行效率是{stop_time - star_time}")
return "好靓的发型"
return inner
home = timer(home)
home("太白",22)
# 在被修饰函数(home)上面加上@装饰器函数名(timer),就等同于那句话 home = timer(home)
# @timer 相当于 home = timer(home)
import time
def timer(func):
def inner(*args, **kwargs): # 形参位置 *聚合:args = ('太白',18)
star_time = time.time()
# func(*args, **kwargs) # 执行位置的*是打散 func('太白',18)
ret = func(*args, **kwargs) # 带返回值的原函数
stop_time = time.time()
print(f"此函数的执行效率是{stop_time - star_time}")
return ret
return inner
@timer
def home(name, age):
time.sleep(3)
print(f"欢迎访问{age}岁的{name}的博客园主页")
return true
home("太白", 23)
print(home("太白", 23))
标准版装饰器
代码优化:语法糖 @ / 优化语法
- 在被修饰函数(home)上面加上@ + 装饰器函数名(timer),就等同于那句话 home = timer(home)
语法糖@的执行方式
- @ 会向下读一行 , 将原函数的函数存到内存 传到装饰器 函数的形参 上 并将原函数名() = 装饰器函数名(原函数名)
标准版的装饰器
def wrapper(func): # wrapper 包装
def inner(*args,**kwargs):
'''执行被装饰函数之前的操作'''
ret = func
'''执行被装饰函数之后的操作'''
return ret
return inner
装饰器→简单登录
# 简单登录验证
ogin = {"flag":False}
# flag = False
def auth(f):
def inner(*args,**kwargs):
# global flag # 在函数最前面先声明 要改变全局变量 flag
if login["flag"]:
# if flag:
ret = f(*args,**kwargs)
return ret
user = input("user>>>")
passwords = input("passwords>>>")
if user.strip() == "杨泽涛很帅" and passwords.strip() == "确实帅":
login["flag"] = True
# flag = True
ret = f(*args,**kwargs)
return ret
return inner
@auth
def article():
print('欢迎访问文章页面')
@auth
def diary():
print('欢迎访问日记页面')
@auth
def comment():
print('欢迎访问评论页面')
article()
diary()
comment()
装饰器→自定义循环原函数
def wrapper(f):
def inner(*args,**kwargs):
for i in range(*args):
f(*args,**kwargs)
return inner
@wrapper
def func(n):
print("没错循环的我")
func(n)
装饰器 → 录入文件时间
import time
def wrapper(f):
def inner(*args,**kwargs):
start_time = time.localtime()
ret = time.strftime("%Y-%m-%d %H:%M:%S", start_time) # 当前时间节点 ymdhms → 年月日时分秒
f()
ret_1 = f.__name__
with open ("文件时间录入.excel",mode = "r+",encoding = "utf-8") as file_1:
file_1.seek(0,2)
file_1.write(f"\n{ret_1}_{ret}")
return inner
@wrapper
def func():
print("快来录入")
func()
# start_time = time.localtime()
# ret = time.strftime("%Y-%m-%d %H:%M:%S", start_time)
# 自动生成指定格式的日期串 func_2019-06-24 17:56:36
装饰器 → 限制该函数被调用的频率
# 请实现一个装饰器,限制该函数被调用的频率,如3秒一次(借助于time模块,time.time())
import time
'''
if 第二次执行的时间 - 第一次执行的时间 > 3: 逆推法
第一次时间节点: 123443543.546 - 0 肯定 > 3
第二次进入:time.time() 123443545.546 - 123443543.546 < 3''''
def wrapper(f):
t = 0
def inner(*args,**kwargs):
nonlocal t
if time.time() - t > 3:
ret = f(*args,**kwargs)
return ret
return inner
@wrapper
def func():
print("666")
func()
time.sleep(3)
func()
带参数的装饰器
login = False
def auth(x):
def auth2(func):
def inner(*args,**kwargs):
global login
if login:
ret = func()
return ret
if x = "wechat":
user = input(">>>用户名:").strip()
passwords = input(">>>密码:").strip()
if user == "杨泽涛" and passwords == "123":
login = True
ret = func()
return ret
if x = "QQ":
user = input(">>>用户名:").strip()
passwords = input(">>>密码:").strip()
if user == "杨泽涛" and passwords == "123":
login = True
ret = func()
return ret
return inner
return auth2
@auth("wechat")
def jitter():
print("欢迎回到抖音")
@auth("QQ")
def pipishrimp():
print("皮皮虾等你好久了")
jitter()
pipishrimp()
多个装饰器装一个参数
def wrapper_1(f1):
def inner_1(*args,**wkargs):
print("wrapper_1,before f1")
f1(*args,**wkargs)
print("wrapper_1,after f1")
return inner_1
def wrapper_2(f2):
def inner_2(*args,**wkargs):
print("wrapper_2,before f2")
f2(*args,**wkargs)
print("wrapper_2,after f2,")
return inner_2
@wrapper_2
@wrapper_1
def func():
print("666")
func()
# 打印结果
'''
wrapper_2,before f2
wrapper_1,before f1
666
wrapper_1,after f1
wrapper_2,after f2
''''
递归函数 (recursion )
- 在一个函数里在调用这个函数本身 / 递归的最大深度:998 , 最多执行到997
- 人理解循环,神理解递归
- 可以使用递归来遍历各种树形结构, 比如我们的文件夹系统. 可以使用递归来遍历该文件夹中的所有文件
- 有规律的线性结构 有些适合用递归
自定义递归深度
import sys # 调用系统
print(sys.setrecursionlimit(10000)) # 设置默认值递归深度
def foo(n):
print(n)
n += 1
foo(n)
foo(1)
有规律的数值差 / 递归
def age(n):
if n == 1:
return 40
else:
return age(n-1)+2
print(age(4))
遍历列表 / 递归
l1 = [1, 3, 5, ['22','python', 34, [33, 55, [11,33]]], [77, 88],66]
def func(alist):
for i in alist:
if type(i) == list:
func(i)
else:
print(i)
func(l1)