VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • Python装饰器(2)

2) return formatResult return wrapper @digitalFormat def add(a:float,b:float)->float: return a+b print(add(12.09,19.12345))

其输出结果如下所示:

31.21

    通过装饰器,我们很快就达到要求。但有些情况,单纯的数值可能并没有太大意义,需要结合单位。假设上面示例返回为重量,则单位可能为g、kg等。那这种需求有没有解决办法了?示例代码如下所示:

def unit(unit:str)->str:
    def digitalFormat(func):
        def wrapper(*args,**kwargs):
            result=func(*args,**kwargs)
            formatResult=f"{round(result,2)} {unit}"
            return formatResult
        return wrapper
    return digitalFormat


@unit("kg")
def add(a:float,b:float)->float:
    return a+b

print(add(12.09,19.12345))

其输出结果如下所示:

31.21 kg

如果装饰饰器本身需要传递参数,那么再定义一层函数,将装饰的参数传入即可,是不是很简单。

2.3.5 类装饰器

1.使用类去装饰函数

    前面实现的装饰器都是针对函数而言,在实际应用中,类也可以作为装饰器。在类装饰器中主要依赖函数__call__(),每调用一个类的示例时,函数__call__()就会被执行一次,示例代码如下所示:

class Count:

    def __init__(self,func):
        self.func=func
        self.callCount=0

    def __call__(self, *args, **kwargs):
        self.callCount+=1
        print(f"call count is {self.callCount}")
        return self.func(*args,**kwargs)

@Count
def testSample():
    print("Hello, Surpass")

for i in range(3):
    print(f"first call {testSample()}")

其输出结果如下所示:

call count is 1
Hello, Surpass
first call None
call count is 2
Hello, Surpass
first call None
call count is 3
Hello, Surpass
first call None

2.使用函数去装饰类

def decorator(num):
    def wrapper(cls):
        cls.callCount=num
        return cls
    return wrapper

@decorator(10)
class Count:
    callCount = 0
    def __init__(self):
       pass

    def __call__(self, *args, **kwargs):
        self.callCount+=1
        print(f"call count is {self.callCount}")
        return self.func(*args,**kwargs)


if __name__ == '__main__':
    count=Count()
    print(count.callCount)

其输出结果如下所示:

10

2.4 何时使用装饰器

    这个需要据实际的需求而定。比如需要测试每个函数运行时间,此时可以使用装饰器,很轻松就能达到。另外装饰器也可应用到身价认证、日志记录和输入合理性检查等等。

2.5 装饰器实际案例

    在实际工作中,装饰器经常会用来记录日志和时间,示例如下所示:

from functools import wraps
import logging
import time
def logType(logType):
    def myLogger(func):
        logging.basicConfig(filename=f"{func.__name__}.log",level=logging.INFO)
        @wraps(func)
        def wrapper(*args,**kwargs):
            logging.info(f" {logType} Run with args:{args} and kwargs is {kwargs}")
            return func(*args,**kwargs)
        return wrapper
    return myLogger

def myTimer(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        startTime=time.time()
        result=func(*args,**kwargs)
        endTime=time.time()
        print(f"{func.__name__} run time is {endTime-startTime} s ")
        return result
    return wrapper

@logType("Release - ")
@myTimer
def testWrapperA(name:str,color:str)->None:
    time.sleep(5)
    print(f"{testWrapperA.__name__} input paras is {(name,color)}")

@logType("Test - ")
@myTimer
def testWrapperB(name:str,color:str)->None:
    time.sleep(5)
    print(f"{testWrapperB.__name__} input paras is {(name,color)}")


if __name__ == '__main__':
    testWrapperA("apple","red")
    testWrapperB("apple", "red")

其输出结果如下所示:

testWrapperA input paras is ('apple', 'red')
testWrapperA run time is 5.000441789627075 s
testWrapperB input paras is ('apple', 'red')
testWrapperB run time is 5.000349521636963 s

日志记录信息如下所示:

02日志记录信息.png

3.小结

    装饰器就是接受参数类型为函数或类并返回函数或类的函数,通过装饰器函数,在不改变原函数的基础上添加新的功能。

03装饰器示意图.png


相关教程