四个函数搞清 Python 作用域

简说Python

共 5031字,需浏览 11分钟

 ·

2021-07-12 10:15

↑↑↑关注后"星标"简说Python

人人都可以简单入门Python、爬虫、数据分析
 简说Python推荐 

来源: 简说Python

作者:巩庆奎

四个函数搞清 Python 作用域


Python 内置函数中,和作用域相关的函数有 locals、global、vars 以及 dir。日常常用这些函数,但时常分不清准确用法,试来试去。下面来分析这些函数是什么意思,有什么差别,一劳永逸学会 Python 作用域的相关知识点。

本文先说明这些函数最直接的功能,然后对特殊情况进行解释,最后说明这些函数有什么用。

最直接的功能

最直接和常用的功能如下:

  • locals() 返回当前局部作用域的符号表字典。
  • globals() 返回全局作用域的符号表字典。
  • vars() 相当于 locals ()
  • dir() 返回当前局部作用域的符号表字典对应的 keys()。

来看代码。

>>> import time
>>> pi = 3.1415
>>> globals()
{'__spec__': None, 'pi': 3.1415, 'time': <module 'time' (built-in)>, '__loader__': <class'_frozen_importlib.BuiltinImporter'>, '__name__''__main__''__doc__': None, '__package__': None, '__builtins__': <module 'builtins' (built-in)>}

这里导入了 time 模块,定义了 pi 全局变量。调用 globas () 输出全局变量,可见是一些系统相关的内置属性,以及定义的 pi 和导入的 time 。

出于篇幅和方便阅读考虑,之后输出都不再列出 __ 开头的属性。上例输出,去掉 __ 开头属性为:{'pi': 3.1415, 'time': <module 'time' (built-in)>},阅读更清晰。

继续调用 locals() 函数,输出当前局部作用域的变量表。因为 locals() 位于交互 REPL 界面,所以当前局部作用域实际就是全局作用域,所以两者输出一样。

>>> locals() #去掉 __ 开头的属性。
{'pi': 3.1415, 'time': <module 'time' (built-in)>}

继续,因为 vars() 相当于 locals(),所以代码globals() == locals() == vars()成立,结果为 True 。

最后调用 dir(),返回当前局部作用域的符号表字典对应的 keys()

>>> dir() #去掉 __ 开头的属性
['pi''time']

因为 dir() 返回的是局部变量字典的 keys,又因为这里局部变量和全局变量一致,加上 vars() 又相当于 locals(),所以实际上,可以得到如下等式。

>>> sorted(dir()) == sorted(globals().keys()) == sorted(locals().keys()) == sorted(vars().keys())
True

目前为止的分析中,locals 和 globals 都在全局作用域中,vars 和 dir 都没有参数,下面分析特殊情况。

特殊情况

先来分析当 locals 和 globals 位于函数内部时的情况。

locals 和 globals 位于函数内部

看如下代码

zs = 'zhangsan'

def hello(name):
    print(globals())
    print(locals())
    print(vars())
    print(dir())
    print('Hello,%s!'%name ) 

ls = 'lisi'

hello(ls) 

在函数内部,global() 返回的是全局作用域变量,所以 zs,ls 和 hello 函数都有。而 locals() 返回局部变量和自由变量,这里没有闭包,只有函数形参 name。vars() 和 dir() 和上例相同,结果如下:

{'ls''lisi''zs''zhangsan''hello': <function hello at 0x00667DB0>} 
{'name''lisi'}
{'name''lisi'}
['name']
Hello,lisi!

另外,确切地说,globals() 返回的是函数定义时的全局变量空间。所以,如果 zs 变量和 hello 函数定义在另一个文档 lib.py 中,在本程序中 from lib import hello 后,再执行,返回的是定义时的全局变量:{'zs': 'zhangsan', 'hello': <function hello at 0x00667DB0>}不会包含调用空间的全局变量 ls。

下面说明当 vars 和 dir 有参数时的情况。

vars 和 dir 带参数执行

vars 和 dir 函数有参数时的功能如下:

  • vars(obj) 返回 obj 的 dict
  • dir(obj) 返回 obj 的属性。

vars(obj) 返回模块、类、实例以及有 dict 属性的对象的 dict 属性。

模块、类以及实例中的 dict 指代模块的命名空间或属性字典。

如下代码,新建一个类和类的实例,分别对类和实例进行 vars 操作,可见:

class Man:
    def __init__(self,age,name):
        self.age = age
        self.name = name

zs = Man(21,'zhangsan')
print(vars(Man))
print(vars(zs))

这其中,类返回的是编译相关的对象,诸如弱引用、模块名、文档等。对象返回的是属性,这里是对象属性 age 和 name。

{'__weakref__': <attribute '__weakref__' of 'Man' objects>, '__dict__': <attribute '__dict__' of 'Man' objects>, '__module__''__main__''__doc__': None, '__init__': <function Man.__init__ at 0x00657390>}
{'age': 21, 'name''zhangsan'}

dir(obj) 返回对象的有效属性的名字,这个有效属性根据模块、类和对象等有所不同,大概是从 dict 中提取的,但又不全然这样。

虽然常在交互模式下 dir() 查询对象,但这查询并不完全。

看实例和类的差别。

print(set(dir(zs))-set(dir(Man)))

以上代码对 zs 实例和 Man 类的 dir() 执行结果求差集,可知对象实例与类实例相比,多了 {'age', 'name'} 两个属性,这也是 zs 实例的应有之义。

分析了半天的 globals、locals、vars和 dir,它们有什么用呢?

作用

了解、分析对象用法

我们常在 REPL 命令行中用 dir() 来查看类或对象支持的方法、拥有的属性,这在认识新包、编写程序需要提示时比较有作用。比如 import time 后,忘记 time 的方法了,可以 dir(time) 一下。

globals 和 locals 可以帮助认识函数的作用域,了解当前作用域的变量,分析局部、全局、自由变量。

另外,借助于 globals 和 Locals 可以实现动态编写代码。

动态编写代码

如下代码,用 exec 动态执行 Python 代码,生成新的变量 s。这里 exec 第一个参数时源代码,第二个参数是源代码的全局变量环境,第三个参数是源代码的局部变量环境。

取当前全局变量字典(为了用全局变量 math 中的 pi)做第二个参数。

取当前局部变量字典,并稍作修改,加入 r 局部变量,形成 loc 字典做第三个参数。

import math 
loc = locals()
loc['r'] = 10
print('exec',exec('s = math.pi * r * r'),globals(),loc)

print(s)
print(locals()['s'])

可得计算结果 314.159。用 print(s) 输出,说明这里的 s 是动态生成的。又用 locals()['s'] 输出,说明这里的 s 赋值给了局部作用域字典。

总结

本文先说明 globals ()、locals()、vars()、dir() 这些函数最直接的功能,然后对特殊情况进行解释,最后说明这些函数在理解变量作用域、分析对象、动态编码中的作用。

作者:巩庆奎,大奎,对计算机、电子信息工程感兴趣。gongqingkui at 126.com


--END--

老表荐书

图书介绍实战大数据(Hadoop+Spark+Flink)详细介绍了大数据工程师在实际工作中应该熟练掌握的大数据技术。全书共8章,分别是大数据技术概述、搭建IDEA开发环境及Linux虚拟机、基于Hadoop构建大数据平台、基于HBase和Kafka构建海量数据存储与交换系统、用户行为离线分析—构建日志采集和分析平台、基于Spark的用户行为实时分析、基于Flink的用户行为实时分析、用户行为数据可视化。

扫码即可加我微信

老表朋友圈经常有赠书/红包福利活动


学习更多:
整理了我开始分享学习笔记到现在超过250篇优质文章,涵盖数据分析、爬虫、机器学习等方面,别再说不知道该从哪开始,实战哪里找了

优秀的读者都知道,“点赞”传统美德不能丢 

浏览 30
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报