
在 python 编程中,理解变量的作用域(scope)至关重要。作用域定义了变量在程序中可以被访问的范围。python 遵循 legb 规则来解析变量:局部(local)、封闭(enclosing function locals)、全局(global)和内置(built-in)。当我们在函数内部操作变量时,其行为会根据变量的声明方式而有所不同。
在 Python 中,如果在函数内部对一个变量进行赋值操作,那么该变量默认会被视为该函数的局部变量。这意味着即使外部存在同名变量,函数内部的赋值也不会影响到外部的变量,而是创建或修改函数自身作用域内的局部变量。
考虑以下示例:
def scope_test():
def do_local():
spam = "local spam" # 默认创建局部变量
spam = "test spam"
do_local()
print("After local assignment:", spam)运行 scope_test() 后,输出将是 "After local assignment: test spam"。这表明 do_local() 函数内部对 spam 的赋值只影响了 do_local 自身的局部变量,而 scope_test 作用域内的 spam 保持不变。
当我们需要在函数内部修改模块(即文件)级别的全局变量时,需要使用 global 关键字明确声明。global 关键字告诉 Python 解释器,该变量不是当前函数的局部变量,而是指向模块最外层作用域中的同名变量。
立即学习“Python免费学习笔记(深入)”;
def scope_test():
# ... 其他函数 ...
def do_global():
global spam # 声明 spam 为全局变量
spam = "global spam"
spam = "test spam" # scope_test 作用域的 spam
# ...
do_global()
print("After global assignment:", spam) # 仍打印 scope_test 的 spam在上述代码中,do_global() 内部的 global spam 声明使得 spam = "global spam" 这一赋值操作影响的是模块级别的 spam 变量。然而,当我们在 scope_test() 内部打印 spam 时,我们仍然看到的是 scope_test 自身的 spam 变量的值。只有在 scope_test() 调用结束后,在全局作用域再次打印 spam 时,才能看到 do_global() 所做的修改。
# 完整示例的全局部分
# ... (scope_test 函数定义) ...
scope_test()
print("In global scope:", spam) # 此时会打印 "global spam"nonlocal 关键字用于在嵌套函数中修改其直接外层(非全局)作用域中的变量。它允许内部函数访问并修改其封闭函数(Enclosing Function)中的变量,而不是创建新的局部变量。
def scope_test():
def do_nonlocal():
nonlocal spam # 声明 spam 为非局部变量
spam = "nonlocal spam"
spam = "test spam" # scope_test 作用域的 spam
do_nonlocal()
print("After nonlocal assignment:", spam)在 do_nonlocal() 中使用 nonlocal spam 后,spam = "nonlocal spam" 会修改 scope_test 作用域中的 spam 变量。因此,print("After nonlocal assignment:", spam) 将输出 "After nonlocal assignment: nonlocal spam"。
理解 Python 变量作用域的关键在于,Python 在函数 定义时(或者说,在函数对象被“编译”时)就已经确定了函数内部变量的绑定方式。这意味着 Python 会扫描函数体,识别所有被赋值的变量。
这种“编译时”的绑定确定性解释了为什么在某些情况下会出现 UnboundLocalError。考虑以下示例:
spam = 10
def function1():
print(spam) # spam 未在 function1 中赋值,被视为全局变量
def function2():
print(spam) # 错误:UnboundLocalError
spam = 11 # spam 在 function2 中被赋值,被视为局部变量function1() 能够正常运行并打印 10,因为 spam 在 function1 内部没有被赋值,Python 会沿着 LEGB 规则向上查找,最终找到全局作用域的 spam。
然而,function2() 会抛出 UnboundLocalError。这是因为 Python 在解析 function2() 时,发现 spam = 11 这条赋值语句,因此它将 function2() 内部的所有 spam 引用都标记为局部变量。当 print(spam) 执行时,它尝试访问一个局部变量 spam,但此时 spam 尚未被赋值,从而导致错误。
结合上述概念,我们来完整分析最初提供的 scope_test 示例:
def scope_test():
def do_local():
spam = "local spam" # 1. 这里的 spam 是 do_local 的局部变量
def do_nonlocal():
nonlocal spam # 2. 这里的 spam 指向 scope_test 的 spam
spam = "nonlocal spam"
def do_global():
global spam # 3. 这里的 spam 指向模块级别的 spam
spam = "global spam"
spam = "test spam" # 4. scope_test 的局部变量 spam
do_local()
print("After local assignment:", spam) # 5. 打印 scope_test 的 spam,仍为 "test spam"
do_nonlocal()
print("After nonlocal assignment:", spam) # 6. 打印 scope_test 的 spam,已被 do_nonlocal 修改为 "nonlocal spam"
do_global()
print("After global assignment:", spam) # 7. 打印 scope_test 的 spam,仍为 "nonlocal spam" (do_global 修改的是全局 spam)
scope_test()
print("In global scope:", spam) # 8. 打印模块级别的 spam,已被 do_global 修改为 "global spam"执行流程及输出:
以上就是深入理解 Python 变量作用域与绑定机制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号