【一】名称空间
【1】什么是名称空间
- 名称空间就是存放函数名与函数值对应关系的地方
- 内存空间就是申请一块内存空间,然后将函数值放到内存空间里
- 再将变量名和变量值绑定存到名称空间里
- 程序执行期间最多会存在三种名称空间
【2】内置名称空间
- 会跟着python解释器的启动而生成,关闭而结束
- 一般会用来存放一些内置的名字,比如if、else、def等
【3】全局名称空间
- 随着Python文件的执行而产生,执行结束而回收
- 函数的形参、函数内定义的名字都会被存放于该名称空间中
#列表的ID不变,它不会因为列表中元素的修改而改变
num_list = []
print(id(num_list)) # 1200291395392
def add_list(num):
num_list.append(num)
print(id(num_list)) # 1200291395392
add_list(1)
add_list(2)
add_list(3)
print(num_list) # [1, 2, 3]
print(id(num_list)) # 1200291395392
【4】局部名称空间
- 在函数内部或者类内部定义的变量,随着函数的调用而产生,结束而消失
- 函数的形参、函数内定义的名字都会被存放于该名称空间中
def num(a)
b = 1
【5】名称空间的加载和查找顺序
- 加载顺序
- 内置名称空间--->全局名称空间--->局部名称空间
- 而查找一个名字,必须从三个名称空间之一找到,查找顺序:
- 局部名称空间--->全局名称空间--->内置名称空间
【二】作用域
【1】变量作用域
- 变量的作用域:
- Python是静态作用域,也就是说Python中,变量的作用域源于它在代码中的位置
- 在不同的位置,可能有不同的命名空间。命名空间是变量作用域的体现形式
- 变量作用域分别有4种:
- Local(局部变量)
- Enclosed(嵌套)
- Global(全局)
- Built-in(内置)
(1)Local(局部变量)
- 暂时的存在,依赖于创建该局部作用域的函数。函数在,局部变量就在,函数无,局部变量就无
- 作用范围:当前整个函数体范围
# 函数内部就是局部作用域
def outside():
a = 1 #存在于函数内部的变量
print(a) # 1
outside() #调用函数找不到a,因为a不在全局作用域中
print(a)
'''
Traceback (most recent call last):
File "D:\Python\pythonProject\pythonProject1\demo7.py", line 397, in <module>
print(a)
NameError: name 'a' is not defined
'''
(2)Enclosed(嵌套)
- 一般是在函数中嵌套函数的时候,外层函数的变量作用域。
- 作用范围:闭包函数
def outside():
a = 1
print(a) # 1
def inside():
# 函数inside就是嵌套作用域
print(a) # 1
inside()
outside()
(3)Global(全局)
- 一般模块文件顶层声明的变量具有全局作用域,从外部来看,模块的全局变量就是一个模块对象的属性,仅限于单个模块文件中。
- 作用范围:当前模块(文件)
a = 1 # 全局变量
# 定义在全局的变量,在本文件任意位置可调用该变量
def outside():
print(a) # 1
outside()
print(a) # 1
(4)Built-in(内置)
- Built-in(内置):解释器内置的变量,比如int, str等
- 作用范围:所有模块(文件)
- Python中没有块级作用域
- 块级作用域:代码块中的变量,比如if、while、for后面的代码
【2】变量的修改
(1)global修改全局变量
# 【1】未使用global关键字
a = 1 # 全局变量
def outside():
a += 1
print(a)
outside()
print(a)
'''
Traceback (most recent call last):
File "D:\Python\pythonProject\pythonProject1\demo7.py", line 343, in <module>
outside()
File "D:\Python\pythonProject\pythonProject1\demo7.py", line 340, in outside
a += 1
UnboundLocalError: local variable 'a' referenced before assignment
'''
# 【2】使用global关键字后,就会正常的修改外部的全局变量
a = 1 # 全局变量
def outside():
global a
a += 1 #修改全局变量
print(a) # 2
outside()
print(a) # 2
(2)nonlocal修改外层函数变量
# 【1】不使用nonlocal关键字修改外层函数变量值会和修改全局变量报一样的错
# 【2】使用nonlocal关键字
def outside():
a = 1
def inside():
nonlocal a # 使用nonlocal关键字
a += 1 # 可以正常修改外层的函数变量值
print(a) # 2
inside()
print(a) # 2
outside()
【3】LEGB规则
- LGEB规则:按照L--->E--->G--->B的顺序查找变量
- L就是Local(局部变量)、E就是Enclosed(嵌套)、G就是Global(全局)、B就是Built-in(内置)
- 当不同命名空间具有相同变量名称的变量时,我们先查找局部变量,如果没有查到,再去全局变量查找
(1)基于命名空间的常见变量类型
- 局部变量:在一个函数体的内部定义的变量,作用域为函数内部,通过locals()查看局部变量
- 全局变量:在函数体外部,文件最外层定义的变量,作用域为整个文件内部,通过globals()查看全局变量
- 变量访问规则:从内到外,全局变量和局部变量重名时,采用就近原则
(2)案例讲解
a = 555 # 全局变量
def outside():
a = 666 # 局部变量1
def inside():
a = 777 # 局部变量2
print(f'这是局部变量2的a:{a}')
inside()
print(f'这是局部变量1的a:{a}')
outside()
print(f'这是全局变量的a:{a}')
# 这是局部变量2的a:777
# 这是局部变量1的a:666
# 这是全局变量的a:555
(3)变量的使用规则
- 创建变量时从上往下创建,搜索变量时从下往上搜索。
- 创建变量时,下层变量会覆盖上层同名变量,但不会改变上层变量的值,除非使用gloable和nonlocal关键字声明