函数基础知识之名称空间和作用域
一、名称空间
1.什么是名称空间
名称空间就是存放名字(变量名或者函数名等)与对象映射/绑定关系的地方。例如x = 3,python会将内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间,del x 表示清除该绑定关系。
如果你想访问一个变量值,必须先访问对应的名称空间,拿到名字和对应的内存地址的绑定关系
2.名称空间的分类
-
内置名称空间
python提前定义过的名字,比如内置的函数名,就是存在于内置名称空间,
生命周期:python解释器启动的时候生效,解释器关闭的时候失效
-
全局名称空间
py文件执行过程中产生的名字都会存放于全局名称空间,是第二个被加载的名称空间,例如if,while,for内部定义的名字执行之后也会存放于全局名称空间。
生命周期:当启动当前py文件时全局名称生效,当前页面代码执行结束就会失效。
例如:以下名称都是全局名称空间
import sys #模块名sys
x=1 #变量名x
if x == 1:
y=2 #变量名y
def foo(x): #函数名foo
y=1
def bar():
pass
Class Bar: #类名Bar
pass -
局部名称空间
函数内部定义的所有的名字都是存放于当前函数的局部名称空间
生命周期:当你调用函数时生效,函数体最后一行代码执行结束时失效
def foo(x):
y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中 -
名称空间的加载顺序
内置名称空间--->全局名称空间--->局部名称空间
-
查找顺序
局部名称空间--->全局名称空间--->内置名称空间
在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常
在全局作用域查找名字时,起始位置便是全局作用域,所以先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常
二、作用域
1.全局作用域与局部作用域
-
全局作用域:位于全局名称空间、内置名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,否则在整个文件执行过程中存活)、全局有效(在任意位置都可以使用);
-
局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放)、局部有效(只能在函数内使用)。
只有可变类型可以在局部修改外部变量的值
注意:可以调用内建函数locals()和globals()来分别查看局部作用域和全局作用域的名字,查看的结果都是字典格式。在全局作用域查看到的locals()的结果等于globals()
-
global:可以声明全局变量(将局部变量改为全局变量)
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字 , 当实参的值为可变类型时,函数体内对该值的修改将直接反应到原值,
nonlocal:在局部名称空间声明局部变量,在局部修改上层函数的变量, 例如nonlocal x会从当前函数的外层函数开始一层层去查找名字x,若是一直到最外层函数都找不到,则会抛出异常。
三、函数对象
1.函数是第一类对象
-
函数名可以被引用
def index1():
print("from index1")
a = index1 # 不要加括号,否则会直接被执行
print(a())
-
函数名可以当作参数传递
def index2(a,b,index3):
print(a,b)
index3()
def index3():
print("你好")
index2(2,2,index3)
-
函数作为返回值
def index4():
print("from index4")
def func(a): # 将index4返回到a
return a
a = func(index4)
a()
-
函数名可以被当作容器类型的元素
def func():
print('from func')
l1 = [1, '2', func, func()]
f = l1[2]
print(f)
print(l1)
print(func())