python语法之名称空间

名称空间与作用域

什么是名称空间

回忆:我们定义变量时,发生了什么

name = 'leethon'
"""
赋值符号右边,产生了一个数据值'leethon',我们在内存中划定一个区域,将其存进去
内存空间很大,数据值的位置需要被记录,所以记录在了变量名name中
"""

提问:变量名以及数据值的位置存在什么地方呢?

实际上,变量名及其绑定的数据值的位置也存在内存中,它们被集中放在内存中方便寻找的某一处,这个地方就是名称空间。

名称空间不仅会存储变量名,还会存储函数名等所有名字。

三大名称空间介绍

  1. 内置名称空间

    解释器级别的名称空间,存了所有内置函数和关键字的名字如:print、len、def

  2. 全局名称空间

    文件级别的名称空间,当运行py文件时,会产生一个全局名称空间,存储文件中定义的变量名、函数名还有类名(之后会讲)。

  3. 局部名称空间

    函数级别的名称空间,在调用某个函数时,会产生一个局部名称空间,存储函数中定义的变量名、函数名等。

三个名称空间在内存中是三块空间,其中存储的名字分别是自己的,但是高级别的名称空间的名称的应用范围更广。

名称空间存活周期和作用域

  • 存活周期
    1. 内置名称空间:python解释器启动则创建,关闭则销毁。
    2. 全局名称空间:py文件执行则创建,运行结束则销毁。
    3. 局部名称空间:函数体代码运行创建,函数体代码结束则销毁。
  • 作用域
    1. 内置名称空间:只要是python程序,其中的名字都可以使用。
    2. 全局名称空间:只要是当前的py文件,其中的名字在定义完就可以使用。
    3. 局部名称空间:当前函数体代码内有效。

名字的查找顺序

有时候,我们可能在函数内定义了某个变量名而在全局也定义了这个变量名,但我们在全局调用某个函数时,它内部的变量名我们并不能考虑的到,所以规则上,函数体内的局部变量名和全局中的全局变量名不应该互相影响。

所以,python规定了名称空间的作用域,而我们在使用变量时,也要搞清楚变量名在哪个名称空间中。

  • 局部名称空间内使用名字:

    局部名称空间 ---> 全局名称空间 ---> 内置名称空间

  • 全局名称空间内使用名字:

    全局名称空间 ---> 内置名称空间

ps:所以我们在变量名命名时,会规定变量名不能使用系统提供给我们的关键字,因为会优先使用局部和变量的名称而使关键字失去原本的功能。

# 例子1:两个局部变量的名称空间是独立的,互相不影响
def func1():
    name = 'jason'
    print(age)  

def func2():
   	age = 18
   	print(name)

下图是几个名称空间的作用域示意图和查找顺序:

image

当在局部作用域中使用名字,会按照从低到高的名称空间级别去找。

两个局部名称空间是独立的,不会使用对方空间中的名字,如果没在局部找到则到全局名称空间找,如果全局没找到就会去内置名称空间找。

# 例子2
x = 1
def func1():
    x=2
    def func2():
        # x = 3
        print(x)

        
    func2()
func1()

名字x的查找过程:

func2局部名称空间 ---> func1局部名称空间(找到了)

image

名字print的查找过程:

func2局部名称空间 ---> func1局部名称空间 ---> 全局名称空间---> 内置名称空间

global与nonlocal

这个关键字能让我们突破上述名称空间的限制,修改变量的值。

  1. global声明全局关键字
    x = 100
    def func():
    	global x  # 声明这个x是全局变量的x变量
    	x = 666
    	# 这里的x不是定义一个局部变量的x变量了,就是修改全局变量x的值了
    print(x)  # 100
    func()
    print(x)  # 666  # x的值被修改了
    

image

  1. nonlocal声明外层函数关键字
    x = 100
    def func1():
    	x = 200  # 目标改动值,不在全局,不在func2中,在func2外的func1中
    	def func2():
    		nonlocal x  # 声明这个x为外层函数空间中的变量x而非本函数的新变量x
    		x = 300  # 性质从定义x变为修改外层函数的变量x
    	print(x)  # 200
    	func2()
    	print(x)  # 300  # x在func2的函数体内被改变了
    func1()  # 依次打印200 和 300
    print(x)  # 100  # 全局的x没有受影响
    

练习

判断下列打印的 money的值是多少并说明理由,试着用global和nonlocal改变打印的结果。


# t1
money = 100
def index():
    money = 666	
index()
print(money)
"""
会打印100
index函数体内的money是函数体内新定义的x,它从属于局部名称空间,无法作用于全局的money
如果想在函数内对全局的x进行修改,则要在index内部先声明global x。
"""
   
# t2
money = 100
def func1():
    money = 666
    def func2():
        money = 888
    func2()
	print(money)
func1()
"""
会打印666
大概原理是和t1一样的,外层函数的名称空间无法被内部函数的同名变量修改,
只有在func2中先声明nonlocal x才能修改外层函数空间中的x。
"""
posted @ 2022-10-10 20:35  leethon  阅读(95)  评论(0编辑  收藏  举报