什么是Python装饰器?如何定义和使用?


Posted in Python onApril 11, 2022

1.装饰器的定义

装饰器:给已有函数增加额外的功能的函数,本质上是一个闭包函数

特点:

  •     1.不修改已有函数的源代码
  •     2.不修改已有函数的调用方式
  •     3.给已有函数增加额外的功能
  •     4.代码执行时先解析装饰器
import time
 
# 装饰器原理
# def show():
#     n=0
#     for i in range(10000000):
#         n+=i
#     print('show_',n)
#
# # 定义一个闭包
# def count_time(fun):
#     def inner():
#         start=time.time()
#         fun()
#         end=time.time()
#         print(f'用时{end-start}秒')
#     return inner
#
# # 装饰器在装饰函数时的原理
# show=count_time(show)
# show()
 
# 定义装饰器(语法糖)
def count_time(fun):    # 必须要有一个参数接收被装饰函数
    def inner():
        start=time.time()
        fun()
        end=time.time()
        print(f'用时{end-start}秒')
    return inner
# 装饰器写法:@闭包的外部函数,必须在闭包定以后使用
print('解析装饰器1')
@count_time # 解释成show=count_time(show),show指向count_time函数中的inner
def show():
    n=0
    for i in range(10000000):
        n+=i
    print('show_',n)
 
print('解析装饰器2')
@count_time # 解释成display=count_time(display)
def display():
    print('Display')
 
print('正式执行...')
show()
display()

2.装饰器的通用类型的定义

(当被装饰函数有参数或者有返回值时同样适用)

'''
装饰器的通用类型的定义(当被装饰函数有参数或者有返回值时同样适用)
'''
 
def outer(func):
    def inner(*args,**kwargs):  # *为元组和列表解包,**为字典解包
        print('*'*30)
        print(args,kwargs)
        ret=func(*args,**kwargs)    # 解包,否则形参是元组或字典
        print('*'*30)
        return ret
    return inner
 
@outer
def show(name,msg):
    return str(name)+' say: '+str(msg)
 
print(show('Tom',msg='Hello'))

3.多个装饰器同时装饰一个函数

# 第一个闭包
def wrapper_div(func):
    def inner(*args,**kwargs):
        return '<div>'+func(*args,**kwargs)+'</div>'
    return inner
 
# 第二个闭包
def wrapper_p(func):
    def inner(*args,**kwargs):
        return '<p>'+func(*args,**kwargs)+'</p>'
    return inner
 
# 从下往上装饰,从上往下执行
@wrapper_div
@wrapper_p
# 定义一个函数
def show():
    return 'Short life I use Python.'
 
print(show())   #<div><p>Short life I use Python.</p></div>

4.多个装饰器同时装饰一个函数(二)

def outer1(func):
    def inner():
        print('装饰器1-1')
        func()
        print('装饰器1-2')
    return inner
 
def outer2(func):
    def inner():
        print('装饰器2-1')
        func()
        print('装饰器2-2')
    return inner
'''
1.show指向outer1.inner
2.outer1.inner.func指向outer2.inner
3.outer2.inner.func指向show
'''
@outer1
@outer2
def show():
    print('Show...')
 
show()

5.类装饰器使用方法

import time
 
class Wrapper():
    def __init__(self,func):
        self.func=func
 
    # 当类中实现了此方法时,该类的实例对象就变成了可调用对象,即可以在实例对象后面加()
    def __call__(self, *args, **kwargs):
        print('装饰内容1...')
        start=time.time()
        ret=self.func(*args,**kwargs)
        end=time.time()
        print(f'执行了{end-start}秒')
        print('装饰内容2...')
        return ret

该装饰器执行完成后,被装饰函数指向该类的实例对象
如果让被装饰函数执行,那么在类中要添加__call__方法,相当于闭包格式中的内函数
一旦被装饰函数执行调用,那么就会去执行实例对象中的__call__函数

@Wrapper    #解释成show=Wrapper(show),show变成了类的一个对象
def show():
    print('Show...')
 
show()
6.装饰器带有参数(使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数)
# @Author  : Kant
# @Time    : 2022/1/23 22:43
 
def set_args(msg):
    def outer(func):
        def inner():
            print('装饰内容',msg)
            func()
        return inner
    return outer
 
'''
使用带有参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回的是装饰器
调用set_args()后会返回outer的地址引用,变成了@outer
'''
@set_args('Hello')
# 无论闭包函数写成什么样子,被装饰函数永远指向闭包函数的内函数
def show():
    print('Show...')
 
show()

6.使用装饰器实现自动维护路由表

路由功能:通过请求的路径,可以找到资源的地址

# 定义一个路由表字典
router_table={}
def router(url):
    def wrapper(func):
        def inner():
            print('1')
            print('inner-',func)    # 查看当前的被装饰函数是谁
            func()
        # 在这里维护路由表字典
        router_table[url]=inner # 如果写func,inner函数中的内容都不会执行
        print('路由表字典:',router_table)
        return inner
    return wrapper
 
@router('index.html')
def index():
    print('首页内容')
 
@router('center.html')
def center():
    print('个人中心')
 
@router('mail.html')
def mail():
    print('邮箱页面')
 
@router('login.html')
def login():
    print('登录页面')
 
def error():
    print('访问页面不存在')
 
def request_url(url):
    func=error
    if url in router_table:
        func=router_table[url]
    func()
 
print('开始执行函数')
request_url('index.html')
request_url('center.html')
request_url('mail.html')
request_url('test.html')
request_url('login.html')
Python 相关文章推荐
Python使用MySQLdb for Python操作数据库教程
Oct 11 Python
Python标准库之随机数 (math包、random包)介绍
Nov 25 Python
Python中文件操作简明介绍
Apr 13 Python
Python程序退出方式小结
Dec 09 Python
python实现随机梯度下降法
Mar 24 Python
解决python中os.listdir()函数读取文件夹下文件的乱序和排序问题
Oct 17 Python
Python设计模式之原型模式实例详解
Jan 18 Python
Python使用os.listdir()和os.walk()获取文件路径与文件下所有目录的方法
Apr 01 Python
python binascii 进制转换实例
Jun 12 Python
Python ORM框架Peewee用法详解
Apr 29 Python
django queryset相加和筛选教程
May 18 Python
Java ExcutorService优雅关闭方式解析
May 30 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
基于PHP magic_quotes_gpc的使用方法详解
2013/06/24 PHP
PHP使用array_fill定义多维数组的方法
2015/03/18 PHP
php实现在限定区域里自动调整字体大小的类实例
2015/04/02 PHP
php利用smtp类实现电子邮件发送
2015/10/30 PHP
Yii框架实现邮箱激活的方法【数字签名】
2016/10/18 PHP
PHP创建单例后台进程的方法示例
2017/05/23 PHP
[原创]php正则删除img标签的方法示例
2017/05/27 PHP
tp5.1框架数据库子查询操作实例分析
2020/05/26 PHP
新闻内页-JS分页
2006/06/07 Javascript
Javascript miscellanea -display data real time, using window.status
2007/01/09 Javascript
JavaScript 组件之旅(二)编码实现和算法
2009/10/28 Javascript
浅谈JSON.parse()和JSON.stringify()
2015/07/14 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
jQuery实现边框动态效果的实例代码
2016/09/23 Javascript
移动端触屏幻灯片图片切换插件idangerous swiper.js
2017/04/10 Javascript
详解如何提高 webpack 构建 Vue 项目的速度
2017/07/03 Javascript
在webstorm中配置less的方法详解
2020/09/25 Javascript
[03:10]2014DOTA2 TI马来劲旅Titan首战告捷目标只是8强
2014/07/10 DOTA
[02:22:36]《加油!DOTA》总决赛
2014/09/19 DOTA
python实现同时给多个变量赋值的方法
2015/04/30 Python
Pandas 对Dataframe结构排序的实现方法
2018/04/10 Python
django formset实现数据表的批量操作的示例代码
2019/12/06 Python
解决HTML5中的audio在手机端和微信端的不能自动播放问题
2019/11/04 HTML / CSS
法国低价在线宠物商店:bitiba.fr
2020/07/03 全球购物
JSP和EJB可以共享HttpSession么?EJB里面可以改变session里面的内容
2013/06/05 面试题
养殖人员的创业计划书范文
2013/12/26 职场文书
社区优秀志愿者材料
2014/02/02 职场文书
民族团结先进个人材料
2014/02/05 职场文书
大学专科求职信
2014/07/02 职场文书
2014年银行客户经理工作总结
2014/11/12 职场文书
离婚协议书范文
2015/01/26 职场文书
保研导师推荐信
2015/03/25 职场文书
副校长2015年教育教学工作总结
2015/07/27 职场文书
python绘制箱型图
2021/04/27 Python
python opencv检测直线 cv2.HoughLinesP的实现
2021/06/18 Python
简单聊聊Vue中的计算属性和属性侦听
2021/10/05 Vue.js