python namespace

python程序在运行的三个过程:

  1. 启动python解释器程序
  2. 将python 程序代码.py文件读取到内存中
  3. 根据python语法,对程序代码进行解释执行

python是一种一边解释一边运行的语言,在解释的过程中,就会根据代码创建相应的数据类型、变量和函数等,而这些对应的名称会怎么存放呢,本次我们来讨论这个问题。

 

首先,我们先做了解一下定义变量时的操作,变量x=8,是在内存中的两个地方生成两个东西,一个是x,一个是8,其中,x是在栈区,8是在堆区,然后在栈区x上引用了8在堆区的内存地址,这个时候,x就是一个变量名,即产生了name,而这个name存放的位置,也就是namespace了。

内存中,栈区可分割成不同的namespace,堆区还是统一的。

在python语言中,namespace分成三种:

  1. 内置namespace,buildin,在python解释器开始运行时,就会申请生成的地方,在这里存放的都是系统内置的名称,比如python关键字,print,import等等,或者内置的变量pi;该namespace只有一个,只有当python解释器退出的时候,才会进行释放回收。
  2. 全局namespace,在程序代码解释过程中,只要不是函数体内创建的name,都存放在全局namespace中,包含变量名、函数名、类名等等。作用域整个python程序,当该python程序运行完成后,才会进行清空回收。
  3. 局部namespace,在函数体内定义的name,作用域只在函数体内,调用一次函数即会产生一次namespace,每个函数实例都会有自己的namespace,当函数调用完成后,就会释放消失。

不同的namespace之间是相互隔离的,也就是说,全局namespace中有一个变量名为x,在局部namespace中,也可以有一个变量名为x。这个是可以的。

生成顺序:1.内置namespace,2.全局namespace,3.局部namespace

销毁顺序:1.局部namespace,2.全局namespace,3.内置namespace

查找顺序:当前位置,向上查找,如果在全局,只能差全局和内置,如果在局部,三个namespace都可以查找  

局部namespace之间是相互隔离的,两个同级函数相互调用的时候,不会区对方的namespace中查找,只会在本函数定义的时候的查找空间去查找。如果是函数1嵌套在函数2的定义中,那么函数1的namespace则就属于函数2的namespace,当函数1在运行时查找name时,如果函数1内部查找不到,就会去函数2的namespace中查找。

name的查找空间,是在定义的时候就已经确定了的。  

有了namespace之后,就可以隔离了,意思就是,在不同的namespace中,可以存在相同名称的变量名,这就是后续装饰器中使用的重点。 

 

有了namespace之后,就会有作用域的概念出现了,全局作用域和局部作用域,也就是global和local,内置和全局对应的就是global,局部对应的就是local。在函数体内部定义的变量,存活空间只有local,不会影响global的内容。

当需要函数体内部对global的不可变数据类型进行修改时,需要先在修改前声明,修改的是global变量,不推荐使用,因为修改变量的原理就是创建一个新的堆区,然后将栈区的引用地址进行修改,但是如果是要修改global中的可变数据类型时,则不需要进行声明。不可变数据类型主要有整型int、字符串str,可变数据类型主要有列表list、字典dict等。 

nonlocal,直接跳出本层局部namespace,到外层区找,但不会到全局namesapce里面去找,只是在函数定义嵌套的时候才会使用。 

 

函数对象,说的就是函数名,也就是一个变量名,指向的是一个内存地址,可以作为某一个函数的返回值,这个时候应用场景是两个函数,在函数定义过程中,函数f2定义在函数f1的定义中,也就是嵌套定义,由于是定义的嵌套,所以全局namespace中只有f1函数,要想在全局中使用f2函数,可以通过在f1函数的返回值中,返回函数f2的函数名,也就是内存地址,则在全局过程中就可以使用f2函数,这就是说的函数对象的概念。  

通过函数对象,可以将localname内的内容,在全局namespace里面使用,且在调用的时候,函数的输出结果是稳定的,不受调用位置的影响。函数的闭包,闭说的就是函数的嵌套,包说的是内嵌函数使用外层函数的namespace。

函数传参数的两种方式:

  1. 直接通过在函数定义的时候进行传参,调用的时候直接调用该函数即可
  2. 通过闭包函数,将要实际要调用的函数,封闭定义在外层函数的定义过程中,然后外层函数的返回值为该内层函数的内存地址,在全局调用外层函数的时候,将返回值赋值给一个变量, 然后将变量执行调用过程,使用闭包方法,在外层函数定义的过程中,可以传递参数进去,然后在内层函数中使用该传递的参数即可。
posted @ 2020-10-04 20:02  波波波波波  阅读(972)  评论(0编辑  收藏  举报