给妹子讲python-S01E18初探函数作用域

简介:

当你在一个程序中使用变量名时,python创建、改变或查找变量名都是在所谓的命名空间中进行的,也就是我们要说的变量的作用域。在代码中给一个变量赋值的地方决定了这个变量将存在于哪一个命名空间,也就是他的可见范围。

def之中的变量名和def之外的变量名并不冲突,一个在def之外被赋值(例如,在另外一个def之中或者在模块文件的顶层)的变量X与在这个def之中赋值的变量X是完全不同的变量。

所以我们看出,变量的作用域完全是由变量在程序文件中源代码的位置而决定,而不是由函数调用决定。

【妹子说】好啦,说了这么多概念,还是用例子说话吧!

 

x = 99
def func () :
x = 88
print(x)

func()
print(x)

88
99

这里就可以看出,在这个模块文件中:语句X=99,我们创建了一个名为X的全局变量(在这个函数所在的模块文件中可见),但是X=88这个赋值语句创建了一个本地变量X(只在def语句内是可见的)。

尽管这两个变量都是X,但是他们作用域可以把它们区别开来。实际上,函数的作用域有助于防止程序之中变量名的冲突,并且有助于函数成为更加独立的程序单元。

【妹子说】哦,我大概对作用域有那么点概念了。

那下面我们接着展开具体介绍函数的四个作用域:LEGB,即L本地作用域,E内嵌作用域,G全局作用域和B内置作用域。

在一个函数中定义的是本地作用域,而模块(也就是一个xxx.py文件)中定义的是全局作用域。而内置作用域,我们使用时是直接使用变量名而不需要导入任何模块,比如一些内置的函数名:print等等

这里再强调一下python中所谓的全局作用域:

全局作用域的作用范围仅限于单个文件,别被全局二字所迷惑,这里的全局指的是一个文件的顶层的变量名仅对于这个文件内部的代码而言是全局的,在python中听到全局,你就应该想到模块二字。

变量名由模块文件隔开,并且必须精确的导入一个模块文件才能够使用这个文件中使用的变量名。

再说说本地作用域:每次对函数的调用都创建一个新的本地作用域,赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量。在默认的情况下,所有函数定义的内部变量名都位于本地作用域(与函数调用相关的)内。

再来看一个例子来演示一下这两种作用域:

 

x = 99
def func (y) :
z = x + y
return z

print(func( 1 ))

100

这个例子中出现了全局作用域内变量名:x和func

因为x是在模块文件顶层注册的,所以他是全局变量;他能够在函数内部进行引用,仅仅是引用变量不需要进行全局变量声明。

也有本地作用域变量名,y,z

z和参数y都是本地变量,只在函数运行时存在,因为他们都是在函数定义内部进行赋值的,前面我们说过函数的参数也是通过赋值进行传递的。

这种变量名隔离机制存在的意义在于本地变量是作为临时的变量名,只有在函数运行的时候才需要它们,例如,y和z都只存在于函数内部,这些变量名不会与模块命名空间内的变量名(同理,与其他函数内的变量名)产生冲突。

【妹子说】那么如果一段程序中,不同作用域内的几个变量名称相同怎么办?

好问题!这正是python的LEGB变量名搜索机制要解决的问题。

当在python中使用某个变量名时,python按照L-E-G-B的顺序依次搜索四个作用域,L本地作用域,E即上一层def或者lambda的本地作用域,之后是全局作用域G,最后是内置作用域B,并且在第一处能找到作用名的地方停下来,如果变量名在这一次搜索中没有找到,python会报错。

因此按照LEGB法则中规定的变量搜索顺序,在本地作用域中的变量名是会在本地作用域中覆盖在全局作用域和内置作用域中有相同变量名的变量,全局变量名会覆盖内置的同名变量名。

【妹子说】话不多说,上例子

 

x = 88
def func () :
x = 99
print(x)

func()
print(x)

99
88

在这一段程序中,本地变量名x覆盖了全局变量名x,此时本地和全局的两个变量虽然都叫x,但他们是完全不同的变量。

 

def func():
open = 1
open('test.txt')

func()

Traceback (most recent call last ):
File "E:/12homework/12homework.py" , line 5 , in < module >
func()
File "E:/12homework/12homework.py" , line 3 , in func
open ( 'test.txt' )
TypeError: 'int' object is not callable

这个例子中,本地作用域中的变量名open就覆盖了内置作用域中的变量名open,因此再使用open去打开文件,此时的操作就无法使用,因为文件打开的open函数变量被open=1这个本地数值变量覆盖了。

强调一点:这里我们提到的只是在本地作用域去引用或者覆盖全局变量和内置变量。

但是,请注意!如果试图去修改,即在函数内部试图改变函数外部声明的值,那就得用global和nonlocal关键字了。

global关键字

之前我们说过python中的变量不用声明,直接赋值使用,但是这个global关键字看上去就像一个声明,但是他不是一个类型的声明,而是一个变量命名空间的声明,它告诉python函数打算生成一个或多个全局变量。应用他,就可以在函数内部对全局变量进行引用和修改

 

x = 88
def func () :
global x
x = 99

func()
print(x)

99

在这个例子中,我们对X加了一个global声明,以便在def之内引用并修改位于全局的变量x,而不是产生一个新的本地变量x并将其覆盖

我们再看一个综合的例子,串联起刚刚我们提到的几个知识点

 

x,y,z = 1 , 2 , 3

def all_global () :
global x
x = y + z

all_global()
print(x)

5

这个例子中,x,y,z都是全局变量,y和z只是引用值,而对于x,我们想改变他的值,因此用了global进行引用声明。


原文发布时间为:2018-09-4

本文作者:给妹子讲python

本文来自云栖社区合作伙伴“Python爱好者社区”,了解相关信息可以关注“Python爱好者社区”。

相关文章
|
2月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
209 1
|
2月前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
307 1
|
2月前
|
Java 数据处理 索引
(numpy)Python做数据处理必备框架!(二):ndarray切片的使用与运算;常见的ndarray函数:平方根、正余弦、自然对数、指数、幂等运算;统计函数:方差、均值、极差;比较函数...
ndarray切片 索引从0开始 索引/切片类型 描述/用法 基本索引 通过整数索引直接访问元素。 行/列切片 使用冒号:切片语法选择行或列的子集 连续切片 从起始索引到结束索引按步长切片 使用slice函数 通过slice(start,stop,strp)定义切片规则 布尔索引 通过布尔条件筛选满足条件的元素。支持逻辑运算符 &、|。
188 0
|
3月前
|
设计模式 缓存 监控
Python装饰器:优雅增强函数功能
Python装饰器:优雅增强函数功能
281 101
|
3月前
|
缓存 测试技术 Python
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
232 99
|
3月前
|
存储 缓存 测试技术
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
203 98
|
3月前
|
缓存 Python
Python中的装饰器:优雅地增强函数功能
Python中的装饰器:优雅地增强函数功能
|
4月前
|
Python
Python 函数定义
Python 函数定义
577 155
|
5月前
|
PHP Python
Python format()函数高级字符串格式化详解
在 Python 中,字符串格式化是一个重要的主题,format() 函数作为一种灵活且强大的字符串格式化方法,被广泛应用。format() 函数不仅能实现基本的插入变量,还支持更多高级的格式化功能,包括数字格式、对齐、填充、日期时间格式、嵌套字段等。 今天我们将深入解析 format() 函数的高级用法,帮助你在实际编程中更高效地处理字符串格式化。
577 0
|
3月前
|
算法 安全 数据安全/隐私保护
Python随机数函数全解析:5个核心工具的实战指南
Python的random模块不仅包含基础的随机数生成函数,还提供了如randint()、choice()、shuffle()和sample()等实用工具,适用于游戏开发、密码学、统计模拟等多个领域。本文深入解析这些函数的用法、底层原理及最佳实践,帮助开发者高效利用随机数,提升代码质量与安全性。
751 0

推荐镜像

更多