• 10、Python函数命名空间、作用域(LEGB)及Global


    一、命名空间和作用域

    当出现了函数,变量声明的位置就发生了变化,不同位置声明的变量,能访问这个变量的范围也出现了限制

    1.1 定义

    1. 命名空间: 是虚拟概念,对栈区的划分,用于对变量进行分区管理
    2. 作用域: 一个数据能够作用的范围

    命名空间根据范围的不同,分为以下几种类型:

    1.2 内建命名空间和内建作用域

    Python程序中最大的一个命名空间,通常在解释器运行目标代码的时候(也就是点RUN的时候),由解释器创建的一个命名空间,负责初始化(即第一次赋值、第一次创建)系统环境变量。如:int/type()等

    1. 内建命名空间加载时间运行代码之前,通过解释器加载好系统的命名空间。包含了int/float/str/type()等等各种数据类型或者函数,所以我们在代码中才可以直接使用这些数据类型或者函数
    2. 作用:初始化系统环境变量
    3. 作用域内建作用域(Builtin),此空间内的数据作用范围是整个内建空间,包括子空间
    4. 查看方式dir()

    在这里插入图片描述

    1.3 全局命名空间和全局作用域

    定义: 编写Python代码时,创建一个python文件,其中声明在函数外部的变量,称为:全局变量(global)。当前可以声明全局变量的所有位置称为全局命名空间

    1. 加载时间解释器运行目标代码时,加载全局命名空间,初始化该命名空间中的所有全局变量
    2. 作用:声明、定义全局变量的范围
    3. 作用域全局作用(Global)
    4. 查看方式:globals()查看当前全局命名空间中的所有全局变量,本质上globals()就是一个存储了数据的字典,

    例如:

    name = "张三"
    age = 12
    grade = ["1",2,"3"]
    
    def outer():
        a = "a"
        def inner():
            a = "b"
        return inner
    
    
    fun = outer()
    fun()
    print(f"全局变量字典为:{globals()}")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行结果:
    在这里插入图片描述

    1.3 局部命名空间和局部作用域

    定义:当Python文件中声明函数时,独立出来了一个小的作用范围(函数内部),通常情况下我们将函数内部的空间称为:局部命名空间

    1. 加载时间:解释器运行目标代码时,加载完全局命名空间之后,加载局部命名空间,初始化局部命名空间中的局部变量

    注意:如果是嵌套函数,嵌套函数是没有命名空间的,嵌套函数的空间存于父函数内,但嵌套函数是有其自己的作用域的,叫嵌套作用域(内部作用域)

    1. 作用:声明、定义局部变量
    2. 作用域:局部作用域(嵌套作用域)
    3. 查看方式:Locals()查看当前命名空间中的所有数据

    Locals(): 查看当前命名空间中的数据

    • 编写在函数内部:查看局部命名空间中的数据
    • 编写在函数外部:和globals()一样的意义

    示例:

    name = "张三"
    age = 12
    grade = ["1",2,"3"]
    
    
    def outer():
        a = "a"
        print(f"outer局部的数据:{locals()}")
        def inner():
            a = "b"
            print(f"inner局部的数据:{locals()}")
        return inner
    
    fun = outer()
    fun()
    print(f"全局变量字典为:{globals()}")
    print(f"全局部的数据:{locals()}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果:
    在这里插入图片描述

    1.4 总结

    1. 命名空间是一个名词, 表示了一个可以声明变量的范围
    2. 用作域是一个动词,表示一个变量起作用的范围
    3. 解释器运行时,命名空间的加载顺序:内建命名空间–>全局命名空间–>局部命名空间
    4. 命名空间销毁顺序:局部名称空间(调用函数结束销毁)> 全局命名空间(py文件执行j结束销毁)> 内置名称空间(关闭python解释器销毁)
    5. 查询使用变量,查询使用顺序:内部作用域–>嵌套作用域–>全局作用域–>内建作用域,也就是Python常说的LEGB原则。查找顺序通俗的说就是:就近原则,一直找到内建作用域,找不到报:“name is not defined”

    在这里插入图片描述

    1.5 扩展:LEGB

    • Local,本地作用域,局部作用域的local命名空间。函数调用时创建,调用结束消亡
    • Enclosing,Python2.2时引入嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间
    • Global,全局作用域,即一个模块的命名空间。模块被import时创建 ,解释器退出时消亡
    • Build-in,内置模块的命名空间,生命周期从python解释器启动时创建到解释器退出时消亡,例如:print(open),print和open都是的变量
      在这里插入图片描述

    二、Global关键字的使用说明

    在讲述什么是Global之前,让我们先来看一个例子,以下例子两条print语句分别打印什么:

    x = 100
    def fn1():
        x +=1
        print(f"函数内的{x}")
    fn1()
    print(f"变更后的{x}")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果:
    在这里插入图片描述
    为什么会运行报错:X在使用前需要先分配变量值,明明我们在全局已经定义了一个X=100
    原因:在python动态语言内,== 赋值即定义== ,在inner内部

    • x += 1其实是一个x = x+1的赋值语句,那这个x就会函数运行在初始化进行加载,变成局部的一个变量
    • 而=运算时,从左往右执行,在x=的时候已经默许了x是local variable,因此外部作用域的x=100是被屏蔽的。所以x+1中的x相当于一个没有赋值的变量,从而报错。

    那么怎么解决这个问题?解决的办法一:使用global关建字将x定义为全局变量,这时在函数局部就会将x指向全局的变量x

    让我们来看看具体的应用,下面的代码运行结果如何:

    x = 100
    def fn1():
        x = 10
        global x
        x +=1
        print(f"函数内的{x}")
    fn1()
    print(f"变更后的{x}")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果:
    在这里插入图片描述
    为什么还是报错,我们不是已经使用了global吗?那是因为我们前面声明前加了一句:x = 10
    x = 10 时会将其置为局部变量,但程序执行到global x时,发现x已经在局部定义过了,所以报错,所以我们要先声明再调用

    所以我们将程序调整为:
    在这里插入图片描述

    那么问题又来了,下面的例子,global x在inner函数内可以调用吗?

    x = 100
    def outer():
        global x
        x +=1
        print(f"ouer的x调用结果{x}")
        def inner():
            x +=1
            print(f"inner的x调用结果{x}")
        return inner
    a = outer()
    a()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果:
    在这里插入图片描述
    为什么报错,不是已经定义了global全局变量,同时也是局部作用域内先定义了吗?
    原因:Global 定义只在全局和定义的当前作用域内起作用,所以上面的例子,global x只在全局作用域和嵌套作用域内可用,如果inner内部想调用,需要做以下调整
    在这里插入图片描述
    特别说明

    global关键字是一种破坏函数封装的方式,变量未经过传参即可在函数内部作用域内使用。所以在日常使用中,**不要使用,那我们要实现这种调用,可以用什么方式呢?python给我提供了一个关键字:Nolocal,后续我的笔记中会详细提到

    以上内容均为自理解整理内容,如有错误,请指正,转载请注明出处

  • 相关阅读:
    vscode 插件配置推荐
    Xintell——全生命周期的模型建设+智能数据中台
    Linux 5.20 可能将版本号升级为 Linux 6.0
    【笔记】29元microbit套装如何玩——套装硬件简介
    VMware 虚拟机安装 CentOS 7
    每天一个面试题:ThreadLocal底层原理和实现Demo
    罗技g402鼠标宏设置教程
    Java工程师的就业前景?薪资水平?
    浏览器backspace无法回退到上一层解决办法
    微信小程序云开发
  • 原文地址:https://blog.csdn.net/totorobig/article/details/126687921