• 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

  • 相关阅读:
    15.scrapy中selenium的应用
    14.UA池和代理池
    17.基于scrapy-redis两种形式的分布式爬虫
    08.Python网络爬虫之图片懒加载技术、selenium和PhantomJS
    05.Python网络爬虫之三种数据解析方式
    06.Python网络爬虫之requests模块(2)
    04.Python网络爬虫之requests模块(1)
    16.Python网络爬虫之Scrapy框架(CrawlSpider)
    10.scrapy框架简介和基础应用
    Python网络爬虫第三弹《爬取get请求的页面数据》
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/10759265.html
Copyright © 2020-2023  润新知