【函数篇】函数的进阶,名称空间、作用域、函数的嵌套、作用域链

名称空间
内置名称空间:
存放时的是系统内置的名称,python一启动时,这些名称已经存放在内存;比如:print,input等
全局名称空间:
存放的是自定义的名称,变量名,函数名等等
局部名称空间:
在函数体内的自定义的名称
加载顺序为:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
调用顺序为:
在局部调用时:局部-->全局-->内置
在全局调用时:全局-->内置

作用域
全局作用域:内置名称空间和全局名称空间被统称为全局作用域;在整个文件的任意位置都能被引用、全局有效
局部作用域:函数体内的被称为局部作用域;只能在局部范围内生效
globals():以字典的形式返回全局作用域的变量的对应关系
locals():以字典的形式返回当前作用域的变量的对应关系(由于是当前,可以用在全局作用域,也可以是局部作用域)
i = 10
n = 20
def func():
    a = 1
    def count():
        b = 1
        def num():
            print(a,b)
        num()
    count()
func()
print(globals())  #全局作用域变量的对应关系,可以得到i,n的对应关系,而局部的无法得到
print(locals())    #当前作用域的变量对应关系,由于这里的当前是在全局作用域下,所以同样可以得到i,n的对应关系,局部的同样无法得到
如果我们把globals()与locals()的位置换一下:
内部函数调用外部函数:
i = 10
n = 20
def func():
    a = 1
    print(locals())  #{'a': 1}
    print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
    def count():
        b = 1
        print(locals())  #{'b': 1, 'a': 1}
        print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
        def num():
            c = 1
            print(locals())  #{'c': 1, 'a': 1, 'b': 1}
            print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
            def old():
                print(a, b)#调用
                print(locals())  #{'a': 1, 'b': 1}
                print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
            old()
        num()
    count()
func()
不进行调用:
i = 10
n = 20
def func():
    a = 1
    print(locals())#{'a': 1}
    print(globals()) #全局作用域的所有变量的对应关系,但不包含局部的
    def count():
        b = 1
        print(locals())#{'b': 1}
        print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
        def num():
            c = 1
            print(locals())#{'c': 1}
            print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
            def old():
                d = 1
                print(locals())#{'d': 1}
                print(globals())#全局作用域的所有变量的对应关系,但不包含局部的
            old()
        num()
    count()
func()


上面一种情况是在内部函数调用了外部函数的变量,这时locals()获取的变量信息与不在内部函数调用外部函数的变量获取的信息完全不一样;
当内部函数不对外部函数的变量进行调用时,locals()只有获取当前作用域的变量信息;
当内部函数对外部函数的变量进行调用时,变量信息会在包含的局部作用域逐级从上至下传导,直到调用结束


函数的嵌套
嵌套的调用:定义在全局作用域的函数被另外一个函数调用
def max(a,b):
   c = a if a > b else b
   return c
print(max(1,2))

def new_max(x,y,z):
    c = max(x,y) #调用全局作用域的函数max
    s = c if c > z else z
    return s
print(new_max(4,5,6))

嵌套的定义:定义在内部的函数无法直接在全局被调用
def func():
    a = 1
    def fun1():
        print(a)
    fun1()
func()
fun1()#定义在内部的函数无法直接在全局被调用,会报错,可以以闭包的形式调用

函数的作用域链
global:对于不可变数据类型,在局部可以查看全局作用域中变量
但是不能直接对它进行修改操作
若想修改,需要添加global声明,声明后对该变量的任何修改对全局作用域有效
a =2
def func():
    a = 1
    def count():
        global a
        a = a +1
        print('全局',a) #a = 3,影响到全局作用域的a
        def num():
            global a
            a+=1
            print('全局',a) #a被上面的声明影响过一次,此时a = 4
        num()
    count()
func()


#打印:
全局 3
全局 4

nonlocal:局部作用域在嵌套内部可以查看局部作用域中的变量
但同样不能直接对它进行修改操作
若想修改,需要添加nonlocal声明,声明后依次向上一级寻找最近的变量,若局部作用域没有,则会报错
声明后对该变量的任何修改,以寻找到的作用域为起点,对以下的局部作用域有效,对全局无效
 
b = 4
def func():
    a = 1
    def count():
        nonlocal a
        # nonlocal b #报错,尽管下边有变量b,但只能从当前作用域逐级往上找,不能往下面的作用域找,且只能找局部的
        global b #不报错,声明的时全局作用域的变量
        b += 1
        a += 1
        print('局部',a)
        print('全局',b)
        def num():
            nonlocal a
            b = 1
            a+=1
            print('局部',a)
            def i():
                nonlocal a
                nonlocal b
                a+=1
                b+=1
                print('还是局部',a)
                print('局部',b)
            i()
        num()
    count()
func()
print('被影响的全局b=',b)


#打印:
局部 2
全局 5
局部 3
还是局部 4
局部 2
被影响的全局b= 5



 



 
原文地址:https://www.cnblogs.com/aizhinong/p/11356734.html