【Python】从记录数据功能到__call__方法的探究

版权声明:欢迎交流,转载请注明出处。 https://blog.csdn.net/u013034226/article/details/82667705

首先,我们有一个需求:记录一个函数的执行次数。

我们可以设计一个全局变量,用它来记录函数的执行次数,

count_num = 0

def my_func():
    print('MyFunc Run...')
    global call_num
    count_num += 1

# 执行两次函数
my_func()
my_func()
print(count_num)

# 结果:
# MyFunc Run...
# MyFunc Run...
# 2

虽然实现了记录次数功能,但是全局变量会占用内存空间不释放,而且不安全;因为类可以记录数据(属性),而函数不行,我们可以使用__call__来实现,实现__call__后,可以将对象当做函数一样去使用,称为仿函数或函数对象;如果在创建class的时候写了__call__方法, 那么该class实例化出对象后, 对象()就是调用__call__方法。

普通对象与函数对象的区别:普通对象在执行完成后就结束了,不能保存函数执行的状态,函数对象可以保存函数的状态。

__call__方法实现:

class MyFunc(object):
    def __init__(self):
        self.__call_num = 0

    def get_call_num(self):
        return self.__call_num

    def __call__(self, *args, **kwargs):
        print('MyFunc Run...')
        self.__call_num += 1


mf = MyFunc()
# MyFun实例出的对象可以直接用mf()来调用方法,仿函数
mf()
mf()
print(mf.get_call_num())

# 这种方式利用了类的记录数据功能,也避免了全局变量的出现
# MyFunc Run...
# MyFunc Run...
# 2

函数不能记录数据,那闭包能不能实现呢?

def my_func():
    print('MyFunc Run...')

# 闭包
def outer(func):
    mysum = 0
    def inner():
        nonlocal mysum
        mysum += 1
        func()
        print(mysum)
    return inner

my_func = outer(my_func)
my_func()
my_func()


# MyFunc Run...
# 1
# MyFunc Run...
# 2

基于类用装饰器来实现呢?

class Counter(object):
    def __init__(self, func):
        self.func = func
        self.mysum = 0

    def __call__(self, *args, **kwargs):
        self.mysum += 1
        return self.func(*args, **kwargs)


@Counter
def my_func():
    print("MyFunc Run...")


for i in range(2):
    my_func()

print(my_func.mysum)


# MyFunc Run...
# MyFunc Run...
# 2

需要注意的是:类装饰器中,在__call__方法的最后,如果被装饰函数有返回值,那__call__方法中必须也必须有返回值:return self.__(*args, **kwargs),如果被装饰函数没有返回值,也可以写成:self.__(*args, **kwargs),同样,如果被装饰函数中有参数,在__call__方法中也要接受参数,一般用不定长参数和关键字参数来传参。

思绪有点乱,先写到这里。

猜你喜欢

转载自blog.csdn.net/u013034226/article/details/82667705
今日推荐