Python装饰器示例运用及举例-学习版

简介: Python装饰器示例运用及举例-学习版

示例1:普通装饰器

def name(n):
    def func(x):
        res = n(x+x)
        return res
    return func
@name
def run(x):     # run = name(run)
    print(x)
if __name__ == '__main__':
    run(1)
# 2
def name(n):
    def func(*x):
        res = n(x+x)
        return res
    return func
@name
def run(x):     # run = name(run)
    print(x)
if __name__ == '__main__':
    run(1)
# (1, 1)

上述二者的比较,注意传参参数。一个是普通的传值,一个是两个元组相加。

示例2:普通装饰器传值

def name(n):
    def func(x, y):
        res = n(x,y)
        return res
    return func
@name
def run(x, y):  # run = name(run)
    print(x, y)
if __name__ == '__main__':
    run(1, 2)
# 1 2

试想,如何才能实现1+2,run函数中还是name函数中

def name(n):
    def func(x, y):
        res = n(x,y)
        return res
    return func
@name
def run(x, y):  # run = name(run)
    print(x + y)
if __name__ == '__main__':
    run(1, 2)

在run函数中实现,name函数作用近似于调用的操作,也可以在name函数中实现

def name(n):
    def func(x, y):
        res = n(x,y)
        print(x + y)
        return res
    return func
@name
def run(x, y):  # run = name(run)
    # print(x + y)
    pass
if __name__ == '__main__':
    run(1, 2)

示例3-进阶:日志

import logging
def name(n):
    def func(x, y):
        res = n(x,y)
        logging.basicConfig(format='%(asctime)s  %(name)s  %(levelno)s %(filename)s '
                                   '%(lineno)d    %(message)s', level=logging.DEBUG)
        logging.info("执行了{},{},结果是{}".format(x,y,res))
        return res
    return func
@name
def run(x, y):  # run = name(run)
    return x+y
if __name__ == '__main__':
    run(1, 2)
# 2023-03-01 12:24:10,474  root  20 ceshi_test.py 10    执行了1,2,结果是3

这里的结果貌似没有指明函数,影响不大,可以看看logging模块,也可以自己加。

import logging
def name(n):
    def func(x, y):
        res = n(x,y)
        logging.basicConfig(format='%(asctime)s  %(name)s  %(levelno)s %(filename)s '
                                   '%(lineno)d  %(funcName)s %(message)s', level=logging.DEBUG)
        logging.info("执行了{},{},{},结果是{}".format(n.__name__,x,y,res))
        return res
    return func
@name
def run(x, y):  # run = name(run)
    return x+y
if __name__ == '__main__':
    run(1, 2)
# 2023-03-01 12:35:15,283  root  20 ceshi_test.py 9  func 执行了run,1,2,结果是3

可以看到,获取的运行函数其实不太一样。要想准确的获取,建议手写

示例4-进阶:时间计时器

import time
def timer(clock):
    def func(*args,**kwargs):
        start = time.time()
        res = clock(*args,**kwargs)
        print("耗时 {} S".format(time.time() - start))
        return res
    return func
@timer
def run(x, y): 
    time.sleep(1)
    print(x + y)
if __name__ == '__main__':
    run(1, 2)
# 3
# 耗时 1.0103626251220703 S

上述是在不做任何操作的情况下,单纯用来计算程序运行时间。

示例5-再进阶-带参

def outwapper(out):
    def country(cont):
        def inwapper(*args,**kwargs):
            if out == '中国':
                print("你好啊,兄弟")
            else:
                print("你是哪个国家的")
            cont(*args,**kwargs)
        return inwapper
    return country
@outwapper("中国")
def people():
    pass
if __name__ == '__main__':
    people()

是不是看起来麻烦了很多,仔细一看其实也久那么回事。传个参数,该返回的值还是得返回。

def outwapper(out):
    def country(cont):
        def inwapper(*args,**kwargs):
            if out == '中国':
                print("你好啊,兄弟")
            else:
                print("你是哪个国家的")
            cont(*args,**kwargs)
        return inwapper
    return country
@outwapper("中国")
@outwapper("俄罗斯")
def people():
    pass
if __name__ == '__main__':
    people()
# 你好啊,兄弟
# 你是哪个国家的

可以多个装饰器作用同一个函数上,也能重复使用。

示例6-高阶-类装饰器

class Time(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print(args,kwargs)
@Time
def name():
    pass
if __name__ == '__main__':
    name()

套用格式即可,__init__中的参数是必须的,因为需要传递函数。

class Time(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print(args,kwargs)
@Time
def name(x,y):
    pass
if __name__ == '__main__':
    name('清安',age=18)
# ('清安',) {'age': 18}

很明显了吧,__call__中用来接收值并处理的。

传参

class Time(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, evt):
        def wapper(*args, **kwargs):
            print(self.func, args, kwargs)
        return wapper
@Time("中国")
def name(x, y):
    pass
if __name__ == '__main__':
    name('清安', age=18)
# 中国 ('清安',) {'age': 18}

evt是啥?

class Time(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, evt):
        def wapper(*args, **kwargs):
            print(evt.__name__, args, kwargs)
        return wapper
@Time("中国")
def name(x, y):
    print(x,y)
if __name__ == '__main__':
    name('清安', age=18)
# name ('清安',) {'age': 18}

就是name函数的函数地址,如何使用evt参数呢?

class Time(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, evt):
        def wapper(*args, **kwargs):
            evt(args,kwargs)
            # print(evt.__name__, args, kwargs)
        return wapper
@Time("中国")
def name(x, y):
    print(x,y)
if __name__ == '__main__':
    name('清安', age=18)

就是这么简单。

示例7-高阶-装饰类的装饰器

def func(cls):
    def inwapper(*args,**kwargs):
        print(cls.__name__)
        print(args)
    return inwapper
@func
class User:
    def __init__(self,name):
        self.name = name
if __name__ == '__main__':
    User("清an")
# User
# ('清an',)

类中函数使用装饰器

def func(cls):
    def inwapper(x, *args, **kwargs):
        logging.basicConfig(format='%(asctime)s  %(name)s  %(levelno)s %(filename)s '
                                   '%(lineno)d  %(funcName)s %(message)s', level=logging.DEBUG)
        logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
    return inwapper
# @func
class User:
    @func
    def name(self, name, name1, age):
        # return name, name1, age
        pass
if __name__ == '__main__':
    u = User()
    u.name("清安","ANAN",age=18)
2023-03-01 18:36:36,310  root  20 ceshi_test.py 74  inwapper 执行了name,结果是<__main__.User object at 0x0000020A11DABE50>,('清安', 'ANAN'),{'age': 18}

为什么要有个x,因为self会被当作参数传递,直接把内存地址一起传走了,要么下标取值要么再来个参数接收这个self。要么类中不使用self

既然使用了self,那么装饰器中能用来调用属性吗,答案是当然可以。

def func(cls):
    def inwapper(x, *args, **kwargs):
        logging.basicConfig(format='%(asctime)s  %(name)s  %(levelno)s %(filename)s '
                                   '%(lineno)d  %(funcName)s %(message)s', level=logging.DEBUG)
        x.info = 1
        logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
    return inwapper
class User:
    info = None
    @func
    def name(self, name, name1, age):
        # return name, name1, age
        pass
if __name__ == '__main__':
    u = User()
    u.name("清安","ANAN",age=18)
    print(u.info)
# 1
# 2023-03-02 09:15:36,640  root  20 ceshi_test.py 75  inwapper 执行了name,结果是<__main__.User object at 0x0000021B20A2F5B0>,('清安', 'ANAN'),{'age': 18}

显而易见,赋值成功。再来看看对其他函数赋值。

def func(cls):
    def inwapper(x, *args, **kwargs):
        logging.basicConfig(format='%(asctime)s  %(name)s  %(levelno)s %(filename)s '
                                   '%(lineno)d  %(funcName)s %(message)s', level=logging.DEBUG)
        x.Info("QA",18)
        logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
    return inwapper
class User:
    info = None
    @func
    def name(self, name, name1, age):
        # return name, name1, age
        pass
    def Info(self,name,age):
        print("我是{},今年{}".format(name,age))
if __name__ == '__main__':
    u = User()
    u.name("清安","ANAN",age=18)
# 2023-03-02 09:19:26,910  root  20 ceshi_test.py 75  inwapper 执行了name,结果是<__main__.User object at 0x00000232FF01F5B0>,('清安', 'ANAN'),{'age': 18}
# 我是QA,今年18

示例8-伪装

from functools import wraps
def timer(value):
    def func(fun):
        # @wraps(fun)
        def inner(*args,**kwargs):
            res = fun()
            print(value)
            print(inner.__name__)
            return res
        return inner
    return func
@timer("QA")
def run():
    pass
if __name__ == '__main__':
    run()

伪装装饰器,让装饰器函数名称指向运行函数名。

此外还有一些用法,此处就不再阐述,学习完上述的示例后,你是否能自己写出一个像样的装饰器呢?

目录
打赏
0
0
0
0
8
分享
相关文章
|
17天前
|
掌握Python装饰器:轻松统计函数执行时间
掌握Python装饰器:轻松统计函数执行时间
150 76
抖音直播间采集提取工具,直播间匿名截流获客软件,Python开发【仅供学习】
这是一套基于Python开发的抖音直播间数据采集与分析系统,包含观众信息获取、弹幕监控及数据存储等功能。代码采用requests、websockets和sqlite3等...
掌握 Python 文件处理、并行处理和装饰器
本文介绍了 Python 在文件处理、并行处理以及高级功能(如装饰器、Lambda 函数和推导式)的应用。第一部分讲解了文件的基本操作、读写方法及处理大型文件的技巧,并演示了使用 Pandas 处理结构化数据的方式。第二部分探讨了多线程与多进程的并行处理,以及 `concurrent.futures` 模块的简化用法,适合不同类型的任务需求。第三部分则深入装饰器的实现与应用,包括简单装饰器、带参数的装饰器及 `functools.wraps` 的使用,同时简要介绍了 Lambda 函数和推导式的语法与场景。内容实用且全面,帮助读者掌握 Python 高效编程的核心技能。
掌握Python的高级用法:技巧、技术和实用性示例
本文分享了Python的高级用法,包括生成器、装饰器、上下文管理器、元类和并发编程等。生成器通过`yield`实现懒加载序列;装饰器用于增强函数功能,如添加日志或性能分析;上下文管理器借助`with`语句管理资源;元类动态定制类行为;并发编程利用`threading`和`asyncio`库提升任务执行效率。掌握这些高级概念可优化代码质量,解决复杂问题,提高程序性能与可维护性。
Python学习的自我理解和想法(28)
本文记录了学习Python第28天的内容——冒泡排序。通过B站千锋教育课程学习,非原创代码。文章详细介绍了冒泡排序的起源、概念、工作原理及多种Python实现方式(普通版、进阶版1和进阶版2)。同时分析了其时间复杂度(最坏、最好、平均情况)与空间复杂度,并探讨了实际应用场景(如小规模数据排序、教学示例)及局限性(如效率低下、不适用于高实时性场景)。最后总结了冒泡排序的意义及其对初学者的重要性。
Python学习的自我理解和想法(27)
本文记录了学习Python第27天的内容,主要介绍了使用Python操作PPTX和PDF的技巧。其中包括通过`python-pptx`库创建PPTX文件的详细步骤,如创建幻灯片对象、选择母版布局、编辑标题与副标题、添加文本框和图片,以及保存文件。此外,还讲解了如何利用`PyPDF2`库为PDF文件加密,涵盖安装库、定义函数、读取文件、设置密码及保存加密文件的过程。文章总结了Python在处理文档时的强大功能,并表达了对读者应用这些技能的期待。
Python学习的自我理解和想法(26)
这是一篇关于使用Python操作Word文档的学习总结,基于B站千锋教育课程内容编写。主要介绍了通过`python-docx`库在Word中插入列表(有序与无序)、表格,以及读取docx文件的方法。详细展示了代码示例与结果,涵盖创建文档对象、添加数据、设置样式、保存文件等步骤。虽为开学后时间有限下的简要记录,但仍清晰梳理了核心知识点,有助于初学者掌握自动化办公技巧。不足之处欢迎指正!
Python中使用Flask-SQLAlchemy对数据库的增删改查简明示例
这样我们就对Flask-SQLAlchemy进行了一次简明扼要的旅程,阐述了如何定义模型,如何创建表,以及如何进行基本的数据库操作。希望你在阅读后能对Flask-SQLAlchemy有更深入的理解,这将为你在Python世界中从事数据库相关工作提供极大的便利。
238 77
Python学习的自我理解和想法(25)
这是一篇关于Python操作Word文档(docx)的教程总结,基于B站千锋教育课程学习(非原创代码)。主要内容包括:1) docx库插件安装;2) 创建与编辑Word文档,如添加标题、段落、设置字体样式及保存;3) 向新或现有Word文档插入图片。通过简单示例展示了如何高效使用python-docx库完成文档操作。因开学时间有限,内容精简,后续将更新列表和表格相关内容。欢迎指正交流!
Python学习的自我理解和想法(24)
本文记录了学习Python操作Excel的第24天内容,基于B站千锋教育课程。主要介绍openpyxl插件的使用,包括安装、读取与写入Excel文件、插入图表等操作。具体内容涵盖加载工作簿、获取单元格数据、创建和保存工作表,以及通过图表展示数据。因开学时间有限,文章简要概述了各步骤代码实现,适合初学者参考学习。如有不足之处,欢迎指正!

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问