首先,我们有一个需求:记录一个函数的执行次数。
我们可以设计一个全局变量,用它来记录函数的执行次数,
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__方法中也要接受参数,一般用不定长参数和关键字参数来传参。
思绪有点乱,先写到这里。