社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

安全开发:说一说Python的作用域与名称空间

唤之 • 7 年前 • 745 次点击  

0x00 前言

在这个系列的开始,介绍了Python文件操作相关的概念,这一节我会说一说对Python的作用域与名称空间的理解。

很多同学可能会觉得说的东西比较基础似乎和安全没有什么关系,其实不然。我是这么理解的,know it,then hack it.真正牛逼的漏洞都是对程序本身有深入的理解后挖出来的,『人肉扫描器』没啥意思,只有真正弄懂了基础,再去分析漏洞报告,做到举一反三,我相信0day也会随之而来。

同时,我更希望看到的是随着SDL的落地,安全意识的提高,从源头上“堵住”漏洞,走出『挖漏洞,补漏洞』的怪圈。

不罗嗦了,开始今天的主题。

0x01 Python的名称空间

什么是名称空间?

简单来说,名称空间就是存放名字与值绑定关系的地方。

这里说的名字与值,不单单指变量名与变量值之间的关系。函数名、类名等均为这里所指的名字。

名称空间是内存中一块隔离的空间。

名称空间还方便了大型项目的协作开发,Python之禅中也提到,“名称空间是一个伟大的发明,在日常开发中,我们要尽可能多的使用它。”

名称空间的分类:

名称空间共分为3类,

1、全局名称空间

2、局部名称空间

3、内置名称空间

注:变量名、函数名、类名等都是文中所指的名字。

内置名称空间,就是在Python解释器启动时生效,在Python解释器关闭时失效。像一些常见的函数,比如说print()、len()、max()等均存在于内置名称空间。

全局名称空间,定义的是文件级别的名字与值之间的绑定关系。举个例子,比如说我们在当前文件中定义变量x=1、函数def fuck:pass,等诸如此类,未在函数或类中定义的变量与值之间的绑定关系就是全局名称空间。这类名字与值之间的绑定关系,直接在Python文件的上下文中定义,未在函数或类的内部定义。

局部名称空间,定义的是函数内部名字与值之间的绑定关系。

在启动Python解释器时,内置名称空间随之生效。此时可以直接调用一些内置的函数,而不需要对该类函数进行定义。当Python解释器关闭时,内置名称空间随之失效。

执行Python文件时,Python解释器会将该Python文件级别的名字与值之间的绑定关系存放起来,存放该绑定关系的空间就是全局名称空间。当该Python文件执行完毕时,全局名称空间也随之失效。

在调用函数时,局部名称就会临时生效。函数调用结束,局部名称空间随之失效。

需要注意的是,类中定义的名字与值之间的绑定关系也可以理解为局部名称空间。与函数中的名称空间不同,类定义完,该名称空间就会产生。除非类被删除,否则这块名称空间不会被回收。

可见,名称空间的加载顺序如下:

1、先加载内置名称空间

2、再加载全局名称空间

3、最后有可能加载局部名称空间

反之,Python解释器查找名字的顺序为,先局部,再全局,最后内置。

0x02 作用域

作用域就是一个作用范围,简单理解,也跟找名字有关。

众所周知,Python的三块名称空间有:内置名称空间、全局名称空间、局部名称空间。

这几个内存空间的特点如下:

内置名称空间来说,

生效:在Python解释器启动时,内置名称空间生效。

失效:在Python解释器关闭时,内置名称空间失效。

全局名称空间呢?

生效:执行Python文件时,全局名称空间生效。

失效:当Python文件执行完毕时,全局名称空间失效。

局部名称空间:

生效:当函数被调用时,局部名称空间临时生效。

失效:函数调用结束,局部名称空间失效。

围绕Python的名称空间,其作用域一共分为两块:全局作用域、局部作用域。

全局作用域由内置名称空间、全局名称空间两部分的名字与值之间的绑定关系组成。

其特点为:全局存活,全局有效,伴随Python文件执行始终。

局部作用域由局部名称空间的名字与值之间的绑定关系构成。

其特点为:临时存活,局部有效。

总结一下,名字的查找顺寻为LEGB,即locals -> enclosing function -> globals -> builtins。

locals:代表函数内部的名字空间,包括函数内部的局部变量,和形式参数。

enclosing:外部函数嵌套的名字空间,这种形式常见于闭包中。

globals:全局变量,即文件级别定义的名字与值之间的绑定关系。函数定义所在模块的名称空间。

builtins:内置模块的名字空间。

查看作用域的两个内置函数:globals()、locals()。

globals(),用来查看全局名称空间的名字。

dir(globals()['__builtins__']),用来查看内置名称空间的名字。

在内置名称空间中,存在诸如print、max、len等名字,这就是为什么我们可以直接调用这些函数,而不需要进行定义的原因。

locals(),用来查看局部名称空间的名字。

在文件级别而不是在函数中调用locals()查看名字时,与globals()的返回值相同。

作用域关系,在函数定义时就已经确定,与调用位置无关。

x = 23333

def f1():
    def f2():
        print(x)
    return f2

f = f1()

print(f)
f()

def func():
    x = 123
    f()

func()

如上代码,由于作用域关系在函数定义时就已经确定了,即f()函数的作用域关系在定义时确定x = 23333(全局名称空间),与调用位置x=123(局部名称空间)无关,所以最后的输出结果仍为23333而不是123。

0x03 关键字global和nonlocal的引入

x = 1
def foo():
    x = 10
foo()
print(x)

该代码的执行结果为:1

x = 1
def foo():
    global x
    x = 10
foo()
print(x)

该代码的执行结果为:10

在函数内部(局部名称空间),要想修改全局名称空间内变量的值需要使用关键字global声明。

x = 1
def foo():
    x = 2
    def foo2():
        nonlocal x
        x = 13213321
    foo2()
    print('foo:'+str(x))
foo()
print(x)

该代码的执行结果为:

foo:13213321
1

在嵌套定义的函数中,要想修改上一级函数中(上一级局部名称空间)变量的值,需要使用关键字nonlocal进行声明。若上一级不存在该变量,则继续向上一级寻找,直到找到为止(仅限在函数内部)。找不到则报错。

0x04 参考链接

9. Classes - Python 3.6.4 documentation


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/nZpAaOupgb
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/7804
 
745 次点击