装饰器

Posted yongpiaopiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器相关的知识,希望对你有一定的参考价值。

1.定义 

装饰器:本质就是函数,功能是为其他函数添加附加功能

原则:

1.不修改被修饰函数的源代码

2.不修改被修饰函数的调用方式

开放封闭原则:程序一旦上线,就不应该更改程序内部的源代码

装饰器=高阶函数+函数嵌套+闭包

2.高阶函数定义:函数接收的参数是一个函数名或者函数的返回值是一个函数名

函数接收的参数是一个函数名:

作用:在不修改函数源代码的前提下,为函数添加新功能

不足:会改变函数的调用方式

import time
def foo():
time.sleep(3)
print(‘hello cyx‘)

def test(func):
# print(func)
start_time = time.time()
func()
stop_time = time.time()
print(‘函数的运行时间是 %s‘ %(stop_time - start_time))

test(foo)#原函数的调用方式foo()被改变

函数的返回值是一个函数名

作用:不修改函数的调用方式

不足:不能添加新功能

def fooo():
print(‘from the foo‘)

def test(func):
return func
foo = test(foo)
foo()

高阶函数的两个功能相结合,会多运行一次,所以单纯高阶函数无法实现装饰器功能

import time
def foo():
time.sleep(3)
print(‘from the foo‘)

def timer(func):
start_time = time.time()
func()
stop_time = time.time()
print(‘函数的运行时间是 %s‘ %(stop_time - start_time))
return func

foo = timer(foo)
foo()

3.函数嵌套:函数里再定义一个函数

函数里再调用一个函数不是函数嵌套

def foo():
print(‘from foo‘)
def bar():
print(‘from bar‘)
foo()#这个不是函数的嵌套
def father(name):
print(‘from father %s‘ %name)
def son():
name = ‘cyx_1‘
print(‘my father is %s‘ %name)#son是局部变量,只能在局部调用
son()
print(locals())#打印当前层的局部变量,包括name和son
father(‘cyx‘)

4.函数闭包装饰器基本实现

装饰器框架:

def timer(func):
def wrapper():
print(func)
func()
return wrapper

import time
def timer(func):#func = test
def wrapper():
start_time = time.time()
func()#就是在运行test()
stop_time = time.time()
print(‘函数运行的时间是%s‘ %(stop_time - start_time))
return wrapper

@timer#相当于test = timer(test)
def test():
time.sleep(3)
print(‘test函数运行完毕‘)

# test = timer(test)#返回的是wrapper地址
test()#执行的是wrapper

5.函数闭包加上返回值

import time
def timer(func):
def wrapper():
start_time = time.time()
res = func()#就是在运行test
stop_time = time.time()
print(‘函数运行的时间是%s‘ %(stop_time - start_time))
return res
return wrapper

@timer#test = timer(test)
def test():
time.sleep(3)
print(‘test函数运行完毕‘)
return ‘这是test的返回值‘

res = test()#运行的是wrapper
print(res)

6.函数闭包加上参数

加定长参数

import time
def timer(func): #func = test
def wrapper(name, age):
start_time = time.time()
res = func(name, age)#就是在运行test
stop_time = time.time()
print(‘函数运行的时间是%s‘ %(stop_time - start_time))
return res
return wrapper

@timer#test = timer(test)
def test(name, age):
time.sleep(3)
print(‘test函数运行完毕 名字是%s 年龄是%s‘ %(name, age))
return ‘这是test的返回值‘

a = test(‘cyx‘, 18)#运行的是wrapper
print(a)

加不定长参数

import time
def timer(func): #func = test
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)#就是在运行test
stop_time = time.time()
print(‘函数运行的时间是%s‘ %(stop_time - start_time))
return res
return wrapper

@timer#test = timer(test)
def test(name, age):
time.sleep(3)
print(‘test函数运行完毕 名字是%s 年龄是%s‘ %(name, age))
return ‘这是test的返回值‘

@timer # test1 = timer(test1)
def test1(name, age, gender):
time.sleep(3)
print(‘test函数运行完毕 名字是%s 年龄是%s 性别是%s‘ % (name, age, gender))
return ‘这是test1的返回值‘

res = test(‘cyx‘, 18)
print(res)
res1 = test1(‘cyx‘, 18, ‘male‘)
print(res1)

7.解压序列

需求1:取列表的第一个和最后一个元素(不用索引的方法)

l = [1, 2, 6, 9, 34, 89, 36, 87, 36]
a, *_, c = l
print(a)
print(c)

需求2:取列表的第一、第二和倒数第一、第二个元素

l = [1, 2, 6, 9, 34, 89, 36, 87, 36]
a,b, *_, c, d = l
print(a, b)
print(c, d)

需求3:交换a,b的值

a = 1
b = 2
a, b = b, a
print(a)
print(b)

8.函数闭包:为函数加上认证功能

以下装饰器bug:每次执行函数都要输入密码,和实际场景不符

def auth_func(func):
def wrapper(*args, **kwargs):
username = input(‘用户名:‘).strip()
passwd = input(‘密码:‘).strip()
if username == ‘cyx‘ and passwd == ‘123‘:
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
return wrapper

@auth_func
def index():
print(‘欢迎来到京西‘)

@auth_func
def home(name):
print(‘欢迎回家%s‘ % name)

@auth_func
def shopping_cart(name):
print(‘%s的购物车里有[%s, %s, %s]‘ % (name, ‘apple‘, ‘banana‘, ‘orange‘))

index()
home(‘cyx‘)
shopping_cart(‘cyx‘)

9.函数闭包模拟session

优化上一个验证功能装饰器(只输一次密码即可)

user_dic = {‘username‘: None, ‘login‘: False}

def auth_func(func):
def wrapper(*args, **kwargs):
if user_dic[‘username‘] and user_dic[‘login‘]:
res = func(*args, **kwargs)
return res
username = input(‘用户名:‘).strip()
passwd = input(‘密码:‘).strip()
if username == ‘cyx‘ and passwd == ‘123‘:
user_dic[‘username‘] = username
user_dic[‘login‘] = True
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
return wrapper

@auth_func
def index():
print(‘欢迎来到京西‘)

@auth_func
def home(name):
print(‘欢迎回家%s‘ % name)

@auth_func
def shopping_cart(name):
print(‘%s的购物车里有[%s, %s, %s]‘ % (name, ‘apple‘, ‘banana‘, ‘orange‘))

index()
home(‘cyx‘)
shopping_cart(‘cyx‘)

优化上一个验证功能装饰器(用户名密码和数据库进行匹配)

user_list = [{‘name‘: ‘cyx‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘ypp‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘yjj‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘yss‘, ‘passwd‘: ‘123‘},
]

current_dic = {‘username‘: None, ‘login‘: False}

def auth_func(func):
def wrapper(*args, **kwargs):
if current_dic[‘username‘] and current_dic[‘login‘]:
res = func(*args, **kwargs)
return res
username = input(‘用户名:‘).strip()
passwd = input(‘密码:‘).strip()
for user_dic in user_list:
if username == user_dic[‘name‘] and passwd == user_dic[‘passwd‘]:
current_dic[‘username‘] = username
current_dic[‘login‘] = True
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
return wrapper

@auth_func
def index():
print(‘欢迎来到京西‘)

@auth_func
def home(name):
print(‘欢迎回家%s‘ % name)

print(‘before‘, current_dic)
index()
print(‘after‘, current_dic)
home(‘cyx‘)

10.函数闭包带参数装饰器

user_list = [{‘name‘: ‘cyx‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘ypp‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘yjj‘, ‘passwd‘: ‘123‘},
{‘name‘: ‘yss‘, ‘passwd‘: ‘123‘},
]

current_dic = {‘username‘: None, ‘login‘: False}

def auth(auth_type = ‘filedb‘):
def auth_func(func):
def wrapper(*args, **kwargs):
print(‘认证类型是‘, auth_type)
if auth_type == ‘filedb‘:
if current_dic[‘username‘] and current_dic[‘login‘]:
res = func(*args, **kwargs)
return res
username = input(‘用户名:‘).strip()
passwd = input(‘密码:‘).strip()
for user_dic in user_list:
if username == user_dic[‘name‘] and passwd == user_dic[‘passwd‘]:
current_dic[‘username‘] = username
current_dic[‘login‘] = True
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
elif auth_type == ‘ldap‘:
print(‘ldap‘)
res = func(*args, **kwargs)
return res
else:
print(‘无法识别您的认证方式‘)
res = func(*args, **kwargs)
return res
return wrapper
return auth_func

@auth(auth_type = ‘filedb‘)#auth_func = auth(auth_type = ‘filedb‘)→@auth_func附加了一个auth_type形参→index= auth_func(index)
def index():
print(‘欢迎来到京西‘)

@auth(auth_type = ‘ldap‘)
def home(name):
print(‘欢迎回家%s‘ % name)


@auth(auth_type = ‘sssssss‘)
def shopping_cart(name):
print(‘%s的购物车里有[%s, %s, %s]‘ % (name, ‘apple‘, ‘banana‘, ‘orange‘))

index()
home(‘cyx‘)
shopping_cart(‘cyx‘)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象学习之八,装饰器

thymeleaf 片段渲染后重新加载 javascript

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码