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

 

posted @ 2019-04-23 21:52  dandyzhang  阅读(316)  评论(0编辑  收藏  举报