给妹子讲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爱好者社区”。

相关文章
|
27天前
|
Python
【python从入门到精通】-- 第五战:函数大总结
【python从入门到精通】-- 第五战:函数大总结
61 0
|
24天前
|
Python
Python之函数详解
【10月更文挑战第12天】
Python之函数详解
|
25天前
|
存储 数据安全/隐私保护 索引
|
14天前
|
测试技术 数据安全/隐私保护 Python
探索Python中的装饰器:简化和增强你的函数
【10月更文挑战第24天】在Python编程的海洋中,装饰器是那把可以令你的代码更简洁、更强大的魔法棒。它们不仅能够扩展函数的功能,还能保持代码的整洁性。本文将带你深入了解装饰器的概念、实现方式以及如何通过它们来提升你的代码质量。让我们一起揭开装饰器的神秘面纱,学习如何用它们来打造更加优雅和高效的代码。
|
16天前
|
弹性计算 安全 数据处理
Python高手秘籍:列表推导式与Lambda函数的高效应用
列表推导式和Lambda函数是Python中强大的工具。列表推导式允许在一行代码中生成新列表,而Lambda函数则是用于简单操作的匿名函数。通过示例展示了如何使用这些工具进行数据处理和功能实现,包括生成偶数平方、展平二维列表、按长度排序单词等。这些工具在Python编程中具有高度的灵活性和实用性。
|
19天前
|
Python
python的时间操作time-函数介绍
【10月更文挑战第19天】 python模块time的函数使用介绍和使用。
24 4
|
20天前
|
存储 Python
[oeasy]python038_ range函数_大小写字母的起止范围_start_stop
本文介绍了Python中`range`函数的使用方法及其在生成大小写字母序号范围时的应用。通过示例展示了如何利用`range`和`for`循环输出指定范围内的数字,重点讲解了小写和大写字母对应的ASCII码值范围,并解释了`range`函数的参数(start, stop)以及为何不包括stop值的原因。最后,文章留下了关于为何`range`不包含stop值的问题,留待下一次讨论。
17 1
|
26天前
|
存储 Python
在Python中,什么是作用域
【10月更文挑战第12天】在Python中,什么是作用域
13 2
|
26天前
|
索引 Python
Python中的其他内置函数有哪些
【10月更文挑战第12天】Python中的其他内置函数有哪些
14 1
|
1月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
26 3