zoukankan      html  css  js  c++  java
  • python-变量作用域

    变量作用域

    局部变量

    python不要求声明变量,但是在函数体内赋值的变量,都会被当作局部变量。

    name = 'global'
    def fun():
        name = 'fun'
        print(name)
    
    fun() #fun

    但是如果我把赋值语句写在print语句之后呢?

    name = 'global'
    def fun():
        print(name)
        name = 'fun'
    
    fun()
    #UnboundLocalError: local variable 'name' referenced before assignment

    为什么会报错呢?

    其实在python编译函数fun的时,已经把函数体内的name当作局部变量,

    但是在执行函数体内的打印语句执行时,name此时还未被赋值,所以报错UnboundLocalError。

    对于这样的情况,我们最好将函数的局部变量赋值放在第一次使用它的前面。

    global

    当然,在函数体内我们也可以直接访问全局变量name

    name = 'global'
    def fun():
        print(name)
    
    fun() #global

    但是,如果我们想在函数内更改全局变量的值,该怎么办呢?

    我们可以使用global声明函数内的变量为全局变量

    name = 'global'
    def fun():
        global name
        name = 'fun'
        print(name)
    
    fun() #fun
    print(name) #fun

    闭包

    闭包是函数和它能够访问的函数体外的变量(自由变量)组成的一个记录。

    自由变量,指未在当前作用域绑定的变量。

    def make_averager():
        series = []
        
        def averager(new_value):
            series.append(new_value)
            total_value = sum(series)
            total_count = len(series)
            return total_value / total_count
    
        return averager
    
    avg = make_averager()
    print(avg(3)) #3.0
    print(avg(5)) #4.0

    说明:当调用函数make_averager时,会产生一个闭包,这个闭包不仅包含函数averager,而且还包含自由变量series

    即使定义作用域不可用了,但是闭包仍然保存对其自由变量的绑定

    nonlocal

    但是这种做法效率并不高,因为我们每次都要对自由变量求和、计算series中元素的个数,

    其实我们只需存储目前的总值和元素个数即可,如下

    def make_averager():
        total_value = 0
        total_count = 0
        
        def averager(new_value):
            total_value += new_value
            total_count += 1
            return total_value / total_count
    
        return averager
    
    avg = make_averager()
    print(avg(3))

    但是代码会报错:UnboundLocalError: local variable 'total_value' referenced before assignmen

    这是为什么呢?

    total_value += new_value等价于total_value = total_value + new_value,这也就是说python编译器把total_value当作函数体内的局部变量。

    对于数字、字符串、元组等不可变类型来说,只能读取,不能更改,如果尝试重新绑定,如total_value = total_value + new_value,会隐式的创建局部变量total_value,

    这样total_value绑定的就不是自由变量total_value了,因此不会保存在闭包中。

    那我们有方法使python把函数内部的变量total_value当作自由变量吗?

    当然有,我们可以使用nonlocal,它的作用就是把变量标识为自由变量

    def make_averager():
        total_count = 0
        total_value = 0
        
        def averager(new_value):
            nonlocal total_value, total_count
            total_value += new_value
            total_count += 1
            return total_value / total_count
    
        return averager
    
    avg = make_averager()
    print(avg(3)) #3.0
    print(avg(5)) #4.0

    参考资料:《流畅的python》

  • 相关阅读:
    设计模-设计原则-开闭原则
    使用export/import导出和导入docker容器
    Docker学习笔记(二)
    redis-cli的一些有趣也很有用的功能
    Redis命令总结
    使用domain模块捕获异步回调中的异常
    大话程序猿眼里的高并发
    使用pm2躺着实现负载均衡
    Request —— 让 Node.js http请求变得超简单
    避免uncaughtException错误引起node.js进程崩溃
  • 原文地址:https://www.cnblogs.com/marton/p/10908447.html
Copyright © 2011-2022 走看看