zoukankan      html  css  js  c++  java
  • python命名空间和作用域

     

    python使用命名空间记录变量。python中的命名空间就像是一个dictkey是变量的名字,value是变量的值。

    • python中,每个函数都有一个自己的命名空间,叫做local namespace,它记录了函数的变量。
    • python中,每个module有一个自己的命名空间,叫做global namespace,它记录了module的变量,包括 functions, classes 和其它imported modules,还有 module级别的 变量和常量。
    • 还有一个build-in 命名空间,可以被任意模块访问,这个build-in命名空间中包含了build-in function 和 exceptions

    python中的某段代码要访问一个变量x时,python会在所有的命名空间中寻找这个变量,查找的顺序为:

    • local namespace - 指的是当前函数或者当前类方法。如果在当前函数中找到了变量,停止搜索
    • global namespace - 指的是当前的模块。如果在当前模块中找到了变量,停止搜索
    • build-in namespace - 如果在之前两个namespace中都找不到变量xpython会假设xbuild-in的函数或者变量。如果x不是内置函数或者变量,python会报错NameError

    对于闭包来说,这里有一点区别,如果在local namespace中找不到变量的话,还会去父函数的local namespace中找变量。

    locals

    内置函数locals(), 返回当前函数(方法)的局部命名空间

    def func(a = 1):
        b = 2
        print(locals())
        return a+b
    func()
    # {'a': 1, 'b': 2} 可以看出,locals返回的是个dict
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    globals

    内置函数globals(),返回当前module的命名空间

    def func(a = 1):
        b = 2
        return a+b
    func()
    print(globals()) # globals()返回的也是个dict
    • 1
    • 2
    • 3
    • 4
    • 5

    locals()和globals()有一个区别是,locals只读,globals可以写

    def func(a = 1):
        b = 2
        return a+b
    func()
    glos = globals()
    glos['new_variable'] = 3
    print(new_variable)
    # 3  , 我们并没有显示定义new_variable这个变量,只是在globals中添加了这个key,在随后的代码中,
    #就可以像访问一般变量一样来访问。
    
    def func(a = 1):
        b = 2
        locs = locals()
        locs['c']  = 1
        print(c)
    func()
    # NameError: name 'c' is not defined
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    from module import 和 import module

    • 使用import module时,module本身被引入,但是保存它原有的命名空间,所以我们需要使用module.name这种方式访问它的 函数和变量。
    • from module import这种方式,是将其它模块的函数或者变量引到当前的命名空间中,所以就不需要使用module.name这种方式访问其它的模块的方法了。

    if __name__ trick

    python中的module也是对象,所有的modules都有一个内置的属性__name__,模块的__name__属性的值取决于如何使用这个模块,如果import module,那么__name__属性的值是模块的名字。如果直接执行这个模块的话,那么__name__属性的值就是默认值__main__

    module的一些内置属性

    • __name__: 上面已经介绍过
    • __file__ : 当前module的绝对路径
    • __dict__:
    • __doc__ :
    • __package__:
    • __path__:

    1、典型案例

    先从几个典型的案例来看下名称空间及作用域对python代码运行的影响,请看下面几个代码实例及其执行结果,是否符合你的预期。

    代码1:块作用域

    1
    2
    3
    if True:
        = 1
    print i

    执行结果: 1

     

    代码2:函数作用域

    1
    2
    3
    4
    5
    def f():
        = 1
     
    f()
    print i

    执行结果:执行报错“NameError: name 'cc' is not defined”

    代码3:静态作用域

    1
    2
    3
    4
    5
    = 1
    def test():
        += 1
     
    test()

    执行结果:执行报错“UnboundLocalError: local variable 'i' referenced before assignment”

     

    代码4:静态作用域

    1
    2
    3
    4
    5
    6
    7
    8
    = 1
    def g():
        print i
         
    def f():
        = 2
        g()
    f() 

    执行结果: 1

     

    代码5:闭包、全局作用域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    = 1
    def f():
        = 2
        def g():
            print i
        return g
     
     
    func = f()
    func()
    print i

    执行结果:2    1 

    PS:python2.1之前执行该代码会报错,闭包(嵌套作用域)是在之后引入的概念,内部函数g()只能访问本函数中的命名空间、全局命名空间、内建命名空间,无法访问外部调用函数的命名空间。

    2、命名空间

    【定义】

        名称到对象的映射。命名空间是一个字典的实现,键为变量名,值是变量对应的值。各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。

     

    【分类】

        python程序执行期间会有2个或3个活动的命名空间(函数调用时有3个,函数调用结束后2个)。按照变量定义的位置,可以划分为以下3类:

        Local,局部命名空间,每个函数所拥有的命名空间,记录了函数中定义的所有变量,包括函数的入参、内部定义的局部变量。

        Global,全局命名空间,每个模块加载执行时创建的,记录了模块中定义的变量,包括模块中定义的函数、类、其他导入的模块、模块级的变量与常量。

        Built-in,python自带的内建命名空间,任何模块均可以访问,放着内置的函数和异常。

    【生命周期】

        Local(局部命名空间)在函数被调用时才被创建,但函数返回结果或抛出异常时被删除。(每一个递归函数都拥有自己的命名空间)。

        Global(全局命名空间)在模块被加载时创建,通常一直保留直到python解释器退出。

        Built-in(内建命名空间)在python解释器启动时创建,一直保留直到解释器退出。

       

        各命名空间创建顺序:python解释器启动 ->创建内建命名空间 -> 加载模块 -> 创建全局命名空间 ->函数被调用 ->创建局部命名空间

        各命名空间销毁顺序:函数调用结束 -> 销毁函数对应的局部命名空间 -> python虚拟机(解释器)退出 ->销毁全局命名空间 ->销毁内建命名空间

        python解释器加载阶段会创建出内建命名空间、模块的全局命名空间,局部命名空间是在运行阶段函数被调用时动态创建出来的,函数调用结束动态的销毁的。

     

    3、作用域

    【定义】

        作用域是针对变量而言,指申明的变量在程序里的可应用范围。或者称为变量的可见性。

    【分类】

        只有函数、类、模块会产生作用域,代码块不会产生作用域(参考代码1)。作用域按照变量的定义位置可以划分为4类:

        Local(函数内部)局部作用域

        Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)

        Global(模块全局)全局作用域

        Built-in(内建)内建作用域

    【规则】

        1、静态作用域规则

             定义:python中变量的作用域是由它在源代码中的位置决定的。(名字查找是动态发生的)

             说明:参考代码3/4,以代码3为例说明,在模块中定义了一个全局变量 i = 1,在test方法中执行 i += 1,对变量 i进行了赋值动作,该赋值动作决定了i在test()方法中是一个局部变量, i += 1可以拆分为两步执行,首先执行 i + 1, 然后将结果赋值给i。执行i + 1操作时,i虽然申明为局部变量,但是没有绑定任何具体值,因此报错。

        2、最内嵌套作用域规则

             定义:由一个赋值语句引进的名字在这个赋值语句所在的作用域里是可见(起作用)的,而且在其内部嵌套的每个作用域内也可见,除非它被嵌套于内部的且引进同样名字的赋值语句所遮蔽。

             说明:参考代码5. 方法g()是方法f()中定义的内嵌函数。在方法f()中定义的局部变量 i =2,在内嵌方法 g()中是可见的。如果在g()中又定义一个重名的变量 i = 3,则f()中定义的变量将被遮蔽。

    4、命名空间与作用域的关系

        命名空间定义了在某个作用域内变量名和绑定值之间的对应关系,命名空间是键值对的集合,变量名与值是一一对应关系。作用域定义了命名空间中的变量能够在多大范围内起作用。

        命名空间在python解释器中是以字典的形式存在的,是以一种可以看得见摸得着的实体存在的。作用域是python解释器定义的一种规则,该规则确定了运行时变量查找的顺序,是一种形而上的虚的规定。

    【变量查找法则】

        python解释器动态执行过程中,对遇到的变量进行解释时,是按照一条固定的作用域链查找解释的,又称为LEGB法则

        其中L代表Local 局部作用域,E代表Enclosing 嵌套作用域,G代表Global 全局作用域,B代表Built-in 内建作用域。

        python解释器查找变量时,会按照顺序依次查找局部作用域,嵌套作用域,全局作用域,内建作用域,在任意一个作用域中找到变量则停止查找,所有作用域查找完成没有找到对应的变量,则抛出 NameError: name 'xxxx' is not defined的异常。

        在局部作用域中,可以看到局部作用域、嵌套作用域、全局作用域、内建作用域中所有定义的变量。

        在全局作用域中,可以看到全局作用域、内建作用域中的所有定义的变量,无法看到局部作用域中的变量。

                

  • 相关阅读:
    View(视图)
    计算器 ——给按钮添加监听器
    Activity(活动)
    UI组件
    计算器界面——GridLayout
    信息界面——GridLayout
    Android计算器界面 TableLayout
    javaji基础x2
    java的开始
    数据类型
  • 原文地址:https://www.cnblogs.com/xc1234/p/9153995.html
Copyright © 2011-2022 走看看