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

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

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

目录
相关文章
|
20天前
|
Python 容器
Python学习的自我理解和想法(9)
这是我在B站跟随千锋教育学习Python的第9天,主要学习了赋值、浅拷贝和深拷贝的概念及其底层逻辑。由于开学时间紧张,内容较为简略,但希望能帮助理解这些重要概念。赋值是创建引用,浅拷贝创建新容器但元素仍引用原对象,深拷贝则创建完全独立的新对象。希望对大家有所帮助,欢迎讨论。
|
2天前
|
数据可视化 数据挖掘 大数据
1.1 学习Python操作Excel的必要性
学习Python操作Excel在当今数据驱动的商业环境中至关重要。Python能处理大规模数据集,突破Excel行数限制;提供丰富的库实现复杂数据分析和自动化任务,显著提高效率。掌握这项技能不仅能提升个人能力,还能为企业带来价值,减少人为错误,提高决策效率。推荐从基础语法、Excel操作库开始学习,逐步进阶到数据可视化和自动化报表系统。通过实际项目巩固知识,关注新技术,为职业发展奠定坚实基础。
|
11天前
|
Python
Python学习的自我理解和想法(10)
这是我在千锋教育B站课程学习Python的第10天笔记,主要学习了函数的相关知识。内容包括函数的定义、组成、命名、参数分类(必须参数、关键字参数、默认参数、不定长参数)及调用注意事项。由于开学时间有限,记录较为简略,望谅解。通过学习,我理解了函数可以封装常用功能,简化代码并便于维护。若有不当之处,欢迎指正。
|
22天前
|
存储 索引 Python
Python学习的自我理解和想法(6)
这是我在B站千锋教育学习Python的第6天笔记,主要学习了字典的使用方法,包括字典的基本概念、访问、修改、添加、删除元素,以及获取字典信息、遍历字典和合并字典等内容。开学后时间有限,内容较为简略,敬请谅解。
|
26天前
|
存储 程序员 Python
Python学习的自我理解和想法(2)
今日学习Python第二天,重点掌握字符串操作。内容涵盖字符串介绍、切片、长度统计、子串计数、大小写转换及查找位置等。通过B站黑马程序员课程跟随老师实践,非原创代码,旨在巩固基础知识与技能。
|
25天前
|
程序员 Python
Python学习的自我理解和想法(3)
这是学习Python第三天的内容总结,主要围绕字符串操作展开,包括字符串的提取、分割、合并、替换、判断、编码及格式化输出等,通过B站黑马程序员课程跟随老师实践,非原创代码。
|
21天前
|
缓存 数据安全/隐私保护 Python
python装饰器底层原理
Python装饰器是一个强大的工具,可以在不修改原始函数代码的情况下,动态地增加功能。理解装饰器的底层原理,包括函数是对象、闭包和高阶函数,可以帮助我们更好地使用和编写装饰器。无论是用于日志记录、权限验证还是缓存,装饰器都可以显著提高代码的可维护性和复用性。
31 5
|
22天前
|
Python
Python学习的自我理解和想法(7)
学的是b站的课程(千锋教育),跟老师写程序,不是自创的代码! 今天是学Python的第七天,学的内容是集合。开学了,时间不多,写得不多,见谅。
|
21天前
|
存储 安全 索引
Python学习的自我理解和想法(8)
这是我在B站千锋教育学习Python的第8天,主要内容是元组。元组是一种不可变的序列数据类型,用于存储一组有序的元素。本文介绍了元组的基本操作,包括创建、访问、合并、切片、遍历等,并总结了元组的主要特点,如不可变性、有序性和可作为字典的键。由于开学时间紧张,内容较为简略,望见谅。
|
22天前
|
存储 索引 Python
Python学习的自我理解和想法(4)
今天是学习Python的第四天,主要学习了列表。列表是一种可变序列类型,可以存储任意类型的元素,支持索引和切片操作,并且有丰富的内置方法。主要内容包括列表的入门、关键要点、遍历、合并、判断元素是否存在、切片、添加和删除元素等。通过这些知识点,可以更好地理解和应用列表这一强大的数据结构。