什么是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实现批量转换文件编码(批转换编码示例)
Jan 23 Python
Python实现生成简单的Makefile文件代码示例
Mar 10 Python
Python多线程编程(八):使用Event实现线程间通信
Apr 05 Python
详解Python的Django框架中的通用视图
May 04 Python
python安装mysql-python简明笔记(ubuntu环境)
Jun 25 Python
Python实现提取XML内容并保存到Excel中的方法
Sep 01 Python
opencv实现图片模糊和锐化操作
Nov 19 Python
flask框架自定义过滤器示例【markdown文件读取和展示功能】
Nov 08 Python
python selenium实现发送带附件的邮件代码实例
Dec 10 Python
Django 如何使用日期时间选择器规范用户的时间输入示例代码详解
May 22 Python
Python-typing: 类型标注与支持 Any类型详解
May 10 Python
Python 详解通过Scrapy框架实现爬取CSDN全站热榜标题热词流程
Nov 11 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
PHP @ at 记号的作用示例介绍
2014/10/10 PHP
php实现window平台的checkdnsrr函数
2015/05/27 PHP
简单介绍PHP的责任链编程模式
2015/08/11 PHP
PHP 文件锁与进程锁的使用示例
2017/08/07 PHP
laravel 判断查询数据库返回值的例子
2019/10/11 PHP
COM中获取JavaScript数组大小的代码
2009/11/22 Javascript
javascript 伪数组实现方法
2010/10/11 Javascript
iframe 父窗口和子窗口相互的调用方法集锦
2010/12/15 Javascript
JS子父窗口互相操作取值赋值的方法介绍
2013/05/11 Javascript
JavaScript实现twitter puddles算法实例
2014/12/06 Javascript
修复bash漏洞的shell脚本分享
2014/12/31 Javascript
JS实现状态栏跑马灯文字效果代码
2015/10/24 Javascript
纯JavaScript基于notie.js插件实现消息提示特效
2016/01/18 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
2016/05/24 Javascript
JavaScript简单实现弹出拖拽窗口(二)
2016/06/17 Javascript
chorme 浏览器记住密码后input黄色背景处理方法(两种)
2017/11/22 Javascript
Node.js Windows Binary二进制文件安装方法
2019/05/16 Javascript
微信小程序+腾讯地图开发实现路径规划绘制
2019/05/22 Javascript
Python+微信接口实现运维报警
2016/08/27 Python
Python 基于Twisted框架的文件夹网络传输源码
2016/08/28 Python
python实现K最近邻算法
2018/01/29 Python
Mac下Anaconda的安装和使用教程
2018/11/29 Python
Python实现的特征提取操作示例
2018/12/03 Python
python解压TAR文件至指定文件夹的实例
2019/06/10 Python
使用Pyhton集合set()实现成果查漏的例子
2019/11/24 Python
Python求解排列中的逆序数个数实例
2020/05/03 Python
利用Python实现朋友圈中的九宫格图片效果
2020/09/03 Python
python安装sklearn模块的方法详解
2020/11/28 Python
使用css如何制作时间ICON方法实践
2012/11/12 HTML / CSS
作为网站管理者应当如何防范XSS
2014/08/16 面试题
先进党支部事迹材料
2014/01/13 职场文书
见习报告格式范文
2014/11/08 职场文书
个人学习总结范文
2015/02/15 职场文书
创业计划书之牛肉汤快餐店
2019/10/08 职场文书
pytorch锁死在dataloader(训练时卡死)
2021/05/28 Python
如何利用python实现列表嵌套字典取值
2022/06/10 Python