Python装饰器
关于开放封闭原则,其核心的思想是:
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
因此,开放封闭原则主要体现在两个方面:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
“需求总是变化”、“世界上没有一个软件是不变的”,这些言论是对软件需求最经典的表白。从中透射出一个关键的意思就是,对于软件设计者来说,必须在不需要对原有的系统进行修改的情况下,实现灵活的系统扩展。
不修改源代码、不修改调用方式,上线后还需要扩展,就用到了装饰器
装饰器可以是任何可调用对象
1 装饰器
1.1 无参装饰器,为被装饰的函数添加统计时间功能
装饰器用到的是闭包函数,在下面的例子中是wrapper函数,我们首先需要了解程序的运行流程,下面一步步的分析:
程序运行到@timmer时,会执行timmer(index) ,index是timmer下面最近的函数名,函数名index作为timmer的参数,下面运行timmer函数。timmer函数运行结束会返回wrapper,继续运行到@timmer,timmer(index)的返回值会赋值给index,也就是index=timmer(index) 。然后执行最后的index()函数,此时实际是wrapper(),然后进入到wrapper函数中执行,wrapper函数是闭包函数,内部有个func函数,执行到这里的时候,wrapper函数颞部没有定义func,就到其外部作用域寻找,在这里是timmer函数传入的参数func。wrapper中的func的地址是最初的index函数的地址,所以执行就是执行下面的index中的 time.sleep(1) \print("welcome index page")着两句。
#-*- coding:utf-8 -*-
# decription:定义无参装饰器,为被装饰的函数添加统计时间功能
# author: hzx
# date: 2017.04.10
import time
def timmer(func):
def wrapper(): # wrapper 是闭包函数
time_start= time.time()
res=func() # 这里是最初的index
time_stop = time.time()
print("run time is %s"%(time_stop-time_start))
return res
return wrapper
@timmer
def index(): # index=timmer(index)
time.sleep(1) # 延时函数2秒
print("welcome index page")
index() # 相当于是wrapper()
1.2 有参装饰器,为被装饰函数添加函数认证功能
有参装饰器是在无参装饰器的的外面再添加一个函数,这个函数负责接收的参数是用于判读用户信息的来源,这里测试是从文件中读取用户信息。
程序思路:
首先程序执行道@auth_file(auth_type="file"),这是auth外面的函数,它的返回值是auth,重点-->,此时程序就是@auth,思路和无参装饰器是一样的,index=auth(index).
程序分为3部分,装饰器定义部分,被装饰函数,函数引用。
#-*- coding:utf-8 -*-
# decription:定义有参装饰器,为被装饰的函数添加函数认证功能,
# 用户信息可以来源文件或者ldap三次登录失败,锁定用户
# author: hzx
# date: 2017.04.10
import os
current_login = {"name":None,"login":False} # 定义的是用户的登录状态
def auth_file(auth_type): # 定义有参装饰器函数
def auth(func):
def wrapper(*args,**kwargs): # 这样就能接收任何数据类型 数据来自func
if current_login["name"] and current_login["login"]: # 在用户认证之情判断
res =func(*args,**kwargs) # 如果认证功过,就直接返回res
return res
if auth_type == "file":
username = input("please input username:")
# user_func()
count = 0 # 记录用户输入密码的次数
flag = 1
lock = []
user_pass = []
with open("locked", encoding="utf-8") as locked_file:
for i in locked_file:
if i == username:
print("用户名被锁定")
break
# 将黑名单文件内容作为列表元素追加到列表中
for line in locked_file:
line = line.strip()
lock.append(line)
# 若输入的用户名在黑名单中,打印:用户已经被锁定,
if username in lock:
print("用户%s" % username)
else:
# 输入的用户名不在黑名单中,则提示用户输入密码信息
while True:
count += 1
passwd = input("please input your password:")
with open("user", encoding="utf-8") as user_file:
for i in user_file:
user_pass = i.strip().split("--")
print(user_pass)
if username == user_pass[0] and passwd == user_pass[1]:
print('welcome user %s login !' % username)
print("认证成功!")
res = func(*args, **kwargs) # 这样设置然函数也能接收任何类型的数据,
current_login["name"] = username
current_login["login"] = True
return res
# flag = True
break
else:
continue
if flag is True:
break
else:
if count == 3:
print('Locked')
with open("locked", "w+", encoding="utf-8") as f_write:
f_write.write(username) # 3次输入错误后将用户名写入locked文件
break
elif auth_type == "ldap":
print("等待使用")
return wrapper
return auth
@auth_file(auth_type="file")
def index():
print("welcome to index page!")
@auth_file(auth_type="ldap")
def home():
print("welcome to home page!")
# 函数调用
index()
home()