作用域
bar()整个函数都处在外部foo()函数的作用域里(foo()是我们可以从外部访问的一个对象区域)。除了在foo()函数内部可以调用bar(),外部不能直接调用bar()
变量作用域
作用域的产生
在作用域中定义的变量,一般只在作用域内有效。需要注意的是,在if-elif-else,for-else,while-else,try-except(else-finally)等关键字的语句块中不会产生作用域。
作用域的类型
python中,使用一个变量,不需要预先声明。但真正使用的时候,必须绑定到某个内存对象。这种变量名的绑定将在当前作用域引入新的变量,同时屏蔽外层作用域中的相同变量。
-
局部作用域(locale — L)
- 局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
注意:如果需要在函数内部对全局变量赋值,需要在函数内部通过global语句声明该变量为全局变量。
- 局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。局部变量域就像一个 栈,仅仅是暂时的存在,依赖创建该局部作用域的函数是否处于活动的状态。所以,一般建议尽量少定义全局变量,因为全局变量在模块文件运行的过程中会一直存在,占用内存空间。
-
嵌套作用域(enclosing — E)
- E也包含在def关键字,E和L是相对的,E相对于上层函数而言也是L。与L的区别在于,对于一个函数而言,L是定义在定义在此函数内部的局部作用域。
-
全局作用域(Global — G)
- 即在模块层次中定义的变量。模块顶层申明的变量具有全局作用域。从外部来看,模块的全局变量就是一个模块对象的属性。
-
内置作用域(built-in — B)
- 系统固定模块中定义的变量。
搜索变量名的优先级:局部作用域>嵌套作用域>全局作用域>内置作用域
全局变量和局部变量
gbl_str = 'foo'
def foo():
loc_str = 'bar'
return gbl_str + loc_str
print(foo())
print(gbl_str)
#输出
foobar
foo
如果在全局变量中有和局部变量同名的变量,然后再局部变量中又有重新给变量赋值,那在赋值之前不能调用这个变量。
a = 123
def bar():
print('a', a)
a = 100
print('a', a)
bar()
#输出
会报错
UnboundLocalError: local variable 'a' referenced before assignment
global
可变类型的全局变量
a = 6688
def foo():
global a # 声明为全局变量
print("foo(),a:\t", a)
a = 666
print("foo(),a:\t", a)
def bar():
print("bar(),a:\t", a)
foo()
bar()
#foo(),a: 6688
#foo(),a: 666
#bar(),a: 666
a = 6688
def foo():
a = 666 # 仍为局部变量
def inner_foo():
global a # 声明inner_foo()中的a为全局变量
print(a)
a = 888
print(a)
inner_foo()
print(a)
print(a)
foo()
print(a)
#6688
#6688
#888
#666
#888