day03.17
python函数的名称空间和作用域
名称空间:
储存名字与值的内存地址映射关系的空间。
名称空间的分类:
- 内置名称空间:
python解释器自带的一些名称与值的对应关系;例如:print()、len()等等。是第一个被加载的名称空间。
其存活周期:伴随python解释器的启动而自动产生内置名称空间;随着python解释器的关闭而销毁。
len() print() open()
- 全局名称空间:
在py文件中,除了内置的函数,文件执行过程中产生的名字都是在全局名称空间中。是第二个被加载的名称空间。
其存货周期:伴随着py文件的执行而产生全局名称空间,当py文件当中所有的代码执行完毕时,py文件运行结束时即刻销毁。
name = 'jason' # 变量名name存入全局名称空间 def index(): # 函数名index存入全局名称空间 pass if True: a = 111 # 变量名a存入全局名称空间 for i in range(10): # 变量名i存入全局名称空间 pass while True: b = 222 # 变量名b存入全局名称空间
- 局部名称空间:
函数体代码运行产生的名字都会存放在局部名称空间中。函数的形参、函数内定义的名字等等都被存放在该空间当中。是最后一个被加载的名称空间。
其存货周期:伴随着函数的调用而产生局部名称空间,在函数体代码运行完毕时即刻销毁。
def index(): name = 'jason' # name存入局部名称空间
名字的查找顺序
NOTE:
- 名称空间的加载顺序是:内置名称空间>>>全局名称空间>>>局部名称空间;
- 查找一个名字,必须从三个名称空间之一找到,(基于当前位置逐步向上层空间查找!!!);查找顺序为:局部名称空间>>>全局名称空间>>>内置名称空间。
在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常。
在全局作用域查找名字时,起始位置便是全局作用域,所以先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常
- 如果函数没有被调用,那么不要去管函数体代码有多复杂 先跳过!!!
- 局部名称空间之间如果不是嵌套关系,那么互不干涉!!!名称空间的嵌套关系是在函数定义阶段就固定死的,与调用位置无关!!!
len = '我是全局名称空间中的len' def index(): len = '我是局部名称空间中的len' print(len) index() # 调用函数 函数体就会执行 就会产生局部名称空间 print(len)
def index1(): name = 'jason' def index2(): age = 18 print(name) # 报错 index1() index2()
函数的作用域
函数的作用域就是指名称空间能够作用的范围。按照名字作用范围的不同可以将三个名称空间划分为两个区域:全局作用域和局部作用域。
全局作用域:位于全局名称空间、内置名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,否则在整个文件执行过程中存活),全局有效(在任意位置都可以使用)。
内置名称空间和全局名称空间作用范围在全局作用域;在程序任意阶段任意位置均可使用,全局有效。
局部作用域:位于局部名称空间的名字一般只能作用在局部范围。那么它的作用域就是局部作用域。
该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放),局部有效且只能在函数内使用。
NOTE:
可以调用内建函数locals()和globals()来分别查看局部作用域和全局作用域的名字,查看的结果都是字典格式。在全局作用域查看到的locals()的结果等于globals()。
名字查找的关键字globals()和locals()关键字:
gloabl关键字:
表示全局范围,就是所谓的全局作用域,局部修改全局不可变类型。
在函数内,无论嵌套多少层,都可以查看到全局作用域的名字;如果想要在局部修改全局名称空间中的值且值为不可变类型时,需要提前加关键字global()申明。
x = 111 def index(): # x = 222 # 并不是在修改全局的x 而是在局部名称空间中创建了一个新的x # 如果想要在局部名称空间中修改全局名称空间中的名字 那么需要使用关键字申明 global x # 申明 修改的是全局x而不是产生新的x x = 666 index() print(x)
如果想要在局部修改全局的可变类型,不需要加关键字global()申明。
l1 = [111, 222, 333] def index(): l1.append(444) index() print(l1) # [111, 222, 333, 444]
locals()关键字:
对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局);
nonlocal x会从当前函数的外层函数开始一层层去查找名字x,若是一直到最外层函数都找不到,则会抛出异常。
局部名称空间嵌套的情况下,内层如果想要修改外层,
如果数据是不可变类型,则需要使用关键字nonlocal;
如果数据是可变类型,则不需要使用关键字nonlocal;
def index(): x = 111 # 在index的局部产生一个x=111 l1 = [11, 22, 33] def f1(): # x = 222 # 在f1的局部产生一个x=222 # print(x) # 局部名称空间嵌套 内层修改外层 # nonlocal x # x = 333 l1.append(44) f1() print(x) # 111 print(l1) # [11, 22, 33, 44] index()
函数名的多种用法:
-
函数名可以当做变量名赋值
def index(): print('from function index') print(index) res = index # 让res也指向函数体代码 print(res) res() # index()
-
函数名还可以当成函数的实参
def index(): print('from index') def func(a): print('from func') print(a) a() func(index) # 函数名当函数的实参
-
函数名还可以当做函数的返回值
def func(): print('from func') # from func return index # 将函数名当做返回值 def index(): print('from index') # <function index at 0x00000216B2FFEBF8> res = func() # res接收函数名 print(res) # 指向的是index函数的内存地址 from index res() # index()
-
函数名可以作为容器类型的元素
容器类型:内部可以存档多个元素的数据类型>>>:列表、元组、字典、集合等等
def index(): print('from index') # [11, 22, 33, 44, <function index at 0x000002B617861EA0>] l1 = [11, 22, 33, 44, index] print(l1) # from index l1[-1]() # index()
函数的嵌套
python允许创建嵌套函数。也就是说我们可以在函数里面定义函数,而且现有的作用域和变量生存周期依旧不变。
def outer(): name = "python" def inner(): # outer函数内部定义的函数 print(name) # python return inner() # 返回该内部函数 outer()
def index(): func() print('from index') def func(): index() print('from func') func()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?