装饰器

装饰器

在不改变被装饰对象"内部代码"以及"调用方式"的基础上添加新的功能
开放封闭原则
	对扩展开放
	对修改封闭
装饰器原则:让使用者察觉不到程序被增加

装饰器

尝试添加装饰器

1.原来的程序
def old():  # 建立函数
	print('假装这是代码!')  # 函数体代码
	return 123  # 返回值
old()
假装这是代码!




2.新加入的功能
# 添加新的功能,不能更改原来的函数体代码和调用方式
print('新的代码!')  # 1.直接添加新的功能
old()  # 2.运行函数体代码
print('又是一个新的代码!')  # 3.添加另一个功能
新的代码!
假装这是代码!
又是一个新的代码!
#可以运行,但如果需要多个位置需要添加同样的功能就会繁琐
#解决需要重复的问题




3.解决代码需要重复的问题
def new():  # 将上一个代码封装成函数,可以在任意位置调用
	print('新的代码!')
	old()
	print('又是一个新的代码!')
new()
新的代码!
假装这是代码!
又是一个新的代码!
# 问题,只可以运行相同的代码,没有实际意义,需要灵活运用
#想办法灵活的将新代码添加到其他代码之上




def old():
	print('假装这是代码!')
	return 123
def old_1():  # 1。另一个需要同样功能的代码
	print('另一个需要新增功能的代码!')
def new(a):  # 2.函数调整为位置形参
	print('新的代码!')
	a()  # 4.传入的实参直接代替a,也就是函数加上括号就会运行
	print('又是一个新的代码!')
#可以运行,但如果需要多个位置需要添加同样的功能就会繁琐
# 函数封装可以在任意位置使用
new(old)  # 3.调用new并将old以实参输入,
new(old_1)  # 3.1调用new并将old_1以实参输入,
新的代码!
假装这是代码!
又是一个新的代码!
新的代码!
另一个需要新增功能的代码!
又是一个新的代码!
#解决了代码不能灵活运用的问题,但更改了原来的传参方式
#需要解决传参的问题



def old():
	print('假装这是代码!')
	return 123
def old_1():
	print('另一个需要新增功能的代码!')
def new_1():  # 1.创建一个闭包函数
	#  但是将这个写死了,没办法改变 a=old,
	a = old  # 2.将old直接赋值给下面的a。然后运行
	def new():  # 3.去掉new需要的形参
		print('新的代码!')
		a()  # 4.a被old赋值,运行到这里会自动找到old
		print('又是一个新的代码!')
	return new  # 5.new_1返回的值为new
res = new_1()  # 6.将返回来的值赋值给res
res()  # 7.返回来的new加上括号就会直接运行函数体代码
# 更改了传参方式,添加闭包函数




def old():
	print('假装这是代码!')
	return 123
def old_1():
	print('另一个需要新增功能的代码!')
def new_1(a):   # 1.为了防止代码不被写死,将new_1调整为需要个实参才可以,填入的这个参数就是需要运行的old或者old_1都可以
	def new():  
		print('新的代码!')
		a()  # 2.这里的a就是传入的参数
		print('又是一个新的代码!')
	return new  
old= new_1(old)  #3.关键
old()
# 没有修改原代码,没有改变传参方式
但如果给其他函数添加同样的功能需要重新填写赋值等号
old_1 = new_1(old_1)
old_1()
# 那么有没有办法可以在方便一些呢,或者可以添加有参函数呢
'''
关键:代码运行到old=new_1(old)会先运行new_1()的函数,并将old以实参的方式传递进去,此时a=old的内存地址,new_1的返回值时new赋值old。(原函数名old内存地址已经被a接收,old这个变量名现在可以随时指向新的内存地址)然后old()是运行new的函数体代码,old指向的就是new。运行new时a就会使用原old的内存地址(也就是运行old函数体代码)
'''

装饰器

装饰器繁琐

def old():  # 1.函数old需要参数,调用需要参数
	print('假装这是代码!')
	return 123
def old_1(b):
	print('另一个需要新增功能的代码!')
def new_1(a):
	def new(*args,**kwargs):  # 1.new需要位置参数或者关键字参数都可以运行
		print('新的代码!')
		a(*args,**kwargs)  # 2.传入任何参数都可以使用或者不传入参数
		print('又是一个新的代码!')
	return new
old = new_1(old)
old()
old_1 = new_1(old_1)
old_1(1)  # 3.最后需要运行的函数需要参数所以当把new返回的时候填入参数,现在old_1就是new。运行到a的时候填入的参数会自动填入
# 完全实现了可以给无参或者有参添加新功能
但没有返回值

装饰器返回值

def old():
	print('假装这是代码!')
	return 123
def old_1(b):
	print('另一个需要新增功能的代码!')
	return 456
def new_1(a):
	def new(*args,**kwargs):
		print('新的代码!')
		l1 = a(*args,**kwargs)  # 1.将原代码的返回值设置变量名,接受返回值
		print('又是一个新的代码!')
		return l1  #2.将返回值返回出去
	return new
old = new_1(old)
l2=old()  # 3.将返回值接收
old_1 = new_1(old_1)
l3=old_1(1)  # 3.1将返回值接收
print(l2)  #打印
print(l3)  #打印

登录认证

def add():
	print('这是111')
def app():
	print('这是222')
def xpp(a):  #形参不可以更改
	def all(*args,**kwargs):  #形参不可以更改
		name = input('账号').strip()
		pasd = input('密码').strip()
		if name == 'x'and pasd == '123':
			i1 = a(*args,**kwargs)
			return i1
		else:
			print('输入错误!')
		return
	return all
add = xpp(add)
i2=add()
print()

一次性登录认证

def add():
	print('这是111')
def app():
	print('这是222')
dict_1 = {'1':False}  # 类似功能字典
def xpp(a):
	def all(*args,**kwargs):
		if dict_1.get('1'):  # 判断字典内是False或者True
			i1 = a(*args, **kwargs)
			return i1
		name = input('账号').strip()
		pasd = input('密码').strip()
		if name == 'x'and pasd == '123':
			i1 = a(*args,**kwargs)
			dict_1['1'] = True  # 登录成功将False改成True
			return i1
		else:
			print('输入错误!')
	return all
add = xpp(add)
i2=add()
print()

装饰器模板

def outer(func):
	def inner(*args,**kwargs):
		print('执行函数之前添加的功能')
		res = func(*args,**kwargs)  #执行被装饰的函数
		print('执行函数之后添加的功能')
		return res #被装饰的函数返回值的返回
	return inner
def index (*args,**kwargss)
	print('这是语法糖')
inder = outer(inder)

语法糖

def outer(func):
	def inner(*args,**kwargs):
		print('执行函数之前添加的功能')
		res = func(*args,**kwargs)  #执行被装饰的函数
		print('执行函数之后添加的功能')
		return res #被装饰的函数返回值的返回
	return inner
def index (*args,**kwargss)
	print('这是语法糖')
inder = outer(inder)
@outer  #  inder = outer(inder)  相等
装饰器语法糖书写规范
	语法糖必须紧贴着要装饰的对象上方
装饰器语法糖内部原理
	自动将下面紧贴着的被装饰对象名字当做参数传给装饰器函数调用

双层语法糖

import time
def get_time(func):
	def inner(*args, **kwargs):
		start_time = time.time()
		res = func(*args, **kwargs)  # 执行被装饰的函数
		end_time = time.time()
		print('函数执行时间:%s'%(end_time-start_time))
		return res  # 将被装饰函数执行之后的返回值返回
	return inner
# 校验用户登录装饰
def login_auth(func):
	def inner(*args, **kwargs):
		# 1.先获取用户的用户名和密码
		username = input('username>>>:').strip()
 		password = input('password>>>:').strip()
 		# 2.校验用户名和密码是否正确
 		if username == 'jason' and password == '123':
 			res = func(*args, **kwargs)  # 执行被装饰的函数
			return res  # 将被装饰函数执行之后的返回值返回
		print('用户名或密码错误 无权限执行')
	return inner
@login_auth
@get_time
def index():
    time.sleep(1)
    print('from index')
index()
'''
先执行距离函数体最近的语法糖,之行结束的返回值会被第二层语法糖运用
'''

装饰器修复技术

from functools import wraps
def outer(func):
	@wraps(func)  # 修复技术就是为了让被装饰对象更加不容易被察觉装饰了
	def inner(*args, **kwargs):
		print('执行函数之前可以添加的额外功能')
 		res = func(*args, **kwargs)  # 执行被装饰的函数
		print('执行函数之后可以添加的额外功能')
 		return res  # 将被装饰函数执行之后的返回值返回
	return inner


@outer  # index = outer(index)
def index():
	print('from index')
print(index)
help(index)

def home():
	"""这是一个home函数"""
	print('from home')
# help(index)
# help(home)
# print(index)
# help(len)
help()  #查看函数参数
from functools import wraps
def 函数名():
	@wraps(函数名)	
				'''就这么用,别问为什么'''

练习题

def outter1(func1):
	print('加载了outter1')
	def wrapper1(*args, **kwargs):
		print('执行了wrapper1')
		res1 = func1(*args, **kwargs)
		return res1
	return wrapper1
def outter2(func2):
	print('加载了outter2')
	def wrapper2(*args, **kwargs):
		print('执行了wrapper2')
		res2 = func2(*args, **kwargs)
		return res2
	return wrapper2
def outter3(func3):
	print('加载了outter3')
	def wrapper3(*args, **kwargs):
		print('执行了wrapper3')
 		res3 = func3(*args, **kwargs)
		return res3
	return wrapper3
@outter1
@outter2
@outter3
def index():
    print('from index')
七个print的打印顺序

有参装饰器

def outer(source_data):
	# source_data = 'file'
	def login_auth(func):
		def auth(*args,**kwargs):
			# 2.校验用户名和密码是否正确
			# 数据的校验方式可以切换多种
			if source_data == 'file':
				# 从文件中获取用户数据并比对
				print('file文件获取')	
			elif source_data == 'MySQL':
  				# 从MySQL数据库中获取数据比对
				print('MySQL数据库获取')
			elif source_data == 'postgreSQL':
				# 从postgreSQL数据库中获取数据对比
				print('postgreSQL数据库获取')
			else:
				print('用户名或密码错误 无法执行函数')
		return auth
	return login_auth

@outer('file')
def index():
	print('from index')
@outer('MySQL')
def home():
	print('from home')

index()
home()
#有参函数,最外层函数在包一层

装饰器

上一篇:两种切割裁剪,切割图片的方法


下一篇:Jekins从安装到发布一个程序排坑记录