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("萌mengan")
# User
# ('萌mengan',)

类中函数使用装饰器

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

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

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

最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】

在这里插入图片描述

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值