百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python之模块和包:模块导入对命名空间的影响

off999 2024-11-26 07:19 34 浏览 0 评论

引言

前面文章中,关于Python解释器在模块导入行为背后所执行的操作,已经做了深入的介绍。本文打算在此基础上,结合实际代码案例,进行进一步的补充说明。同时,比较看似只是微小的导入方式的改变,可能会导致的难以理解的异常问题。

本文的主要内容有:

1、关于命名空间

2、模块导入对命名空间的影响


关于命名空间

有关于命名空间的介绍,前面已经很详细了,对此仍然不太熟悉的,可以翻看一下上一篇文章。这里,主要想就在Python中如何查看、操作命名空间做进一步的说明。

命名空间的作用,主要是用于进行代码中“名字”与对象之间绑定关系的存储。

所谓执行模型,更像是代码在命名空间上执行,从而实现对Python中对象模型的访问及修改。

所以,代码执行过程中,对名称的解析、对象的定位,都是基于命名空间来实现的。

在Python中我们可以通过几个内置函数查看命名空间的相关内容,前面已经简单提及,这里再回顾一下:

1、globals():查看当前全局命名空间的字典

2、locals():查看当前局部命名空间的字典

3、dir():返回当前代码所在范围的所有名字列表

可以先看下这几个内置函数的文档说明:

接下来,我们通过实际代码来看下,这几个内置函数的使用。

首先看代码执行前后全局命名空间的变化,直接看代码:

from rich.pretty import pprint
print("初始的全局命名空间:")
pprint(locals())
a = 10
b = 20


def add(n1, n2):
    return n1 + n2


print("定义了变量和函数后的全局命名空间:")
pprint(locals())

执行结果如下:

从执行结果可以看到,我们在代码中定义的变量和函数,都会把名称和对应的对象存储到全局命名空间的字典中。

需要说明的是,当我们在顶级代码块中,使用locals()函数时,返回的命名空间与globals()返回的是一样的,也就是都是该模块的全局命名空间。

感兴趣的,可以自行把代码中的globals()切换为locals()。


当locals()函数在函数体内进行调用时,则能看到真实的函数内部的局部命名空间中的名称及对象的绑定关系:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    pprint(locals())
    return a + n1 + n2


pprint(globals())
add(10, 20)
c = add(5, 10)
pprint(globals())

执行结果:

从执行结果中可以看出,虽然add()函数的局部命名空间中只有n1和n2两个名称,但是执行到return a + n1 + n2时,并不会报错,且成功返回了我们期望的10 + 5 + 10 = 25的结果。

所以,当函数调用时,会创建局部命名空间。函数体中的代码会在局部命名空间上执行,如果在名称解析的过程中,如果遇到局部命名空间中不存在的名称,则会去更高层级的命名空间去查找,查找顺序遵循LEGB规则。


如果我们稍微调整一下add()函数体的代码,尝试修改全局变量a的取值:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    a = 1000
    pprint(locals())
    return a + n1 + n2


pprint(globals())
add(10, 20)
add(5, 10)
pprint(globals())

执行结果:

从代码中可以看出,我在顶级代码块中定义了一个全局变量a,在函数add中尝试修改全局变量a,其实并没有成功。

因为add函数体中,a = 1000这行代码,默认是在局部命名空间中执行,所以会在局部命名空间中创建一个新的名称对象绑定关系。所以,对比前面一个程序的运行结果,局部命名空间中多了一个a局部变量的名称对象绑定。

虽然全局命名空间中也有同名的变量a,但是在函数的区局作用域中,会优先查找局部命名空间来进行名称解析。

现在陷入了一个尴尬的点,我们想要修改全局变量,却导致了在局部命名空间中新增了一个局部变量。

其实有两种做法可以实现在局部作用域(也就是函数体中),对全局变量的修改。

先来看比较粗暴的做法,既然我们的意图是修改全局变量,而全局变量的名称对象绑定是存储在全局命名空间中,那么我们直接尝试修改全局命名空间中的字典,是否就实现了对全局变量的修改呢?

可以通过如下代码来验证:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    globals()['a'] = 1000
    pprint(locals())
    return a + n1 + n2


pprint(globals())
add(10, 20)
c = add(5, 10)
pprint(globals())

我们将add()函数体中,a = 1000的代码,变换为:globals()['a'] = 1000。

看下执行结果:

从执行结果看出,这种做法,确实直接修改了全局命名空间中a变量,而且没有在局部命名空间中,引入新的局部变量,从而实现了我们的目的。

我们也可以不通过定义变量,直接通过这种操作全局命名空间字典的方式,引入新的变量,感兴趣的同学,可以自行尝试。

之所以说,这种做法比较粗鲁,一方面是因为有点繁琐,另外一方面也不太安全,稍有不慎,会影响后续代码中的命名解析。

其实,Python中有更简单的做法,就是通过global关键字,来声明变量为全局变量,代码如下:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    print(dir())
    global a
    a = 1000
    pprint(locals())
    return a + n1 + n2


pprint(globals())
add(10, 20)
c = add(5, 10)
pprint(globals())

执行结果,跟粗鲁的做法是完全相同的,这里就不再贴出来了。

此外,dir()函数,不传参时,能直接获取当前作用域中可见的名称列表,这里就不再演示了。


模块导入对命名空间的影响

接下来看一下,模块导入会对命名空间产生怎样的影响。

首先,我们定义一个m1.py的模块,代码如下:

a = 100


def add(n1, n2):
    print("在m1的add函数中")
    print(locals())
    return a + n1 + n2


print("在m1模块中")
print(dir())

然后,我们在入口文件中导入该模块,代码如下:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    print("在入口文件的add函数中")
    pprint(locals())
    return a + n1 + n2


pprint(globals())
import m1

c = add(5, 10)
d = m1.add(20, 10)
m1.a = 1000
e = m1.add(20, 10)
pprint(globals())



执行结果如下:

可以看到,通过import m1的方式导入模块,在全局命名空间中只增加了一个m1的模块名与模块对象的绑定关系。虽然我们在模块m1和入口文件中,有同名的全局变量a和add()函数,但是模块中的是通过m1.的前缀访问的。所以,可以各自访问,并不会有冲突或者覆盖的情况。


但是,如果导入方式调整为 from m1 import a, add

代码如下:

from rich.pretty import pprint

a = 10


def add(n1, n2):
    print("在入口文件的add函数中")
    pprint(locals())
    return a + n1 + n2


pprint(globals())
from m1 import a, add

d = add(20, 10)
a = 1000
e = add(20, 10)
pprint(globals())


执行结果:

从执行结果中,可以看出,通过from m1 import a, add的方式进行导入时,全局命名空间中原有的名称a和add的绑定关系发生了变化。也就是入口文件中定义的变量a和函数add()已经被覆盖。

同时会发现,不同于通过m1.a = 1000进行模块m1中全局变量的修改,这里m1中的变量a直接被加入到了入口文件的全局命名空间,所以,a = 1000,并没有影响函数add()的计算结果,因为没有真正修改add()函数中引用的m1.a变量的取值。这点,是需要格外注意的。


总结

本文首先介绍了命名空间相关的补充内容,然后演示了模块导入对命名空间的影响。需要注意的有这几点:

1、当在顶级代码块或者全局作用域中,globals()和locals()获取的命名空间字典都是相同的,都是该模块的全局命名空间。

2、在函数体内或者局部作用域中,globals()是全局命名空间,locals()则是真正的局部命名空间,只有函数的形参及函数体内定义的变量。

3、要在局部作用域中修改全局变量,可以通过globals()['变量名'] 的方式进行修改,也可以通过global关键字的方式进行修改,推进使用后一种方法。

4、import 模块名的方式,只会在全局命名空间中添加模块名与模块对象的名称绑定关系,所以,不会导致命名冲突或者相互覆盖的情况。

5、from 模块名 import xxx的导入方式,会导致模块中具体的变量名、函数名等添加到全局命名空间中,如果已经存在相同的名称,则会覆盖。最终的结果是,最后一次导入的真正生效,之前的都会被覆盖掉。此外,当模块中的函数需要访问模块中的全局变量时,此种导入方式,会导致无法修改模块全局变量的情况,需要特别注意!


感谢您的拨冗阅读,如果对您学习Python有所帮助,欢迎点赞、关注。

相关推荐

安全教育登录入口平台(安全教育登录入口平台官网)

122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...

大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)

大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...

谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)

要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...

2026-02-04 09:03 off999

电信宽带测速官网入口(电信宽带测速官网入口app)

这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...

植物大战僵尸95版手机下载(植物大战僵尸95 版下载)

1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...

免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)

1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...

2025世界杯赛程表(2025世界杯在哪个国家)

2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...

下载搜狐视频电视剧(搜狐电视剧下载安装)

搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...

pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
永久免费听歌网站(丫丫音乐网)

可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...

音乐格式转换mp3软件(音乐格式转换器免费版)

有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...

电子书txt下载(免费的最全的小说阅读器)

1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...

最好免费观看高清电影(播放免费的最好看的电影)

在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...

孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)

要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...

取消回复欢迎 发表评论: