什么是Python变量作用域


Posted in Python onJune 03, 2020

在程序中定义一个变量时,这个变量是有作用范围的,变量的作用范围被称为它的作用域。

根据定义变量的位置,变量分为两种:

  1. 局部变量:在函数中定义的变量,包括参数,都被称为局部变量。
  2. 全局变量:在函数外面、全局范围内定义的变量,被称为全局变量。

每个函数在执行时,系统都会为该函数分配一块“临时内存空间”,所有的局部变量都被保存在这块临时内存空间内。当函数执行完成后,这块内存空间就被释放了,这些局部变量也就失效了,因此离开函数之后就不能再访问局部变量了。

全局变量意味着它们可以在所有函数内被访问。

不管是在函数的局部范围内还是在全局范围内,都可能存在多个变量,每个变量“持有”该变量的值。从这个角度来看,不管是局部范围还是全局范围,这些变量和它们的值就像一个“看不见”的字典,其中变量名就是字典的 key,变量值就是字典的 value。

实际上,Python 提供了如下三个工具函数来获取指定范围内的“变量字典”:

globals():该函数返回全局范围内所有变量组成的“变量字典”。

locals():该函数返回当前局部范围内所有变量组成的“变量字典”。

vars(object):获取在指定对象范围内所有变量组成的“变量字典”。如果不传入object 参数,vars() 和 locals() 的作用完全相同。

globals() 和 locals() 看似完全不同,但它们实际上也是有联系的,关于这两个函数的区别和联系大致有以下两点:

locals() 总是获取当前局部范围内所有变量组成的“变量字典”,因此,如果在全局范围内(在函数之外)调用 locals() 函数,同样会获取全局范围内所有变量组成的“变量字典”;而 globals() 无论在哪里执行,总是获取全局范围内所有变量组成的“变量字典”。

一般来说,使用 locals() 和 globals() 获取的“变量字典”只应该被访问,不应该被修改。但实际上,不管是使用 globals() 还是使用 locals() 获取的全局范围内的“变量字典”,都可以被修改,而这种修改会真正改变全局变量本身:但通过 locals() 获取的局部范围内的“变量字典”,即使对它修改也不会影响局部变量。

下面程序示范了如何使用 locals()、globals() 函数访问局部范围和全局范围内的“变量字典”:

def test ():
  age = 20
  # 直接访问age局部变量
  print(age) # 输出20
  # 访问函数局部范围的“变量数组”
  print(locals()) # {'age': 20}
  # 通过函数局部范围的“变量数组”访问age变量
  print(locals()['age']) # 20
  # 通过locals函数局部范围的“变量数组”改变age变量的值
  locals()['age'] = 12
  # 再次访问age变量的值
  print('xxx', age) # 依然输出20
  # 通过globals函数修改x全局变量
  globals()['x'] = 19
x = 5
y = 20
print(globals()) # {..., 'x': 5, 'y': 20}
# 在全局访问内使用locals函数,访问的是全局变量的“变量数组”
print(locals()) # {..., 'x': 5, 'y': 20}
# 直接访问x全局变量
print(x) # 5
# 通过全局变量的“变量数组”访问x全局变量
print(globals()['x']) # 5
# 通过全局变量的“变量数组”对x全局变量赋值
globals()['x'] = 39
print(x) # 输出39
# 在全局范围内使用locals函数对x全局变量赋值
locals()['x'] = 99
print(x) # 输出99

从上面程序可以清楚地看出,locals() 函数用于访问特定范围内的所有变量组成的“变量字典”,而 globals() 函数则用于访问全局范围内的全局变量组成的“变量字典”。

全局变量默认可以在所有函数内被访问,但如果在函数中定义了与全局变量同名的变量,此时就会发生局部变量遮蔽(hide)全局变量的情形。例如如下程序:

name = 'Charlie'
def test ():
  # 直接访问name全局变量
  print(name) # Charlie
test()
print(name)

上面程序中,第 4 行直接访问 name 变量,这是允许的,此时程序将会输出 Charlie。如果在此之后增加如下一行代码:

name = '孙悟空'

再次运行该程序,将会看到如下错误:

UnboundLocalError : local variable ‘name' referenced before assignment

该错误提示粗体字代码所访问的 name 变量还未定义。这是什么原因呢?这正是由于程序在 test() 函数中增加了“name='孙悟空'”一行代码造成的。

Python 语法规定,在函数内部对不存在的变量赋值时,默认就是重新定义新的局部变量。因此这行代码相当于重新定义了 name 局部变量,这样 name 全局变量就被遮蔽了,所以程序会报错。

为了避免这个问题,可以通过以下两种方式来修改上面程序:

访问被遮蔽的全局变量。如果希望程序依然能访问 name 全局变量,且在函数中可重新定义 name 局部变量,也就是在函数中可以访问被遮蔽的全局变量,此时可通过 globals() 函数来实现,将上面程序改为如下形式即可:

name = 'Charlie'
def test ():
  # 直接访问name全局变量
  print(globals()['name']) # Charlie
  name = '孙悟空'
test()
print(name) # Charlie

在函数中声明全局变量。为了避免在函数中对全局变量赋值(不是重新定义局部变量),可使用 global 语句来声明全局变量。因此,可将程序改为如下形式:

name = 'Charlie'
def test ():
  # 声明name是全局变量,后面的赋值语句不会重新定义局部变量
  global name
  # 直接访问name全局变量
  print(name) # Charlie
  name = '孙悟空'
test()
print(name) # 孙悟空

增加了“global name”声明之后,程序会把 name 变量当成全局变量,这意味着 test() 函数后面对 name 赋值的语句只是对全局变量赋值,而不是重新定义局部变量。

知识点扩展:

python3 之 变量作用域

作用域: 指命名空间可直接访问的python程序的文本区域,这里的 ‘可直接访问' 意味着:对名称的引用(非限定),会尝试在命名空间中查找名称;

  • L:local,局部作用域,即函数中定义的变量;
  • E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
  • G:globa,全局变量,就是模块级别定义的变量;
  • B:built-in,内建作用域,系统固定模块里面的变量,比如:int,bytearray等

到此这篇关于什么是Python变量作用域的文章就介绍到这了,更多相关Python变量作用域详解内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python访问MySQL封装的常用类实例
Nov 11 Python
Python实现的寻找前5个默尼森数算法示例
Mar 25 Python
详谈python在windows中的文件路径问题
Apr 28 Python
python docx 中文字体设置的操作方法
May 08 Python
python计算两个数的百分比方法
Jun 29 Python
python实现反转部分单向链表
Sep 27 Python
python向字符串中添加元素的实例方法
Jun 28 Python
python tkinter实现彩球碰撞屏保
Jul 30 Python
用Python实现二叉树、二叉树非递归遍历及绘制的例子
Aug 09 Python
python cv2.resize函数high和width注意事项说明
Jul 05 Python
解决pip install psycopg2出错问题
Jul 09 Python
Python基于argparse与ConfigParser库进行入参解析与ini parser
Feb 02 Python
Python Flask框架实现简单加法工具过程解析
Jun 03 #Python
python自定义函数def的应用详解
Jun 03 #Python
Python中的整除和取模实例
Jun 03 #Python
python 负数取模运算实例
Jun 03 #Python
Python小白学习爬虫常用请求报头
Jun 03 #Python
Python新手学习函数默认参数设置
Jun 03 #Python
python seaborn heatmap可视化相关性矩阵实例
Jun 03 #Python
You might like
PHP模板引擎SMARTY
2006/10/09 PHP
浅谈php fopen下载远程文件的函数
2016/11/18 PHP
juqery 学习之五 文档处理 包裹、替换、删除、复制
2011/02/11 Javascript
点击弹出层外区域关闭弹出层jquery特效示例
2013/08/25 Javascript
使用Javascript简单实现图片无缝滚动
2014/12/05 Javascript
AngularJs根据访问的页面动态加载Controller的解决方案
2015/02/04 Javascript
JavaScript中Number.NEGATIVE_INFINITY值的使用详解
2015/06/05 Javascript
JavaScript实现非常简单实用的下拉菜单效果
2015/08/27 Javascript
数据结构中的各种排序方法小结(JS实现)
2016/07/23 Javascript
Asp.Net之JS生成分页条的方法
2016/11/23 Javascript
webpack项目调试以及独立打包配置文件的方法
2018/02/28 Javascript
vue项目引入字体.ttf的方法
2018/09/28 Javascript
[01:09]DOTA2次级职业联赛 - 99战队宣传片
2014/12/01 DOTA
[01:14:30]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第二场 8.20.mp4
2019/08/22 DOTA
详解Python中的join()函数的用法
2015/04/07 Python
Python之多线程爬虫抓取网页图片的示例代码
2018/01/10 Python
使用Python从零开始撸一个区块链
2018/03/14 Python
Python3实现的判断回文链表算法示例
2019/03/08 Python
Django Sitemap 站点地图的实现方法
2019/04/29 Python
Python调用Windows API函数编写录音机和音乐播放器功能
2020/01/05 Python
Python3的socket使用方法详解
2020/02/18 Python
python学习将数据写入文件并保存方法
2020/06/07 Python
利用css3径向渐变做一张优惠券的示例
2018/03/22 HTML / CSS
瑞贝卡·泰勒官方网站:Rebecca Taylor
2016/09/24 全球购物
HUGO BOSS美国官方网上商店:世界知名奢侈品牌
2017/08/04 全球购物
什么是反射
2012/03/17 面试题
祖国在我心中演讲稿300字
2014/05/04 职场文书
企业年检委托书范本
2014/10/14 职场文书
2014年化验员工作总结
2014/11/18 职场文书
刑事辩护词范文
2015/05/21 职场文书
呼啸山庄读书笔记
2015/06/29 职场文书
安全生产隐患排查制度
2015/08/05 职场文书
2016年“世界气象日”广播稿
2015/12/17 职场文书
2016机关干部作风建设心得体会
2016/01/21 职场文书
大学生各类奖学金申请书
2019/06/24 职场文书
win10壁纸在哪个文件夹 win10桌面背景图片文件位置分享
2022/08/05 数码科技