python 局部和全局变量分析及global和nonlocal关键字的使用

目录

全局和局部变量 

global and nonlocal

总结:


全局和局部变量 

###代码一
count = 0
def f():
    print(count)
f()

上面的count就是个全局变量,调用f函数的结果就是输出0

###代码二
count = 1
def f():
    count = count+1
    print(count)
f()

运行上面代码就会报错

UnboundLocalError: local variable 'count' referenced before assignment

赋值前引用了局部变量

再来个代码

###代码三
count = 1
def f():
    print(count)
    count = count+1
f()

发现依然报错: UnboundLocalError: local variable 'count' referenced before assignment

原因

python 在对代码编译的时候如果出现对变量进行赋值的操作,会默认将变量视作一个局部变量,不管外部是否有初始化过。如果外部有,在这个赋值的局部空间内(即上面代码的f()函数里),这些同名字的外部变量都视作不可见。

因此回到上述的代码块三,由于出现赋值,编译时f()内的count是局部变量,因此在引用时会在f() 的范围内寻找是否有count初始化,发现没有,所以报UnboundLocalError,同样print(count)时也会报错,即使print是先于count = count + 1的。

注意:这和赋值语句出现的顺序没有关系,即使赋值语句在后,前面调用了的变量依然是局部变量

而在在代码块一 中由于f()中未出现赋值情况,python 会在全局变量中寻找count,因此不会报错

在闭包中同样有上述例子

###代码四
def a():
    count = 1
    def b():
        print(count)
        count = count+1
    b()
a()

报错:UnboundLocalError: local variable 'count' referenced before assignment 

还有个老生常谈的例子

###代码五
def a():
    count = 1
    def b():
        count = 2
    b()
    print(count)
a()

这里的b()中count的赋值改变的是b()中局部变量的,不影响上一层a()中count的值 

解决办法

global and nonlocal

常规的解决方法一般是用global关键字进行声明

###代码六
count = 1
def f():
    global count
    print(count)
    count = count+1
f()

局部需要修改全局变量时可以用global进行声明

但是在闭包中使用这个global关键字可能会报错

###代码七
def a():
    count = 1
    def b():
        global count
        count = count+1
    b()
    print(count)
a()

NameError: name 'count' is not defined

###代码八
def a():
    count = 1
    print(count)
    print(id(count))
    def b():
        global count
        count = 2
        print(id(count))
    print(count)
    b()
a()
print(count)

这个代码不会报错

结果

代码七报错是因为只声明全局变量count,但是未在代码中找到全局变量count,最后count = count+1执行不了,这里的a()中的count其实是b()的上层变量,是属于局部变量。

使用pycharm的话,会发现此时count处有个灰色虚线

未定义的全局变量count

而代码八中先声明global后,count = 2,又重新赋值了,最后结果那样是因为global使count的作用域不在局部而在全局。局部函数执行完之后,不销毁函数内部以global定义的变量。

这样的问题我们可以使用下面的nonlocal关键字来解决,但是如果我们就是想用global呢?

可以这样:

def a():
    global count
    count = 1
    def b():
        global count
        count = count+1
        print(count)
    b()
    print(count)
a()

结果

 

我们在外部函数用global声明个全局变量,再在内部函数使用的时候进行声明就行

当然还可以使用nonlocal,对于在闭包中一般常用的是nonlocal关键字  

nonlocal,非局部声明变量指代的已有标识符是最近外面函数的已声明变量,一般就是类似于闭包的上一层,在递归中可以使用

###代码九
def a():
    count = 1
    def b():
        nonlocal count
        count = count+1
    b()
    print(count)
a()

 上述代码逻辑是先定义个在a函数范围的局部变量count,接着定义了个b函数,在b函数中声明count不是局部变量

nonlocal和global不同,在使用前必须事先声明,那么函数b中的nonlocal就会报错

###代码十
def a():
    def b():
        nonlocal count
        count = 1
        print(count)
    b()
a()

SyntaxError: no binding for nonlocal 'count' found

可执行的代码

def a():
    count = 1
    def b():
        nonlocal count
        count = count+1
        print(count)
    b()
    print(count)
a()

结果

总结

当你尝试在python中对一个变量进行赋值的时候,python会在编译的时候默认该变量是一个局部变量。

要明确 nonlocal 关键字是定义在闭包里面的(不定义在闭包里会抛异常SyntaxError: nonlocal declaration not allowed at module level)。 

nonlocal只能在封装函数中使用,在外部函数先进行声明,在内部函数进行nonlocal声明。

当然,为了防止因为局部和全局的报错最好还是调用参数

滴滴滴,说唱博士·TANGLOOPY 你看完了吗

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值