Python 变量作用域,闭包和装饰器
from dis import dis b = 6 def f1(a): print(a)print(b) b = 9 f1(3) print(dis(f1)) # dis模块可以查看python函数字节码
解决报错的方案一:申明b全局变量
from dis import dis b = 6 def f1(a): print(a) global b print(b) b = 9 f1(3) print(dis(f1)) # dis模块可以查看python函数字节码
闭包
计算移动平均值
class Averager: def __init__(self): self.series = [] def __call__(self, new_value): self.series.append(new_value) total = sum(self.series) # 汇总 return total/len(self.series) # 求平均值 avg = Averager() print(avg(10)) print(avg(11)) print(avg(12))
通过高阶函数实现
def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series) return averager avg = make_averager() print(avg(10)) print(avg(11)) print(avg(12)) print(avg.__code__.co_varnames) # 打印局部变量 print(avg.__code__.co_freevars) # 打印自由变量 print(avg.__closure__) # series的绑定在返回的函数的__closure__属性中 print(avg.__closure__[0].cell_contents) # 这些元素是cell对象,有个cell_contents属性,保存着真正的值 # 综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定 # 注意,只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量
如果是赋值操作呢?
def make_averager(): count = 0 total = 0 def averager(new_value): count += 1 total +=new_value return total / count return averager # 这里直接执行会报错,因为count += 1 相当于count = count + 1,因此当在averager的定义体内为count赋值,会把count变成局部变量。total变量也是同理
解决方案
# 引入nonlocal声明,作用是把变量标记为自由变量 def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total count += 1 total += new_value return total / count return averager
装饰器代码一
def deco(func): def inner(*args, **kwargs): print('this is inner') return inner @deco def foo(): print('this is foo') foo() # this is inner print(foo.__name__) # inner
装饰器代码二
def wrap(func): def deco(*args, **kwargs): print('deco ==> ', args, kwargs) func(*args, **kwargs) print('this is inner') return deco @wrap def foo(*args, **kwargs): print('this is foo') foo() # deco ==> () {} # this is foo # this is inner print(foo.__name__) # deco
装饰器代码三
from functools import wraps def wrap(func): @wraps(func) def deco(*args, **kwargs): print('deco ==> ', args, kwargs) func(*args, **kwargs) print('this is inner') return deco @wrap def foo(*args, **kwargs): print('this is foo') foo() # deco ==> () {} # this is foo # this is inner print(foo.__name__) # foo
有空讲解0.0