Python基础(十四): 函数作用域
2018-03-05 本文已影响10人
伯wen
一、基本概念
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
已经被定义, 所以不会出错