函数中变量的作用域及生命周期和其查找顺序


作用域(scope)规定了变量的可访问范围和其生命周期

生命周期:变量的生命周期取决于其所在的作用域。当程序进入一个作用域时,其中定义的变量被创建;当程序离开该作用域时,这些变量被销毁,内存空间被释放,这也是外部无法访问函数内的变量的原因

Python 中有四种作用域:

  • 全局作用域
  • 局部作用域
  • 嵌套作用域
  • 内置作用域

相应的根据变量所属的作用域我们可以将变量分为:

  • 全局变量
  • 局部变量
  • 非局部变量
  • 内建变量

全局作用域(Global Scope)

全局作用域是在整个程序中都可访问的作用域,在函数外部定义的变量属于全局作用域

示例:

x = 10  # 全局变量

def my_function():
    print(x)  # 可以访问全局变量x

my_function()  # 输出: 10
print(x)  # 输出: 10

局部作用域(Local Scope)

局部作用域是在函数内部定义的变量的作用域,局部作用域仅限于函数内部

示例:

def my_function():
    y = 5  # 局部变量
    print(y)  # 可以访问局部变量y

my_function()  # 输出: 5
print(y)  # 报错,无法访问局部变量y

嵌套作用域(Enclosing Scope)

嵌套作用域是指在一个函数内部定义的函数中的变量的作用域,嵌套作用域的变量在外部函数执行时被创建,在外部函数执行结束时被销毁

示例:

def outer_function():
    x = 10  # 外部函数的局部变量

    def inner_function():
        y = 5  # 嵌套函数的局部变量
        print(x + y)  # 可以访问外部函数的变量

    inner_function()  # 输出: 15

outer_function()

内置作用域(Built-in Scope)

内置作用域是指 Python 解释器中预定义的命名空间,包含了一些内置的函数和对象。这些内置函数和对象可以在任何地方直接使用,无需导入任何模块

示例:

print(len("Hello"))  # 输出: 5,len() 是内置函数

作用域总结

  • 全局作用域:整个程序中都可访问的作用域
  • 局部作用域:在函数内部定义的变量的作用域
  • 嵌套作用域:在一个函数内部定义的函数中的变量的作用域
  • 内置作用域: Python 解释器中预定义的命名空间

上面我们提到,一个变量的生命周期由其所在的作用域决定

  • 全局作用域的变量在程序开始执行时被创建,在程序结束时被销毁
  • 局部作用域的变量在函数执行时被创建,在函数执行结束时被销毁
  • 嵌套作用域的变量在外部函数执行时被创建,在外部函数执行结束时被销毁
  • 内置作用域在解释器启动时自动开始加载,直至解释器关闭

全局变量(Global Variables)

在函数外部(全局作用域)定义的变量被称为全局变量,可以整个程序的任意地方访问。全局变量的作用域从定义开始,直至程序结束销毁

示例:

x = 10  # 全局变量

def my_function():
    print(x)  # 可以访问全局变量x

my_function()  # 调用定义的函数输出: 10
print(x)  # 输出: 10

global关键字声明

一般来说,函数内可以直接访问全局变量,但是无法修改,因为在函数内部是一个局部作用域,程序会默认在其内部是是一个新的局部变量,而不是外部声明的全局变量,此时如果我们要在函数内部对全局变量进行修改,我们要在变量前面使用global关键字进行声明告诉程序这是一个在函数内部使用的全局变量

x = 10  # 全局变量

def my_function():
    global x  # 使用 global 关键字声明 x 是全局变量
    x = 20  # 修改全局变量 x 的值
    print(x)  # 访问全局变量

my_function()  # 输出:20
print(x)  # 输出:20

局部变量(Local Variables)

在函数内部(局部作用域)定义的变量被称为局部变量,局部变量的生命周期仅限于函数的执行过程**在其所属函数执行时创建,在函数执行结束后销毁** 因此只能在其所属函数内部访问,函数外无法访问

示例:

def my_function():
    y = 5  # 局部变量
    print(y)  # 可以访问局部变量y

my_function()  # 调用定义的函数输出: 5
print(y)  # 报错,无法访问局部变量y(全局无法访问局部)

注意:由于查找顺序的问题,如果在函数内部和外部存在同名的变量,调用函数时函数内部的变量会覆盖外部的变量(这里的覆盖仅在函数内部使用时,对于全局来说没有影响)

示例:

z = 15  # 全局变量

def my_function():
    z = 20  # 局部变量,覆盖了全局变量z
    print(z)  # 可以访问局部变量z

my_function()  # 调用定义的函数输出: 20
print(z)  # 输出: 15,全局变量z没有被修改

而在嵌套函数中,如果有与外部函数同名的变量,那么在嵌套函数中对该变量的赋值会创建一个新的局部变量,而不会修改外部函数的变量

示例:

def outer_function():
    x = 10  # 外部函数的局部变量

    def inner_function():
        x = 20  # 内部函数的局部变量,不会修改外部函数的变量x
        print("Inner function:", x)

    inner_function()
    print("Outer function:", x)

outer_function()

# 输出 :

Inner function: 20
Outer function: 10

非局部变量(Nonlocal Variables)

非局部变量是在嵌套函数中定义的变量,非局部变量使用 nonlocal 关键字声明,将外部函数的局部变量在内部函数声明成非局部变量,使内部函数中可以修改外部函数的变量

def outer_function():
    x = 10  # 外部函数的局部变量

    def inner_function():
        nonlocal x  # 将x声明为非局部变量
        x = 20  # 修改外部函数的变量x的值

    inner_function()
    print(x)  # 输出: 20

outer_function()

内建变量(Built-in Variables)

内建变量是 Python 内置的变量,可以直接在程序中使用,无需声明或者定义。例如 TrueFalseNone

变量的查找顺序(LEGB)

上面我们提到了,如果函数内部有与外部相同的变量名,那么调用函数时,局部变量会覆盖全局变量,这涉及到变量查找顺序的问题

在 Python 中,当我们使用一个变量时,解释器会按照以下顺序去查找这个变量的值

变量查找LEGB规则
图片来源于网络,侵权联系删除

1. 局部作用域(Local Scope)
首先,解释器会在当前的函数或者代码块中查找变量。如果变量在当前的作用域中定义了,那么解释器会直接使用该变量的值。

2. 嵌套作用域(Enclosing Scope)
如果变量在当前的作用域中没有定义,解释器会继续在上一级的作用域中查找变量,直到找到为止。这种作用域的关系称为嵌套作用域,即内部作用域可以访问外部作用域中的变量。

3. 全局作用域(Global Scope)
如果变量在所有的局部作用域和嵌套作用域中都没有定义,解释器会在全局作用域中查找变量。全局作用域是在整个程序范围内可见的,通常在函数外部定义的变量属于全局作用域。

4. 内置作用域(Built-in Scope)
如果变量在全局作用域中也没有定义,解释器会在内置作用域中查找变量。内置作用域包含了 Python 内置的函数和变量,例如 print() 和 len() 等。

如果在所有的作用域中都没有找到变量的定义,解释器会返回一个 NameError 的异常

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值