一 LEGB
什么是LEGB?
L:local 函数内部作用域
E:enclosing 函数内部与内嵌函数之间
G:global 全局作用域
B:build-in 内置作用域
顺序是什么?
跟名字一样,Python在函数里面的查找分为4种,称之为LEGB,也正是按照这种顺序来查找的。
首先,是local,先查找函数内部
然后,是enclosing,再查找函数内部与嵌入函数之间(是指在函数内部再次定义一个函数)
其次,是global,查找全局
最后,是build-in,内置作用域
实例(Python3.0+):
name = 'wangyw'
def foo():
name = 'maoj'
def bar():
print(name) # 打印的name时就用到函数作用域,它会找本函数中是否存在此变量,如不存在找上级函数中是否存在,逐级上寻找变量,直到找到变量位置。
return bar
foo()
a = foo() # 把执行foo()函数得到的return返回值赋值给a,也就是把返回值bar赋值给a
print(a) # 此时打印的是a(bar)的内存地址
a() # 相当于执行bar()
二 函数变量
我们通常把定义在函数外的变量成为全局变量,定义在函数内的变量称为局部变量,顾名思义,全局变量的作用域是整个代码段,局部变量的作用域就只是在它所属的代码段,变量只在它的作用域里有效。
通过实例,我们可以进一步理解下,全局和局部的概念。
实例1(Python3.0+):
count = 10 # 全局变量
def print_local():
count = 5 # 局部变量,这个count覆盖了全局变量count,这2个是不同的变量。
print(count)
def print_global():
print(count) # 这里的count是最上面的全局变量噢
print_local()
print_global()
"""
运行结果:
>> 5
>> 10
"""
global
- 函数中引用修改全局变量
实例(Python3.0+):
count = 10
def foo():
global count # 告知程序count是全局变量
print(count)
count = 7 # 修改全局变量count的值
print(count)
foo()
"""
运行结果:
>> 10
>> 7
"""
nonlocal
- 引用修改父级局部变量
实例(Python3.0+):
count = 100
def foo():
count = 10
def inter():
nonlocal count
# 引用父级局部变量
print(count)
count = 20
print(count)
inter()
print(count)
foo()
"""
运行结果:
>> 10
>> 20
>> 20
"""
小结:
- 变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>Python内置作用域。
- 只有模块、类以及函数才能引用新作用域。
- 对于一个变量,内部作用域声明会覆盖外部变量,不直接声明,就会使用外部作用域的变量。
- 内部作用域要修改外部作用域变量的值时,全局变量要使用golbal关键字,嵌套作用域变量要使用nonlocal关键字,nonlocal是Python3新增的关键字,有了这个关键字,就能完美的实现闭包了。
- 如果函数的内容中无global关键字,优先读取局部变量;如无局部变量,则读取全局变量,但无法对全局变量进行重新赋值(name="ffff"),对于可变类型(列表,字典),可以对内部元素进行操作。
错误实例1:
name = "lvcm"
def count():
print(name)
name = "wangyw"
print(name)
count()
"""
运行结果:
>> UnboundLocalError: local variable 'name' referenced before assignment
"""
错误实例1,函数中没有使用global关键字,print(name),读取的是全局变量name,不能对全局变量name进行修改,但如果name是可变类型(字典,列表)时,可以对全局变量进行修改操作。
实例:
name = ['zhubj','age']
def count():
print(name)
name.append("wangyw")
# 列表的所有方法都可以使用
print(name)
count()
print(name)
"""
运行结果:
>>> ['zhubj', 'age']
>>> ['zhubj', 'age', 'wangyw']
>>> ['zhubj', 'age', 'wangyw']
"""
错误实例2:
name = ['name','age']
def count():
name = "wangyw"
global name
print(name)
count()
"""
运行结果:
>>> SyntaxWarning: name 'name' is assigned to before global declaration global name
备注:函数中使用global声明全局变量时,global之前不能定义与全局变量同名的局部变量,否则会报错。为了避免报错,代码中全局变量使用大写,局部变量使用小写
"""