滚雪球学 Python 之作用域下的 global 和 nonlocal 关键字

举报
梦想橡皮擦 发表于 2021/05/26 15:20:45 2021/05/26
【摘要】 橡皮擦,一个逗趣的互联网高级网虫,新的系列,让我们一起 Be More Pythonic。 滚雪球学 Python 第二轮 已完成的文章清单 十、global 和 nonlocal 作用域10.1 Python 中的作用域10.2 global 关键字10.3 nonlocal 关键字10.4 这篇博客的总结 已完成的文章清单 滚雪球...

橡皮擦,一个逗趣的互联网高级网虫,新的系列,让我们一起 Be More Pythonic

已完成的文章清单

  1. 滚雪球学 Python 第二轮开启,进阶之路,列表与元组那些事儿
  2. 说完列表说字典,说完字典说集合,滚雪球学 Python
  3. 关于 Python 中的字符串,我在补充两点,滚雪球学 Python
  4. 列表推导式与字典推导式,滚雪球学 Python
  5. 滚雪球学 Python 之 lambda 表达式
  6. 滚雪球学 Python 之内置函数:filter、map、reduce、zip、enumerate
  7. Python 中级知识之装饰器,滚雪球学 Python
  8. 滚雪球学 Python 之闭包操作,本系列第 8 篇文章
  9. 滚雪球学 Python 之怎么玩转时间和日期库

十、global 和 nonlocal 作用域

该部分内容涉及 Python 变量作用域相关知识,变量作用域指的是变量的有效作用范围,直接理解就是 Python 中的变量不是任意位置都可以访问的,有限制条件。

一般情况下变量的作用域变化范围是 块级、函数、类、模块、包等,级别是从小到达。Python 中是没有块级作用域的,所以我们在写代码的时候,下面的代码是正确的。

if True: x = "hello world"
# 因为没有块级作用域,故 if 代码块中的变量 x 可以被外部访问到
print(x)

  
 
  • 1
  • 2
  • 3
  • 4

在 Python 中常见的块级作用域有 if 语句、for 语句、while 语句、with 上下文语句。

10.1 Python 中的作用域

上文已经提及了作用域是 Python 程序可以直接访问一个变量的作用范围,Python 的作用域一共有 4 种,分别如下:

  1. L(Local):最内层,包含局部变量,例如函数(方法)内部;
  2. E(Enclosing):包含非局部(nonlocal)也非全局(nonglobal)的变量,在嵌套函数中,函数 A 包含函数 B,在 B 中去访问 A 中的变量,作用域就是 nonlocal,直白理解就是闭包函数外的函数中的变量;
  3. G(Global):代码最外层,全局变量;
  4. B(Built-in):包含内建变量。

一个比较经典的案例如下:

# 内建作用域 Built-in
x = int(5/2)

# 全局作用域 Global
global_var = 0

def outer(): # 闭包函数外的函数中 Enclosing out_var = 1 def inner(): # 局部作用域 Local inner_var = 2

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在 Python 中变量寻找的顺序是从内到外,先局部,然后外部,在全局,在内建,这种规则叫做 LEGB 规则

增加以下学习的趣味性,你可以研究下述代码中变量是如何变化的。

len = len([])
def a(): len = 1 def b(): len = 2 print(len) b()
a()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

10.2 global 关键字

定义在函数内部的变量拥有一个局部作用域,定义在函数外部的变量拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。

# 全局变量
x = 0
def demo(): # 此时的 x 是局部变量 x = 123 print("函数内是局部变量 x = ", x)

demo()
print("函数外是全局变量 x= ", x)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

输出结果,函数内部是 123,函数外部依旧是 0

如果希望函数内部(内部作用域)可以修改外部作用域的变量,需要使用 global 关键字。

# 全局变量
x = 0

def demo(): # 此时的 x 是全局变量 global x x = 123 print("函数内是局部变量 x = ", x)

demo()
print("函数外是全局变量 x= ", x)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

此时输出的就都是 123 了,还有一点需要注意,在函数内容如果希望修改全局变量的值,global 关键字一定要写在变量操作前。

def demo(): # 此时的 x 是全局变量 x = 123 global x print("函数内是局部变量 x = ", x)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

该代码会出现语法错误:

SyntaxError: name 'x' is assigned to before global declaration

  
 
  • 1

除了以上知识外,要记住在函数内部使用一个变量,不修改值的前提下,没有声明,默认获取的是全局变量的值。

x = "全局变量"

def demo(): print(x)

demo()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

全局变量还存在一个面试真题,经常出现,请问下述代码运行结果。

x = 10

def demo(): x += 1 print(x)

demo()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结论是报错,原因就是 demo 函数运行时,会先计算 x+1,对变量进行计算之前需要进行声明与赋值,但是函数内部对 x 没有初始化操作,故报错。

10.3 nonlocal 关键字

如果要修改嵌套作用域(Enclosing 作用域)中的变量,需要 nonlocal 关键字,测试代码如下:

def outer(): num = 10 def inner(): # nonlocal 关键字 nonlocal num num = 100 print(num) inner() print(num)

outer()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果自行测试,注意 nonlocal 关键字必须是 Python3.X+版本,Python 2.X 版本会出现语法错误:

 nonlocal num ^
SyntaxError: invalid syntax`

  
 
  • 1
  • 2
  • 3

nonlocal 不能代替 global,例如下述代码,注释掉外层函数的变量声明,此时会出现 SyntaxError: no binding for nonlocal 'num' found 错误。

num = 10
def outer(): # 注释掉本行 # num = 10 def inner(): # nonlocal 关键字 nonlocal num num = 100 print(num) inner() print(num)

outer()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在多重嵌套中,nonlocal 只会上溯一层,如果上一层没有,则会继续上溯,下述代码你可以分别注释查看结果。

num = 10
def outer(): num = 100 def inner(): num = 1000 def inner1(): nonlocal num num = 10000 print(num) inner1() print(num) inner() print(num)

outer()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

局部变量和全局变量具体有哪些,可以通过 locals()globals() 两个内置函数获取。

x = "全局变量"

def demo(): y = "局部变量" print(locals()) print(x)

demo()
print(globals())
print(locals())

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

10.4 这篇博客的总结

本篇博客为大家说明了 Python 的作用域,并且对 global 和 nonlocal 关键字进行了学习,希望对你有所帮助。
相关阅读

  1. Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
  2. Python 爬虫小课,精彩 9 讲

今天是持续写作的第 107 / 200 天。
如果你想跟博主建立亲密关系,可以关注同名公众号 梦想橡皮擦,近距离接触一个逗趣的互联网高级网虫。
博主 ID:梦想橡皮擦,希望大家点赞评论收藏

文章来源: dream.blog.csdn.net,作者:梦想橡皮擦,版权归原作者所有,如需转载,请联系作者。

原文链接:dream.blog.csdn.net/article/details/114527320

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。