一、基本概念
1、变量的作用域
-
变量的作用范围: 可操作范围
-
Python是静态作用域, 也就是说在Python中, 变量的作用域源于它在代码中的位置, 在不同的位置, 可能有不同的命名空间
2、命名空间
-
命名空间是作用域的体现形式
-
表示变量不同的具体的操作范围
3、Python-LEGB
- L-Local: 函数内的命名空间
- 作用范围: 当前整个函数体
def test(): a = 10 print(a) test() # 打印: 10-
a的作用范围只在test函数中
- E-Enclosing function locals: 外部嵌套函数的命名空间
- 作用范围: 闭包函数
def test(): a = 10 def inner(): print(a) inner() test() # 打印: 10-
a的作用域, 在整个闭包函数test中
- G-Global: 全局命名空间
- 作用范围: 当前模块(文件)
a = 10 def test(): print(a) test() # 打印: 10-
a的作用域, 在整个模块当中, 可以理解为当前文件
- B-Builtin: 内建模块命名空间
- 作用范围: 所有模块(文件)
print("aaa")-
print函数, 在所有文件中都可以使用
- 注意:
- Python中没哟快级作用域
- 快级作用域: 代码块中, 比如 if while for 后的代码块
- LEGB规则: 会按照 L -> E -> G -> B 的顺序进行查找
二、基础命名空间的常见变量类型
1、局部变量
-
在一个函数内部定义的变量
-
作用域为函数内部
-
查看局部变量, 可以使用函数
locals()
2、全局变量
-
在函数外部, 文件最外层定义的变量
-
作用域为整个文件内部
-
查看全部变量, 可以使用函数
globals()
3、注意点
-
访问原则:
- 从内到外
-
结构规范:
- 全局变量
- 函数定义: 使用和修改
- 后续代码
-
全局变量和局部变量重名
- 获取: 就近原则
- 修改:
global 全部变量
-
命名规范:
- 全局变量: g_xxx
三、举例
1、闭包
- 代码
def test()
a = 10
def inner():
print(a)
-
a的作用域在整个闭包函数test内, 所以inner中可以访问
def test()
a = 10
def inner():
a = 5
print(a)
- 此时在
inner中, 定义了一个变量a, 此时inner中的a与test中的a, 属于两个不同的变量 - 在
inner中print(a), 会根据就近原则找到变量a = 5 - 如果想要
inner中的a不是新定义的变量, 而是test中的a进行重新赋值, 需要用到关键字nonlocal
def test()
a = 10
def inner():
nonlocal a
a = 5
print(a)
print(a)
inner()
print(a)
test()
# 打印结果:
10
5
5
- 此时, 使用
nonlocal修饰a, 则说明inner中的变量a不是新定义的, 而是test中的, 此时对a赋值, 会修改test中a的值
2、函数中修改全部变量的值
a = 10
def test():
a = 5
print(a)
print(a)
test()
print(a)
# 打印结果:
10
5
10
- 第一次打印,
a = 10 - 第二次打印, 执行了
test函数, 在内部新定义了一个变量a = 5 - 第三次打印,
a = 10, 此时打印与第一次相同, 因为在test中没有对全局变量a进行赋值, 而是新定义了一个变量 - 在函数内部修改全部变量, 与闭包有些类似, 只不过闭包中用的关键字是
nonlocal, 而修改全局变量, 则需要使用关键字global
a = 10
def test():
global a
a = 5
print(a)
print(a)
test()
print(a)
# 打印结果:
10
5
5
- 由于
test中的a使用了global关键字进行修饰, 此时a = 5不在是定义新的变量, 而是对全局变量进行赋值操作
3、函数中的变量, 只有在调用时才去查找
a = 10
def test():
print(a)
print(b)
b = 15
test()
# 打印结果:
10
15
- 上述代码中,
b在test后定义, 而在test中使用了b - 之所以代码正常运行, 是因为只有在
test()时,test函数被调用了, 才去查找b的值, 而此时b = 15已经被定义, 所以不会出错











网友评论