当前位置 : 主页 > 编程语言 > python >

二、名称空间、作用域、加载顺序、取值顺序。

来源:互联网 收集:自由互联 发布时间:2022-06-15
一、命名空间 Python使用叫做命名空间的东西来记录变量的轨迹。命名空间是一个 字典(dictionary) ,它的键就是变量名,它的值就是那些变量的值。 当程序运行时,代码从上之下一次

一、命名空间

  • Python使用叫做命名空间的东西来记录变量的轨迹。命名空间是一个 字典(dictionary) ,它的键就是变量名,它的值就是那些变量的值。
  • 当程序运行时,代码从上之下一次执行,他会将变量与值的关系存储在一个空间中,这个空间叫做名称空间,命名空间,全局名称空间。

在一个 Python 程序中的任何一个地方,都存在几个可用的命名空间。

  • 每个函数都有着自已的命名空间,叫做局部命名空间,它记录了函数的变量,包括函数的参数和局部定义的变量。
  • 每个模块拥有它自已的命名空间,叫做全局命名空间,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 还有就是内置命名空间,任何模块均可访问它,它存放着内置的函数和异常,内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。

二、命名空间查找

当一行代码要使用变量 x 的值时,Python 会到所有可用的名字空间去查找变量,按照如下顺序:

  • 局部命名空间:特指当前函数或类的方法。如果函数定义了一个局部变量 x,或一个参数 x,Python 将使用它,然后停止搜索。
  • 全局命名空间:特指当前的模块。如果模块定义了一个名为 x 的变量,函数或类,Python 将使用它然后停止搜索。
  • 内置命名空间:对每个模块都是全局的。作为最后的尝试,Python 将假设 x 是内置函数或变量。
  • 如果 Python 在这些名字空间找不到 x,它将放弃查找并引发一个 NameError 异常,如,NameError: name 'aa' is not defined。

三、函数的嵌套

  • 先在当前 (嵌套的或 lambda) 函数的命名空间中搜索;
  • 然后是在父函数的命名空间中搜索;
  • 接着是模块命名空间中搜索;
  • 最后在内置命名空间中搜索;
  • 示例1:

    info = "Adress : "
    def func_father(country):
    def func_son(area):
    city= "Shanghai " #此处的city变量,覆盖了父函数的city变量
    print(info + country + city + area)
    city = " Beijing "
    #调用内部函数
    func_son("ChaoYang ");

    func_father("China ")

    #输出结果
    Adress : China Shanghai ChaoYang

    以上示例中,info在全局命名空间中,country在父函数的命名空间中,city、area在自己函数的命名空间中。
    示例2:

    def func1():
    print(666)

    def func2():
    func1()
    print(333)

    def func3():
    func2()
    print(222)
    print(111)
    func3()
    print(555)

    def func1():
    name = 'alex'
    print(name)
    def func2():
    name1 = '太白'
    print(333)
    print(444)
    func2()
    func1()

    #输出结果:
    666
    222
    alex
    333

    四、命名空间的生命周期

  • 内置命名空间在 Python 解释器启动时创建,会一直保留,不被删除。
  • 模块的全局命名空间在模块定义被读入时创建,通常模块命名空间也会一直保存到解释器退出。
  • 当函数被调用时创建一个局部命名空间,当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间。
  •   Python 的一个特别之处在于其赋值操作总是在最里层的作用域。赋值不会复制数据——只是将命名绑定到对象。删除也是如此:"del y" 只是从局部作用域的命名空间中删除命名 y 。事实上,所有引入新命名的操作都作用于局部作用域。
    示例:

    i=1
    def func2():
    i=i+1

    func2()

    #输出结果:
    #错误:UnboundLocalError: local variable 'i' referenced before assignment

    由于创建命名空间时,python会检查代码并填充局部命名空间。在python运行那行代码之前,就发现了对i的赋值,并把它添加到局部命名空间中。当函数执行时,python解释器认为i在局部命名空间中但没有值,所以会产生错误。

    def func3():
      y=123
      del y
      print(y)

    func3()

    #输出结果:
    #错误:UnboundLocalError: local variable 'y' referenced before assignment
    #去掉"del y"语句后,运行正常

    五、作用域

    作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

    5.1:全局作用域:

    • 内置名称空间。
    • 全局名称空间。
    • 包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效。

    5.2:局部作用域:

    • 局部名称空间。
    • 局部名称空间,只能在局部范围内生效。

    六、加载顺序

    内置命名空间(程序运行前加载)  - ->  全局命名空间(程序运行中:从上到下加载)  - ->  局部命名空间(程序运行中:调用时才加载)

    七、取值顺序(单向不可逆)

    在局部调用:

    • 局部命名空间 - -> 全局命名空间 - ->内置命名空间

    在全局调用:

    • 全局命名空间 - ->内置命名空间

    综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。

    八、内置函数locals和globals 

    • globals() 返回一个字典,字典里面的内容是全局作用域的内容。
    • locals():返回一个字典,当前位置 的所有变量。

    示例:

    name = 'alex'
    age = 1000
    sex = '男'

    def func1():
    name1 = 'oldboy'
    age = 10000
    print(globals())
    print(locals())

    func1()
    #输出结果:
    3
    2print(globals())
    print(locals())
    def func1():
    name1 = 'oldboy'
    age = 10000
    def func2():
    name2 = 'wusir'
    age2 = 25
    print(globals())
    print(locals())
    func2()
    func1()

    #输出结果:
    3
    2

    locals 与 globals 之间的区别

    • locals 是只读的,globals 不是。

    示例:

    def func1(i, info):
    x = 12345
    print(locals())
    locals()["x"]= 6789
    print("x=",x)

    y=54321
    func1(1 , "first")
    globals()["y"]= 9876
    print( "y=",y)

    输出结果:
    {'i': 1, 'x': 12345, 'info': 'first'}
    x= 12345
    y= 9876

    解释:   locals 实际上没有返回局部名字空间,它返回的是一个拷贝。所以对它进行改变对局部名字空间中的变量值并无影响。   globals 返回实际的全局名字空间,而不是一个拷贝。所以对 globals 所返回的 dictionary 的任何的改动都会直接影响到全局变量。

    九、命名空间的访问

    9.1:global关键字

    • 声明一个全局变量。
    • 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
    • 对可变数据类型(list,dict,set)可以直接引用不用通过global。
    • 全局 (模块级别)命名空间可以通过 globals() BIF来访问。
    • 返回一个字典,字典里面的内容是全局作用域的内容。

    global关键字举例:

    def func():
    global a
    a = 3
    func()
    print(a)


    count = 1
    def search():
    global count
    count = 2
    search()
    print(count)

    #输出结果:
    2

    对于可变数据类型的应用举例:

    li = [1,2,3]
    dic = {'a':'b'}

    def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
    change()
    print(li)
    print(dic)

    #输出结果
    {'a': 'b', 'q': 'g'}
    [1, 2, 3, 'a']
    [1, 2, 3, 'a']
    {'a': 'b', 'q': 'g'}

    9.2:nonlocal关键字

    • 不能修改全局变量。
    • 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
    • locals 返回一个名字/值对的 dictionary。这个 dictionary 的键是字符串形式的变量名字,dictionary 的值是变量的实际值。
    • 返回一个字典,当前位置 的所有变量。

    nonlocal关键字举例:

    def add_b():
    b = 42
    def do_global():
    b = 10
    print(b)
    def dd_nonlocal():
    nonlocal b
    b = b + 20
    print(b)
    dd_nonlocal()
    print(b)
    do_global()
    print(b)
    add_b()

    #输出结果:
    30
    42


    作者:HaydenGuo

    每一个前十年都想不到后十年我会演变成何等模样,可知人生无常,没有什么规律,没有什么必然。

    只要我还对新鲜的知识、品格的改进、情感的扩张、有胃口,这日子就是值得度过的。

    上一篇:一、函数的定义、调用、返回值、参数。
    下一篇:没有了
    网友评论