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()

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

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

目录
相关文章
|
1月前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
104 61
Python装饰器实战:打造高效性能计时工具
|
1月前
|
设计模式 前端开发 Shell
Python装饰器是什么?
装饰器是Python中用于动态修改函数、方法或类功能的工具,无需改变原代码。通过将函数作为参数传递并返回新函数,装饰器可以在原函数执行前后添加额外逻辑。例如,使用`@logger`装饰器可以打印函数调用日志,而`@timethis`则可用于计算函数执行时间。为了保持被装饰函数的元信息(如`__name__`和`__doc__`),可使用`functools.wraps`装饰器。此外,带参数的装饰器可通过嵌套函数实现,如`@timeitS(2)`,以根据参数条件输出特定信息。
90 59
|
2月前
|
Python 容器
Python学习的自我理解和想法(9)
这是我在B站跟随千锋教育学习Python的第9天,主要学习了赋值、浅拷贝和深拷贝的概念及其底层逻辑。由于开学时间紧张,内容较为简略,但希望能帮助理解这些重要概念。赋值是创建引用,浅拷贝创建新容器但元素仍引用原对象,深拷贝则创建完全独立的新对象。希望对大家有所帮助,欢迎讨论。
|
24天前
|
数据挖掘 数据处理 开发者
Python3 自定义排序详解:方法与示例
Python的排序功能强大且灵活,主要通过`sorted()`函数和列表的`sort()`方法实现。两者均支持`key`参数自定义排序规则。本文详细介绍了基础排序、按字符串长度或元组元素排序、降序排序、多条件排序及使用`lambda`表达式和`functools.cmp_to_key`进行复杂排序。通过示例展示了如何对简单数据类型、字典、类对象及复杂数据结构(如列车信息)进行排序。掌握这些技巧可以显著提升数据处理能力,为编程提供更强大的支持。
30 10
|
2月前
|
Python
Python学习的自我理解和想法(10)
这是我在千锋教育B站课程学习Python的第10天笔记,主要学习了函数的相关知识。内容包括函数的定义、组成、命名、参数分类(必须参数、关键字参数、默认参数、不定长参数)及调用注意事项。由于开学时间有限,记录较为简略,望谅解。通过学习,我理解了函数可以封装常用功能,简化代码并便于维护。若有不当之处,欢迎指正。
|
1月前
|
数据可视化 数据挖掘 大数据
1.1 学习Python操作Excel的必要性
学习Python操作Excel在当今数据驱动的商业环境中至关重要。Python能处理大规模数据集,突破Excel行数限制;提供丰富的库实现复杂数据分析和自动化任务,显著提高效率。掌握这项技能不仅能提升个人能力,还能为企业带来价值,减少人为错误,提高决策效率。推荐从基础语法、Excel操作库开始学习,逐步进阶到数据可视化和自动化报表系统。通过实际项目巩固知识,关注新技术,为职业发展奠定坚实基础。
|
2月前
|
存储 索引 Python
Python学习的自我理解和想法(6)
这是我在B站千锋教育学习Python的第6天笔记,主要学习了字典的使用方法,包括字典的基本概念、访问、修改、添加、删除元素,以及获取字典信息、遍历字典和合并字典等内容。开学后时间有限,内容较为简略,敬请谅解。
|
2月前
|
存储 程序员 Python
Python学习的自我理解和想法(2)
今日学习Python第二天,重点掌握字符串操作。内容涵盖字符串介绍、切片、长度统计、子串计数、大小写转换及查找位置等。通过B站黑马程序员课程跟随老师实践,非原创代码,旨在巩固基础知识与技能。
|
2月前
|
程序员 Python
Python学习的自我理解和想法(3)
这是学习Python第三天的内容总结,主要围绕字符串操作展开,包括字符串的提取、分割、合并、替换、判断、编码及格式化输出等,通过B站黑马程序员课程跟随老师实践,非原创代码。
|
2月前
|
缓存 数据安全/隐私保护 Python
python装饰器底层原理
Python装饰器是一个强大的工具,可以在不修改原始函数代码的情况下,动态地增加功能。理解装饰器的底层原理,包括函数是对象、闭包和高阶函数,可以帮助我们更好地使用和编写装饰器。无论是用于日志记录、权限验证还是缓存,装饰器都可以显著提高代码的可维护性和复用性。
48 5

热门文章

最新文章