装饰器在python中真的很重要,几乎所有的框架都在用装饰器,装饰器Python面试中避不开的话题,今天我们就来彻底搞清楚装饰器
1 一个有状态的类
代码是枯燥的,结合生活中的实例就会变得很有意思,我们定义一个类,这个类的作用是计算平均数,语言上可能不是很好描述,直接敲代码。
方式一
class MakeAvg:
"""
定义一个有状态的求序列平均数的类
"""
def __init__(self):
self.total = []
def avg(self,val):
self.total.append(val)
return f'{self.total}的平均数是{sum(self.total) / len(self.total)}'
if __name__ == '__main__':
make_avg = MakeAvg()
avg = make_avg.avg(10)
print(avg)
avg = make_avg.avg(11)
print(avg)
avg = make_avg.avg(12)
print(avg)
"""
OUT:
[10]的平均数是10.0
[10, 11]的平均数是10.5
[10, 11, 12]的平均数是11.0
"""
通过结果可以看的出来,这个类是一个有状态的类,实例属性total是可以累加的
方式二
class MakeAvg:
"""
定义一个有状态的求序列平均数的类
"""
def __init__(self):
self.total = 0
self.count = 0
def avg(self,val):
self.total += val
self.count += 1
return f'{self.count}个数的和={self.total}的平均数是{self.total / self.count}'
if __name__ == '__main__':
make_avg = MakeAvg()
avg = make_avg.avg(10)
print(avg)
avg = make_avg.avg(11)
print(avg)
avg = make_avg.avg(12)
print(avg)
"""
OUT:
1个数的和=10的平均数是10.0
2个数的和=21的平均数是10.5
3个数的和=33的平均数是11.0
"""
1 一个有状态的函数“闭包”
def make_avg():
total = []
def inner(val):
total.append(val)
avg = sum(total)/len(total)
return avg
return inner
if __name__ == '__main__':
avg = make_avg()
print(avg)
res = avg(10)
print(res)
res = avg(11)
print(res)
res = avg(12)
print(res)
print(avg.__code__.co_varnames)
print(avg.__code__.co_freevars)
print(avg.__closure__[0].cell_contents)
"""
OUT:
<function make_avg.<locals>.inner at 0x0000023364622A60>
10.0
10.5
11.0
('val', 'avg')
('total',)
[10, 11, 12]
"""
闭包就是能够读取其他函数内部变量的函数,一个函数内部的函数,也就是嵌套函数,执行的过程中不会释放自由变量
def make_avg():
total = 0
count = 0
def inner(val):
total += val
count += 1
return total/count
return inner
if __name__ == '__main__':
avg = make_avg()
print(avg)
res = avg(10)
print(res)
res = avg(11)
print(res)
res = avg(12)
print(res)
print(avg.__code__.co_varnames)
print(avg.__code__.co_freevars)
print(avg.__closure__[0].cell_contents)
"""
OUT:
<function make_avg.<locals>.inner at 0x0000025C36682A60>
UnboundLocalError: local variable 'total' referenced before assignment
"""
我先解决这个报错然后再解释出现这种状况的原因
...
nonlocal total, count
...
上面和下面的代码我就不写了,直接把nonlocal这行注释打开程序就不会报错了,读者自己可以试一下,这是为什么呢? 这是Python可变类型与不可变类型的原因,列表是一个可变数据类型,对列表进行append操作不会更改列表的在内存中的地址,但是对于int型数据,total += val 等价于 total = total +val 左边的total等于一个新变量,但是这个变量没有在当前作用域中进行声明,所以会报错,python3中给了一个nonlocal关键字,作用就是让这个变量去自由变量里面去查找看看有没有定义,如果有,那就应用自由变量的定义。
|