什么是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 相关文章推荐
下载安装setuptool和pip linux安装pip    
Jan 24 Python
教你使用python画一朵花送女朋友
Mar 29 Python
使用DataFrame删除行和列的实例讲解
Apr 08 Python
对Python3中的print函数以及与python2的对比分析
May 02 Python
Python爬虫信息输入及页面的切换方法
May 11 Python
pyqt5的QWebEngineView 使用模板的方法
Aug 18 Python
Python Pywavelet 小波阈值实例
Jan 09 Python
Python 实现文件打包、上传与校验的方法
Feb 13 Python
Python基础学习之类与实例基本用法与注意事项详解
Jun 17 Python
Django使用Channels实现WebSocket的方法
Jul 28 Python
详解pandas.DataFrame.plot() 画图函数
Jun 14 Python
python读取excel进行遍历/xlrd模块操作
Jul 12 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
很实用的一个完整email发送程序
2006/10/09 PHP
浅析PKI加密解密 OpenSSL
2013/07/01 PHP
浅析PHP微信支付通知的处理方式
2014/05/25 PHP
PHP 获取 ping 时间的实现方法
2017/09/29 PHP
thinkPHP框架实现的短信接口验证码功能示例
2018/06/20 PHP
tp5.1 框架数据库-数据集操作实例分析
2020/05/26 PHP
ext监听事件方法[初级篇]
2008/04/27 Javascript
用jquery实现学校的校历(asp.net+jquery ui 1.72)
2010/01/01 Javascript
使用PHP+JQuery+Ajax分页的实现
2013/04/23 Javascript
判断滚动条到底部的JS代码
2013/11/04 Javascript
js和css写一个可以自动隐藏的悬浮框
2014/03/05 Javascript
基于jquery的文字向上跑动类似跑马灯的效果
2014/09/22 Javascript
js点击选择文本的方法
2015/02/09 Javascript
jQuery判断多个input file 都不能为空的例子
2015/06/23 Javascript
seajs中模块依赖的加载处理实例分析
2017/10/10 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
js Element Traversal规范中的元素遍历方法
2018/04/19 Javascript
vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】
2019/03/16 Javascript
nuxt 每个页面head标签内容设置方式
2020/11/05 Javascript
python 获取当天每个准点时间戳的实例
2018/05/22 Python
简单了解django缓存方式及配置
2019/07/19 Python
python颜色随机生成器的实例代码
2020/01/10 Python
Python selenium模拟手动操作实现无人值守刷积分功能
2020/05/13 Python
python3 使用openpyxl将mysql数据写入xlsx的操作
2020/05/15 Python
python如何输出反斜杠
2020/06/18 Python
PyTorch安装与基本使用详解
2020/08/31 Python
使用HTML和CSS实现的标签云效果(附demo)
2021/02/03 HTML / CSS
Europcar比利时:租车
2019/08/26 全球购物
生物技术毕业生自荐信
2013/10/23 职场文书
体育专业个人求职信范文
2013/12/27 职场文书
化妆品店促销方案
2014/02/24 职场文书
新年团拜会主持词
2014/04/02 职场文书
国土资源局开展党的群众路线教育实践活动整改措施
2014/09/26 职场文书
2014感恩节演讲稿大全
2014/10/11 职场文书
加强机关作风建设心得体会
2014/10/22 职场文书
节水倡议书
2015/01/19 职场文书