首页 > 编程语言 >python之名称空间和作用域(关键字:global和nonlocal的使用)

python之名称空间和作用域(关键字:global和nonlocal的使用)

时间:2024-07-24 12:55:45浏览次数:27  
标签:__ 作用域 global python 名字 名称 空间 全局

文章目录

前言

本篇文章主要讲解python中的名称空间和作用域,以及他们之间的联系,从底层出发了解其本质,理论知识偏多,请大家耐心观看。

1、名称空间和作用域

1.1 引言

我们在日常保存文件的时候,通常会遇到同名覆盖的问题,那么如何解决这个问题呢?

  1. 更改文件的名字
  2. 将同名文件放入不同的路径,也就是换个文件夹

总的来说,将文件放入不同的空间去保存,就可以避免同名覆盖的现象;那么在python中我们是如何避免这个问题的呢?

案例:

a = 1
a = 2 
print(a) # 输出结果:2,被第二个变量 a 覆盖了

def test1(b): # 形参:b
    print(b)

def b(): # 函数名:b
    pass

test1(666) # 输出结果:666

从上面可以看出,当我们定义两个 变量a时 会发生覆盖现象,而定义函数test1时使用的形参b与函数b 的名字相同,却没有发生覆盖现象,难道他们在不同空间吗?这就是本章内容需要讨论的问题了,我们接着往下看

1.2 名称空间

名称空间又称名字空间,简单来说就是存放名字的一块空间;更切确的说是存放名字和数据绑定关系的地方

  • 名称空间的意义:
    不同的空间可以存放相同的名字,名字相同不会发生冲突

  • 名称空间是对栈区的划分
    这里我们简单了下栈区是什么?大家都知道电脑在使用数据时,需要将数据从外存读取到内存,然后交由cpu来处理,而在内存中,我们又对其进行了划分,分为:
    1.、栈区:存放名字的地方,如电脑中的各种文件名
    2、 堆区:存放数据的地方,文件中的数据

视图如下:
在这里插入图片描述

  • 名称空间分为三类:
    1、内置名称空间
    2、全局名称空间
    3、局部名称空间

1.2.1 内置名称空间

伴随着python解释器的启动而产生的空间,当python解释器关闭后该空间也会被回收,因此它也是第一个被加载的空间

  • 内置名称空间的作用
    用来存放python中一些内置的名字,比如内置函数名:input、len、print 等等,这些名字不用定义就可以使用
print() # 内置函数,不用定义直接使用
ah() # 没有定义过的函数,直接使用会报错

1.2.2 全局名称空间

伴随python代码的执行而产生的空间,执行完毕后就回收,是第二个被加载的空间;只要不是局部名称空间和内置名称空间定义的名字,剩下的名字都存放在全局名称空间中

如:

a = 1
if 3>1:
	b = 5
def c()
	pass
# a、b、c 都存放在全局名称空间中

1.2.3 局部名称空间

当调用函数后,运行函数内的代码从而产生的名字,就存放在局部名称空间内;该空间在调用函数时存活,函数调用完后就会回收

如:

def a(): # 定义时函数内的代码不会执行,不会产生空间
    r1 = '哈哈' 
    r2 = 66
    # r1和r2都是局部名字
    
a() # 调用后才产生局部名称空间,执行完后销毁

1.2.4 名称空间的产生和销毁顺序

  • 产生顺序
    内置名称空间》》全局名称空间》》局部名称空间
  • 销毁顺序
    局部名称空间》》全局名称空间》》内置名称空间

python解释器启动后,会占用一部分内存,在内存中的划分一个栈区来存放名称空间;如图:
在这里插入图片描述

1.3 作用域

前面所学的名称空间就是用来引出作用域;作用域也就是名字能够作用的范围

  • 作用域分为两种类型:
    1、全局作用域
    2、局部作用域

1.3.1 全局作用域

内置名称空间和全局名称空间中的名字都属于全局作用域

  • 全局作用域的特点
    1、全局存活
    在python文件中一直存在
    2、全局有效
    名字在python文件中任意位置都可以使用

案例:

a = 666 
print(a) # 输出结果:666

def b():
    print(a) # 输出结果:666
# 可以看到 变量a属于全局名字,print属于内置名字,他们都可以在全局和局部(函数)内都可以使用

1.3.2 局部作用域

局部名称空间中的名字属于局部作用域

  • 局部作用域的特点
    1、临时存活
    只在局部名称空间产生时存在,销毁后消失
    2、局部有效
    名字只在产生自己的这个局部内起作用
def b():
    a = 666 # a 是局部名字,只能在自己这个局部内使用
    print(a) # 输出结果:666
def c():
    print(a) # 只能使用自己局部内定义的名字,报错
b()
c()    
print(a) # 不能使用局部的名字,报错

1.3.3 名字的查找顺序

当python代码执行后,程序会按顺序查找定义的名字:
局部名称空间》》全局名称空间》》内置名称空间

当名字查询到后就会停止查询,若名字在上面三个空间都无法查询,程序就会报错

案例1:

b = 1
def a():
    b = 666
    print(b) # 结果:666
a() 

在上面可以看到,函数a调用后,局部名称空间产生,那么在程序会从局部开始查找,找到后就会停止查询,输出该结果

案例2:

b = 1
def a():
    print(b) # 会报错
    b = 666
a()

从上面可以看到,在全局和局部都定义了一个 变量b,所以在调用函数后,程序会从局部开始查找得到局部的 变量b,但局部的变量b定义在 print之后,我们知道变量必须先定义在使用,这就导致了报错

1.4 关键字:global

将局部空间内的名字变为全局名称空间的名字,该名字的作用域也变成了全局
语法格式:global 变量名

案例:

a = 1
def b():
    global a # 将变量a 变为全局的名字
    a = 666
b()
print(a) # 输出结果:666

从上面可以看到,本来函数内的名字与全局内的名字是互不干扰的,但使用关键字global将变量a 变为全局的名字后,a 的值就被覆盖掉了

  • global 的本质
    函数内部(局部)不能更改全局的名字,本质上是不能修改这个名字的内存地址,如果需要修改内存地址,则需要用到 global

案例1:

a = [1,2,3] # 可变数据类型
def b():
    a.append(4) # 增加一个元素,内存地址不变
b()
print(a) # 输出结果:[1,2,3,4]

案例2:

a = [1,2,3] # 可变数据类型
def b():
    a = [66,77] # 重新定义一个列表,内存地址改变
b()
print(a) # 输出结果:[1,2,3]

说明:
从上面两个案例可以看到,在案例1中函数内为全局中列表a 增加了一个元素,但内存地址不变,从而修改了全局中的名字;在案例2中 函数内重新定义一个列表,改变了 列表a 的内存地址,所以无法修改全局的名字,只有加上 globa后,才能修改成功

  • 扩展:globas()
    得到全局作用域中所有的名字,以字典的形式打印
a = 1
def b():
    global a
    a = 666
b()
print(globals()) # 打印全局作用域中所有的名字

输出结果:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002375CC73DC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'python文件的路径', '__cached__': None, 'a': 666, 'b': <function b at 0x000002375D0181F0>}

1.5 关键字:nonlocal

如果一个函数内又定义了一个函数,也就是函数的嵌套,那么最开始的函数与它嵌套的那个函数中的名字是无法互相使用修改的,因为他们在不同的局部空间内;若想使用则需要使用关键字:nonlocal,且使用时,外层函数中的名字必须存在
语法格式:nonlocal 变量名

案例:

a = 1 # 全局变量
def b():
    a = 2 # 函数b中的局部变量
    def c():
        nonlocal a # 使函数c可以修改 函数b中a的值,但无法修改全局中的变量a的值
        a = 3 # 函数c中的局部变量
    c()
    print(a) # 输出结果:3
b()
print(a) # 输出结果:1

说明:
从上面可以看到,使用 nonlocal后内层嵌套的函数 c 就可以修改外层函数b 中的变量了,但是注意,使用关键字 nonlocal时 外层函数中必须存在该变量名,且该关键字无法作用于全局变量

  • 扩展点:关键字 locals()

locals() 在全局和局部内使用后的结果不同:

  1. 全局内:得到全局作用域内所有的名字,以字典形式打印
  2. 局部内:得到局部作用域内所有的名字,以字典形式打印

案例:

a = 1
print(locals()) # 得到全局作用域内所有的名字

def b():
 	c = 666
    print(locals()) # 得到局部作用域内所有的名字
b()

输出结果:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000235348B3DC0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/PC_pycharm/CSDN try/基础核心语法/Day 2/1.py', '__cached__': None, 'a': 1}
{'c': 666}

标签:__,作用域,global,python,名字,名称,空间,全局
From: https://blog.csdn.net/m0_59470317/article/details/140598140

相关文章

  • 用于 isinstance() 检查的 dict_keys 的显式 python3 类型是什么?
    在Python3中,我应该使用什么类型来检查字典键是否属于它?>>>d={1:2}>>>type(d.keys())<class'dict_keys'>所以我很自然地尝试了这个:>>>isinstance(d.keys(),dict_keys)Traceback(mostrecentcalllast):File"<stdin>",......
  • 初学Python时需要认识清楚的几个概念:对象、函数、圆括号给、点取、方括号取
    这是我在自学Python的过程中自己挑选和提炼出来的几个重要的概念,之所以特意介绍这些概念,其中包含了我自己的思维方式和我对Python设计理念的认识,有其独特性和局限性。我希望这篇文章能够给喜爱Python的朋友们带来一些启发。1、对象(Object)对象是Python编程的基本单元。就像音是......
  • 如何接受文件或路径作为python中方法的参数
    我正在尝试编写一个方法,该方法将接受打开的文件myFile=open("myFile.txt")obj.writeTo(myFile)myFile.close()或带有路径的字符串obj.writeTo("myFile.txt")该方法的实现如下:defwriteTo(self,hessianFile):ifisinstance(hessianFile,file):pr......
  • Python,“pathlib.Path.open()”方法和内置函数“open()”不返回“typing.IO”的实例
    我读过一些其他答案,它们似乎与现实生活中发生的事情相矛盾。尝试以下操作:fromtypingimportIOfrompathlibimportPathexample_path=Path(r"D:\Example.txt")withexample_path.open("r")asf:print(isinstance(f,IO))withopen(example_path)a......
  • 【Dison夏令营 Day 28】用 Python 创建恐龙游戏
    谁没有玩过谷歌著名的“恐龙游戏”?也许每个人都玩过这个游戏。今天,在这篇文章中,我们将帮助你用Python开发一个恐龙游戏。本教程将深入讲解每一行代码,并提供参考资料。我们将尽力让读者详细、透彻地理解这个项目。Python版恐龙游戏的任务记录包括图片文档和Python资料......
  • Python 无法 pickle 自定义类型
    我正在尝试在ProcessPool中运行一个函数,该函数将通过读取python文件并运行生成的类中的方法来加载一些自定义类。我遇到的错误是TypeError:cannotpickle'generator'object该方法需要返回一个生成器。我该如何解决这个问题,谢谢。我用谷歌搜索但没有运气。......
  • python 语法无效?
    我试图编写一些Python代码,但由于某些奇怪的原因,它重复了无效的语法,我不知道最大的问题是什么。这些行是文件中唯一的代码行。Age=int(input("Howoldareyou?:"))ifAge>=18:print("YouareaAdult!")我尝试更改行,因为这似乎是我的生气,但它没有做任何帮......
  • 如何在Python的matplotlib中将条形标签绘制到右侧并为条形标签添加标题?
    我已经在python中的matplotlib中创建了一个图表,但是以下代码中的最后一行不允许在图表之外对齐条形标签。importmatplotlib.pyplotaspltg=df.plot.barh(x=name,y=days)g.set_title("Dayspeopleshowedup")g.bar_label(g.containers[0],label_type='edge')我得......
  • 19、Python之容器:快来数一数,24678?Counter能数得更好
    引言关于数据的分组计数,前面的文章中已经涉及了很多次。眼下要进行分组计数,我们可用的方法有:1、直接使用dict进行计数,需要对首次出现的键进行判断初始化的操作;2、使用dict的setdefault()方法进行计数,代码可以简化一些,虽然方法名有点怪;3、defaultdict进行计数,可以设置自动......
  • 如何使用 C# 检查用户是否安装了最低 Python 版本并且可以访问我的代码?
    我正在开发一个C#程序,该程序必须为一项特定任务运行一些Python代码。(Python代码很复杂,是由另一个团队开发的。无法在C#中重现其功能。)我正在尝试更新我的程序的安装程序文件以解决此问题:我希望它检查用户是否(谁正在安装我的程序)已安装Python并且它满足我的最低版......