首页 > 技术文章 > 函数嵌套、名称空间及作用域

Mr-shen 2019-11-11 19:21 原文

1、函数的嵌套

函数内嵌套函数,让内层函数封闭起来,不让外部直接调用

def index():
    print("hello world")
def fun():
    index()
fun()

将复杂并且小的功能在函数内部调用,解决代码结构不清晰问题

def index():
    register()
    login()
    ...
index()

2、名称空间

什么是名称空间?

存放名字与对象绑定关系的地方,如果想访问一个变量值,需要先访问对应的名称空间,拿到名字与对应的内存地址绑定关系

名称空间的分类

1、内置名称空间

python提前定义好的名字,就是存放在内置名称空间

生命周期:python解释器启动的时候生效,关闭python解释器失效

<built-in function print>###内建功能print

2、全局名称空间

python文件级别的名字,伴随着.py文件执行打开,执行结束关闭,if 、while、for内部定义的名字只要执行就会存放在全局名称空间

生命周期:启动执行py文件生效,执行完整个py文件才失效

x = 1  # 存在全局名称空间
if x == 1:
    x = 2   # 存在全局名称空间
print(x)
while x == 1: 
    x = 3 # 此步未执行,如果条件成立执行到则存放在全局名称空间内
print(x)

3、局部名称空间

函数内部定义的名字都是存放在局部名称空间内

生命周期:当调用函数时生效,函数体代码执行完立即失效

x = 3  # 存在全局名称空间
def index():
    x = 1  # 存在局部名称空间
    print(x) # 同函数体内x可以更改
index()
print(x)  # 打印是全局名称空间中x,因为函数执行结束,局部名称空间内x关闭

名称空间查找顺序:

如果从局部名称空间执行查找:局部 > 全局 > 内置,内置找不到就报错

如果从全局名称空间执行查找: 全局 > 内置,内置找不到就报错

名称空间加载顺序:

内置 > 全局 > 局部

x=1 # 第四步查找
def index():
    # x = 2 # 第三步查找
    def fun1():
        # x=3 # 第二步查找
        def fun2():
            # x=4 # 第一步查找
            print(x)
        fun2()
    fun1()
index()

函数内使用的名字在定义阶段已经规定死了,与你的调用位置无关,在另一个局部空间无法修改

x=1
def index():
    x = 2
    print(x) # 查找同级局部,如果没有再查找全局,不会被另一个局部名称空间修改
def fun():
    x = 3
    index()
fun()
>>> 2

x = 1
def inner():
    x = 2
    def wrapper():
        print(x)
    wrapper()
inner()
>>>
2

x = 1
def index(arg=x):  # 定义阶段默认参数已经传入参数1
    print(x)
    print(arg)
x = 2
index()
>>>
# 2
# 1

作用域

名称空间的作用范围

1、全局作用域

位于全局名称空间+内置名称空间中的名字属于全局范围,该范围内的名字全局可以调用

2、局部作用域

位于局部名称空间中的名字属于局部范围,该范围内的名字只能在函数内使用,函数调用结束失效

global:声明全局变量,在局部作用域内修改全局名称空间内的变量

x = 1
def index():
    # global x # 声明全局变量,将x=1修改为x=2
    x = 2
    def fun():
        print(x) # 先从局部作用域内查找,如果没有则查找全局作用域
index()
print(x)

nonlocal:在局部名称空间声明局部变量,修改外层能找到的局部名称空间内的变量,会从当前函数的外层一层一层查找变量x,若一直到最外层函数,都找不到,则抛出异常

x= 1
def index():
    x=2
    def fun1():
        global x
        x=3
        def fun2():
            x=4
            def fun3():
                nonlocal x
                x = 5
            print(f"1,{x}")
            fun3()
            print(f"2,{x}")
        fun2()
        print(f"3,{x}")
    fun1()
    print(f"4,{x}")
index()
print(x)
>>>
# 1,4
# 2,5
# 3,3
# 4,2
# 3

如果没有global或nonlocal,正常在局部修改外部的值不能修改,只有可变类型可以在局部名称空间修改外部的值

l1 =[1,2,3]
def index(a):
    l1.append(a)
    print(l1)
index(5)
print(l1)
index(6)
>>>
# [1, 2, 3, 5]
# [1, 2, 3, 5]
# [1, 2, 3, 5, 6]

x=1
def index():
    x = 2  # 只能修改一层,此层不能被修改
    def fun1():
        x=3  # 被修改
        def fun2():
            nonlocal x
            x=4
        fun2()
        print(x)
    fun1()
    print(x)
index()
>>>
4
2

推荐阅读