前言
作用域是程序运行时变量可被访问的范围。
作用域
python变量的作用域很简单,就是LEGB:变量名引用分为三个作用域进行查找,首先是本地(L),之后是函数内(F),之后是全局(G),最后是内置(B)。Python会按照优先级依次搜索4个作用域。
L(local)局部作用域
局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。
在函数内部的变量声明,除非特别的声明(后文会将),否则均默认为局部变量。
def func():
x=1
print(x)#1
print(x)# name 'x' is not defined
E(enclosing)嵌套作用域
E也包含在def关键字中,E和L是相对的,E相对于更上层的函数而言也是L。与L的区别在于,对一个函数而言,L是定义在此函数内部的局部作用域,而E是定义在此函数的上一层父级函数的局部作用域。主要是为了实现Python的闭包,而增加的实现。
def func():
x=1
def innerfunc():
print(x)
innerfunc()
func()# 1
G(global)全局作用域
即在模块层次中定义的变量,每一个模块都是一个全局作用域。也就是说,在模块文件顶层声明的变量具有全局作用域,从外部开来,模块的全局变量就是一个模块对象的属性。 注意:全局作用域的作用范围仅限于单个模块文件内。
funcnum=10
def func():
print (funcnum)
func()#10
B(built-in)内置作用域
系统内固定模块里定义的变量,如预定义在builtin 模块内的变量。
dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
oct(8)
# '0o10'
实例讲解
通过几个例子来加深对python变量作用域的理解。
demo1
def func1():
vars=300
print(vars)
vars=100
func1()
print(vars)
# 300
# 100
本例中,有一个全局变量vars,值为100,有一个作用域为func1函数内部的局部变量vars,值为300,func1内部输出vars变量值时,优先搜索局部作用域,所以打印输出300。
demo2
def func2():
var2=100
print(var2)
def innerfunc2():
print(var2)
innerfunc2()
var2=200
func2()
print(var2)
# 100
# 100
# 200
有两个var2变量,对于innerfunc2函数来说,局部作用域中没有var2变量,所以打印时,在L层找不到,所以进一步在E层找,即在上层函数func2中定义的var2,找到并输出。
demo3
var3=300
def func3():
var3=200
func3()
print(var3)
# 300
在局部变量中修改的不影响全局变量中的值。
修改作用域
如果希望修改变量的作用域可以使用global、nonlocal关键字。
global关键字
如果希望在L作用域中修改G作用域中的变量,则应该使用global关键字。
var=99
def func():
def innerfunc():
global var
print("var=",var)
var =100
return innerfunc
func()()
print(var)
# var= 99
# 100
上段代码中,定义了一个内部函数,并作为一个变量返回,所以func()相当于innerfunc,而不是innerfunc(),所以func()()相当于innerfunc()。这里需要注意的是global关键字,使用了这个关键字之后,在innerfunc函数中使用的var变量就是全局作用域中的var变量,而不会新生成一个局部作用域中的var变量。
nonlocal关键字
在L作用域中修改E作用域中的变量,就需要使用nonlocal关键字了,这个是python3中新增加的特性。
def outer():
count=10
def inner():
nonlocal count
count=20
print(count)
inner()
print(count)
outer()
# 20
# 20
由于声明了nonlocal,这里inner中使用的count变量就是E即outer函数中生命的count变量,所以输出两个20。
总结
参考文章Python基本语法_变量作用域LEGB
code:本节代码
网友评论