什么是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 相关文章推荐
使用Python3中的gettext模块翻译Python源码以支持多语言
Mar 31 Python
Python爬虫框架Scrapy实战之批量抓取招聘信息
Aug 07 Python
Python并发编程协程(Coroutine)之Gevent详解
Dec 27 Python
Django Rest framework之认证的实现代码
Dec 17 Python
python 提取key 为中文的json 串方法
Dec 31 Python
pandas取出重复数据的方法
Jul 04 Python
用Python实现最速下降法求极值的方法
Jul 10 Python
Python利用Scrapy框架爬取豆瓣电影示例
Jan 17 Python
python str字符串转uuid实例
Mar 03 Python
Python 实现自动完成A4标签排版打印功能
Apr 09 Python
Django 解决distinct无法去除重复数据的问题
May 20 Python
Pytorch 卷积中的 Input Shape用法
Jun 29 Python
Python经常使用的一些内置函数
python处理json数据文件
Python几种酷炫的进度条的方式
Python通过loop.run_in_executor执行同步代码 同步变为异步
Python Pandas解析读写 CSV 文件
宝塔更新Python及Flask项目的部署
python模板入门教程之flask Jinja
You might like
eWebEditor v3.8 商业完整版 (PHP)
2006/12/06 PHP
PHP调用MsSQL Server 2012存储过程获取多结果集(包含output参数)的详解
2013/07/03 PHP
PHP中将ip地址转成十进制数的两种实用方法
2013/08/15 PHP
PHP版微信公众平台红包API
2015/04/02 PHP
php项目中百度 UEditor 简单安装调试和调用
2015/07/15 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
phpstorm最新激活码分享亲测phpstorm2020.2.3版可用
2020/11/22 PHP
关于js获取radio和select的属性并控制的代码
2011/05/12 Javascript
ajax页面无刷新 IE下遭遇Ajax缓存导致数据不更新的问题
2012/12/11 Javascript
无缝滚动js代码通俗易懂(自写)
2013/06/19 Javascript
jQuery给多个不同元素添加class样式的方法
2015/03/26 Javascript
javascript设计模式--策略模式之输入验证
2015/11/27 Javascript
JavaScript实现网页头部进度条刷新
2017/04/16 Javascript
基于jQuery实现定位导航位置效果
2017/11/15 jQuery
小程序实现悬浮搜索框
2019/07/12 Javascript
更优雅的微信小程序骨架屏实现详解
2019/08/07 Javascript
vue keep-alive的简单总结
2021/01/25 Vue.js
Python操作CouchDB数据库简单示例
2015/03/10 Python
Python中map和列表推导效率比较实例分析
2015/06/17 Python
深入解析Python中的上下文管理器
2016/06/28 Python
Python中动态创建类实例的方法
2017/03/24 Python
Python模块文件结构代码详解
2018/02/03 Python
python list删除元素时要注意的坑点分享
2018/04/18 Python
Python socket实现的简单通信功能示例
2018/08/21 Python
python腾讯语音合成实现过程解析
2019/08/01 Python
python解析命令行参数的三种方法详解
2019/11/29 Python
利用matplotlib实现根据实时数据动态更新图形
2019/12/13 Python
Pytorch DataLoader 变长数据处理方式
2020/01/08 Python
Django之choices选项和富文本编辑器的使用详解
2020/04/01 Python
pyinstaller将含有多个py文件的python程序做成exe
2020/04/29 Python
python中threading开启关闭线程操作
2020/05/02 Python
Canvas系列之滤镜效果
2019/02/12 HTML / CSS
个人授权委托书格式
2014/08/30 职场文书
2014年教师节讲话稿5篇
2014/09/10 职场文书
关于工作经历的证明书
2014/10/11 职场文书
SQL Server一个字符串拆分多行显示或者多行数据合并成一个字符串
2022/05/25 SQL Server