python装饰器详解

装饰器

储备知识1:*args和**kwargs

def index(x,y):
    print(x,y)
def wrapper(*args,**kwargs):
    index(*args,**kwargs)
wrapper(1,y=2)
# 会将wrapper的参数原封不动的传给index()

储备知识2:名称空间与作用域

# 名称空间的“嵌套”关系实在函数定义阶段即检测语法的时候确定的

储备知识3:函数对象

# 可以把函数当作参数传输
# 可以把函数当作返回值返回
def index():
    pass
def foo(function):
    return function
foo(index)
# 传给foo的是index的内存地址,传给foo的是一个函数

储备知识4:函数的嵌套定义

def outter(function):
    def wrapper():
        pass
    return wrapper

储备知识 5:闭包函数

# 闭函数:指该函数是内嵌函数
# 包函数:该函数对外层函数的作用域名字的引用(不是对全局作用域)
def outter():    
	x=111
    def wrapper():
    	print(x)
	return wrapper
func  = outter()
func()
# func虽然可以全局调用wrapper,但外部包裹了outter()
1、什么是装饰器
  • 器指的是一个工具,大多数场景都是定义成函数
  • 装饰指的是为其他事物添加额外的东西点缀
  • 总结:装饰器指的是定义一个函数或者类,用来为其他函数或类添加额外的功能
2、为何要用装饰器
  • 开放封闭原则
    • 开放:指的是对拓展功能是开放的
    • 封闭:指的是对修改源代码是封闭的
    • 即在不修改源码及调用方式的前提下拓展功能
3、装饰器案例
无参装饰器实例
#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import time
from functools import wraps     # 伪装原函数的所有属性

"""
需求:
	1、原函数为index
	2、不修改原函数源码和调用的方式
	3、增加统计函数运行时间功能
	4、新增的装饰器同样可以装饰其他函数
"""


def timmer(func):
	@wraps(func)    # 伪装原函数的所有属性
	def wrapper(*args, **kwargs):
		start = time.time()
		res = func(*args, **kwargs)
		stop = time.time()
		print('运行时间:{}秒'.format(int(stop - start)))
		# 伪装原函数的返回值
		return res
	#  伪装原函数函数名
	# wrapper.__name__ = func.__name__
	#  伪装原函数文档信息
	# wrapper.__doc__ = func.__doc__
	return wrapper


@timmer  # 语法糖  index = timmer(index)
def index(x, y):
	"""
	被装饰函数
	"""
	time.sleep(2)
	print(x, y)


@timmer  # 语法糖  other = timmer(other)
def other(name):
	"""
	其他被装饰函数
	"""
	time.sleep(3)
	print('{} from other'.format(name))


index(200, 300)
print('函数名:{}\n函数文档信息:{}'.format(index.__name__, index.__doc__))
other('message')
print('函数名:{}\n函数文档信息:{}'.format(other.__name__, other.__doc__))

在这里插入图片描述

有参装饰器实例

为什么需要有参装饰器:

由于语法糖@的限制,装饰器只能由一个参数,并且该参数是用来接收被装饰对象的内存地址。

当wrapper还需要额外的参数时,此时就需要有参装饰器进行装饰。这里的有参指的是给wrapper的参数而不是原函数。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

"""
需求:
	为index和other添加认证功能
	index的数据来源为文件
	other的数据来源为数据库
"""
from functools import wraps
import pymysql


def auth(dt_type):
	# 为装饰器传参数
	def deco(function):
		@wraps(function)
		def wrapper(*args, **kwargs):
			usn = input('your username >>> ').strip()
			pwd = input('your password >>> ').strip()
			if dt_type == 'file':
				print('login from file')
				with open('data/user', 'rt', encoding='utf-8') as f:
					for line in f:
						username, passwords = line.strip().split()
						if usn == username and pwd == passwords:
							res = function(*args, **kwargs)
							return res
					else:
						print('username or password error!')
			elif dt_type == 'mysql':
				print('login from mysql')
				db = pymysql.connect(user='root',password='1234',host='127.0.0.1',
				                     database='user',port=3306,charset='utf-8')
				cursor = db.cursor()
				data = cursor.fetchall()
				for line in data:
					username, passwords = line.strip().split()
					if usn == username and pwd == passwords:
						res = function(*args, **kwargs)
						return res
				else:
					print('username or password error!')
			else:
				print('path error!')

		return wrapper

	return deco


@auth(dt_type='file')
def index(x, y):
	"""
	被装饰函数
	"""
	print('from index -->  ', x, y)


@auth(dt_type='mysql')
def other(x, y):
	"""
	被装饰函数
	"""
	print('from other -->  ', x, y)

    
index(1, 2)
other(3, 4)

在这里插入图片描述

可以看出,所谓有参装饰器是在原装饰器上再进行一次闭包后通过语法糖对原装饰器进行传参。

同时使用多个装饰器时,装饰器的加载顺序为自下而上,而运行顺序为自上而下

@deco1
@deco2
@deco3(x=1)
def index():
	pass
# 加载顺序
# @deco3(x=1) ---> @deco2 ---> @deco1
# 运行顺序
# @deco1 ---> @deco2 ---> @deco3(x=1)

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值