python函数装饰器保存信息

1 python函数装饰器保存信息

python函数装饰器,可以通过实例属性、全局变量、非局部变量和函数属性,来保存被装饰函数的状态信息。

1.1 统计调用并跟踪

描述

通过装饰器统计函数调用次数,并且用打印来跟踪调用记录。

此装饰器用类的__call__()方法来实现。

(1) 装饰器返回实例对象;

(2) 构造函数初始化调用次数为0,记录传入的被装饰函数;

(3) 重载__call__()方法,每次调用计增一次调用次数,并且调用被装饰器函数和打印调用信息;

(4) 返回的实例对象赋值给原函数名;

(5) 调用原函数,相当于实例名(),而括号运算符自动调用__call__()方法,从而达到统计调用次数的功能。

示例

>>> class CountTrace:
    def __init__(self,func):
        self.calls=0
        self.func=func
    #实例名()运算,自动调用__call__   
    def __call__(self,*args):
        self.calls+=1
        print('调用{}{}次'.format(self.func.__name__,self.calls))
        self.func(*args)

        
>>> @CountTrace
def testct(x):
    print(x)

# testct 为 CountTrace 的实例对象
>>> testct
<__main__.CountTrace object at 0x00000173D57DFDF0>  
>>> for i in range(5):
    testct(i+1)

调用testct1次
1
调用testct2次
2
调用testct3次
3
调用testct4次
4
调用testct5次
5
>>> testct.calls
5

1.2 保存被装饰的状态信息

python的实例属性、全局变量、非局部变量和函数属性,可以保存被装饰函数的状态信息。

1.2.1 类实例属性保存被装饰函数

描述

通过类实例属性来保存被装饰函数的状态信息。

(1) 将被装饰函数赋值保存到类实例属性self.func;

(2) 每装饰一个函数就创建一个类实例;

(3) 被装饰的多个不同函数,相当于多个不同的类实例,保存各自的状态信息;

示例

>>> class CountTrace:
    def __init__(self,func):
        self.calls=0
        self.func=func
    #实例名()运算,自动调用__call__   
    def __call__(self,*args,**kargs):
        self.calls+=1
        print('调用{}{}次'.format(self.func.__name__,self.calls))
        return self.func(*args,**kargs)
>>> @CountTrace
def testct(x):
    print(x)

    
>>> @CountTrace
def testsquare(x):
    print(x**2)
>>> testct(2)
调用testct1次
2
>>> testsquare(3)
调用testsquare1次
9

1.2.2 嵌套函数global保存被装饰函数

描述

通过嵌套函数的global来保存被装饰函数的状态信息,实现被装饰函数统一计数。

(1) 定义全局比变量calls;

(2) 嵌套函数声明全局变量calls,并进行递增;

(3) 返回的wrapper赋值给各自被装饰的函数,并且共用全局变量calls,所以多个不同的被装饰函数,共用一个计数器;

示例

>>> calls=0
>>> def counttrace(func):
    def wrapper(*args,**kargs):
        global calls
        calls+=1
        print('调用{}{}次'.format(func.__name__,calls))
        return func(*args,**kargs)
    return wrapper

>>> @counttrace
def testct(x):
    print(x)

>>> @counttrace
def testsquare(x):
    print(x**2)

    
>>> testct('梯阅线条')
调用testct1次
梯阅线条
# 多个被装饰的函数共用一个计数器
>>> testsquare(3)
调用testsquare2次
9

global

描述

函数主体内部声明变量为global,则可以对函数外部的变量进行修改。

示例

>>> vg='tyxt.work'
>>> def noglobal():
    vg='梯阅线条'

>>> def hvglobal():
    global vg
    vg='梯阅线条'

>>> vg
'tyxt.work'
>>> noglobal()
>>> vg
'tyxt.work'
>>> hvglobal()
>>> vg
'梯阅线条'

1.2.3 嵌套函数nonlocal保存被装饰函数

描述

通过嵌套函数的nonlocal来保存被装饰函数的状态信息,实现对被装饰函数各自计数。

(1) 外部函数初始化变量calls=0;

(2) 嵌套函数声明nonlocal变量calls,并进行递增;

(3) 返回的wrapper赋值给各自被装饰的函数,并且使用各自的calls,多个不同的被装饰函数,各用一个计数器;

示例

>>> def counttrace(func):
    calls=0
    def wrapper(*args,**kargs):
        nonlocal calls
        calls+=1
        print('调用{}{}次'.format(func.__name__,calls))
        return func(*args,**kargs)
    return wrapper

>>> @counttrace
def testct(x):
    print(x)

>>> @counttrace
def testsquare(x):
    print(x**2)

>>> testct('梯阅线条')
调用testct1次
梯阅线条
# 多个被装饰的函数各用一个计数器
>>> testsquare(3)
调用testsquare1次
9

nonlocal

描述

python通过nonlocal修改嵌套函数的外部函数的变量。

示例

>>> def f1():
    s='tyxt.work'
    def f2():
        s='梯阅线条'
        print('f2=',s)
    f2()
    print('f1=',s)

    
>>> f1()
f2= 梯阅线条
f1= tyxt.work
>>> def f1():
    s='tyxt.work'
    def f2():
        # 通过nonlocal直接修改嵌套作用域的变量
        nonlocal s
        s='梯阅线条'
        print('f2=',s)
    f2()
    print('f1=',s)

    
>>> f1()
f2= 梯阅线条
f1= 梯阅线条

1.2.4 函数属性保存被装饰函数

描述

通过嵌套函数属性来保存被装饰函数的状态信息,实现对被装饰函数各自计数。

(1) 嵌套函数内部,通过wrapper.calls+=1,进行递增;

(2) 嵌套函数wrapper后面,对calls进行初始化;

(3) 返回的wrapper赋值给各自被装饰的函数,并且使用各自的calls,所以多个不同的被装饰函数,各用一个计数器;

示例

>>> def counttrace(func):
    def wrapper(*args,**kargs):
        wrapper.calls+=1
        print('调用{}{}次'.format(func.__name__,wrapper.calls))
        return func(*args,**kargs)
    # 定义函数 wrapper 后,再进行属性赋值
    wrapper.calls=0
    return wrapper

>>> @counttrace
def testct(x):
    print(x)

>>> @counttrace
def testsquare(x):
    print(x**2)

    
>>> testct('梯阅线条')
调用testct1次
梯阅线条
# 多个被装饰的函数各用一个计数器
>>> testsquare(3)
调用testsquare1次
9

你可能感兴趣的:(python,python)