第30章 Python3 命名空间和作用域教程

命名空间

先看看官方文档的一段话:

A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。

命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。

命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。

咱们举一个计算机系统中的例子,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名。

一般有三种命名空间:

  • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
  • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

命名空间查找顺序:

假设咱们要使用变量 liulianjiangcsdn,则 Python 的查找顺序为:局部的命名空间 -> 全局命名空间 -> 内置命名空间

如果找不到变量 liulianjiangcsdn,它将放弃查找并引发一个 NameError 异常:


    NameError: name 'liulianjiangcsdn' is not defined。

命名空间的生命周期:

命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。

因此,咱们无法从外部命名空间访问内部命名空间的对象。


    实例 
    # var1 是全局名称
    
    var1 = 5
    
    def some_func(): 
    
        # var2 是局部名称
    
        var2 = 6
    
        def some_inner_func(): 
    
            # var3 是内嵌的局部名称
    
            var3 = 7

如所示,相同的对象名称可以存在于多个命名空间中。


作用域

A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.

作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。

Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。

变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python 的作用域一共有4种,分别是:

有四种作用域:

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等,最后被搜索。

规则顺序: L –> E –> G –> B

在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。


    g_count = 0  # 全局作用域
    def outer():
        o_count = 1  # 闭包函数外的函数中
        def inner():
            i_count = 2  # 局部作用域

内置作用域是通过一个名为 builtin 的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:


    >>> import builtins
    >>> dir(builtins)

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:


    >>> if True:
    ...  msg = 'I am from phlcsdn2023'
    ... 
    >>> msg
    'I am from phlcsdn2023'
    >>>

实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。

如果将 msg 定义在函数中,则它就是局部变量,外部不能访问:


    >>> def test():
    ...     msg_inner = 'I am from phlcsdn2023'
    ... 
    >>> msg_inner
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'msg_inner' is not defined
    >>>

从报错的信息上看,说明了 msg_inner 未定义,无法使用,因为它是局部变量,只有在函数内可以使用。

全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:


    实例(Python 3.0+) 
     
    #!/usr/bin/python3
     
    total = 0 # 这是一个全局变量
    # 可写函数说明
    def sum( arg1, arg2 ):
        #return 2个参数的和."
        total = arg1 + arg2 # total在这里是局部变量.
        print ("函数内是局部变量 : ", total)
        return total
     
    #调用sum函数
    sum( 10, 20 )
    print ("函数外是全局变量 : ", total)

以上实例输出结果请在输出结果查看


    函数内是局部变量 :  30
    函数外是全局变量 :  0

global 和 nonlocal关键字

当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。

以下实例修改全局变量 num:


    实例(Python 3.0+) 
     
    #!/usr/bin/python3
     
    num = 1
    def fun1():
        global num  # 需要使用 global 关键字声明
        print(num) 
        num = 123
        print(num)
    fun1()
    print(num)

以上实例输出结果请在输出结果查看


    1
    123
    123

如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:


    实例(Python 3.0+) 
     
    #!/usr/bin/python3
     
    def outer():
        num = 10
        def inner():
            nonlocal num   # nonlocal关键字声明
            num = 100
            print(num)
        inner()
        print(num)
    outer()

以上实例输出结果请在输出结果查看


    100
    100

另外有一种特殊情况,假设下面这段代码被运行:


    实例(Python 3.0+) 
     
    #!/usr/bin/python3
     
    a = 10
    def test():
        a = a + 1
        print(a)
    test()

以上程序执行,报错信息如下:


    Traceback (most recent call last):
      File "test.py", line 7, in <module>
        test()
      File "test.py", line 5, in test
        a = a + 1
    UnboundLocalError: local variable 'a' referenced before assignment

错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。

修改 a 为全局变量:


    实例 
     执行输出结果请在输出结果查看
     
    11
    
    #!/usr/bin/python3
     
    a = 10
    def test():
        global a
        a = a + 1
        print(a)
    test()

也可以通过函数参数传递:


    实例(Python 3.0+) 
     
     执行输出结果请在输出结果查看
     
    11
    
    #!/usr/bin/python3
     
    a = 10
    def test(a):
        a = a + 1
        print(a)
    test(a)

本专栏所有文章

第1章 Python3 教程第2章 Python3 简介教程
第3章 Python3 环境搭建教程第4章 Python3 VScode教程
第5章 Python3 基础语法教程第6章 Python3 基本数据类型教程
第7章 Python3 数据类型转换教程第8章 Python3 推导式教程
第9章 Python3 解释器教程第10章 Python3 注释教程
第11章 Python3 运算符教程第12章 Python3 数字(Number)教程
第13章 Python3 字符串教程第14章 Python3 列表教程
第15章 Python3 元组教程第16章 Python3 字典教程
第17章 Python3 集合教程第18章 Python3 编程第一步教程
第19章 Python3 条件控制教程第20章 Python3 循环语句教程
第21章 Python3 迭代器与生成器教程第22章 Python3 函数教程
第23章 Python3 数据结构教程第24章 Python3 模块教程
第25章 Python3 输入和输出教程第26章 Python3 File教程
第27章 Python3 OS教程第28章 Python3 错误和异常教程
第29章 Python3 面向对象教程第30章 Python3 命名空间/作用域教程
第31章 Python3 标准库概览教程第32章 Python3 实例教程
第33章 Python 测验教程第34章 Python3 正则表达式教程
第35章 Python3 CGI编程教程第36章 Python3 MySQL(mysql-connector)教程
第37章 Python3 MySQL(PyMySQL)教程第38章 Python3 网络编程教程
第39章 Python3 SMTP发送邮件教程第40章 Python3 多线程教程
第41章 Python3 XML 解析教程第42章 Python3 JSON教程
第43章 Python3 日期和时间教程第44章 Python3 内置函数教程
第45章 Python3 MongoDB教程第46章 Python3 urllib教程
第47章 Python uWSGI 安装配置教程第48章 Python3 pip教程
第49章 Python3 operator教程第50章 Python math教程
第51章 Python requests教程第52章 Python random教程
第53章 Python3 os.replace() 方法教程

寄语

本文有 phlcsdn2023 原创,欢迎点赞、转载,博客地址:https://blog.csdn.net/phlcsdn2023

  • 人应该永远拥有两样东西,一盏永不熄灭的灯——希望之灯;一扇长开的窗
  • 一波未平、一波又起:一个浪头还没有平息,另一个浪头又起来了。原比喻诗文写得波澜起伏。后来也比喻一个麻烦问题没有解决,又出现新的麻烦问题。
  • 用双手栽下漫天的绿色,用心灵守望五彩的家园。
  • 既然即使现在的一切和我当初想象的都不一样,可是我要习惯,要接受,要变成真正的没心没肺。
  • 事实上,要想既树立国权,又保留邦权,就只能实行联邦制。因为只有联邦才既有全国宪法和全国政府,又有各邦宪法和各邦政府。不过,这个问题的最终解决,却又是由另一个难题引起的。这就是,蛋糕应该怎么分?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你得不到的念想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值