参考:http://www.opython.com/314.html

26 内嵌函数的执行

示例代码:

x = 0  # 全局变量

def outside():  # 定义函数
    x = 1  # 局部变量,内嵌函数的外部变量

    def inside():  # 定义内嵌函数
        x = 2  # 局部变量
        return x

    return x, inside # 将变量值和函数返回

o, i = outside()  # 通过两个变量接收outside函数的返回值x和inside
print(x)  # 显示输出结果为:0
print(o)  # 显示输出结果为:1
print(i())  # 显示输出结果为:2

在上方代码中,大家能够看到函数的返回值不仅可以返回多个,而且可以返回内嵌函数(这是闭包,后面会讲到)。

返回内嵌函数时,如果函数名称后方没有加上“()”,调用外层函数时不会立即执行返回的函数,需要在调用外层函数后,添加“()”来执行。例如,上方代码最后一句中的“i()”,就是执行变量中保存的函数。

而且,我们也可以用下面这种方法去执行返回的函数。

示例代码:

outside()[1]() # 调用外层函数时,获取的返回值列表中第2项是函数,加上()则会被执行。

这是外层函数有多个返回值时的方法,通过对外层函数返回值列表进行索引,找到函数执行。

如果,外层函数只有一个返回值,我们可以通过函数名称后方直接加上“()()”去执行返回的函数。

另外,在外层函数返回内嵌函数时,在函数名称后方加上了“()”,会在调用外层函数时自动执行。

对比如下两段代码

示例代码(返回函数不带括号):

def outside():
    print('执行外层函数!')

    def inside():
        print('执行内嵌函数!')

    return inside # 返回函数不带括号

outside() # 只执行外层函数outside(),打印 执行外层函数

示例代码(返回函数带括号):

def outside():
    print('执行外层函数!')

    def inside():
        print('执行内嵌函数!')

    return inside() # 返回函数带括号

outside() # 外层函数和内嵌函数同时执行,打印 执行外层函数,执行内嵌函数

27 Python作用域(命名空间)

Python 中作用域也叫命名空间,命名空间是一个我们看不到的字典,字典的键记录变量的名称,字典的值记录着变量的值。

每个模块都会创建一个全局命名空间,用于记录模块的变量,包括全局变量和局部变量,以及其它导入模块中的变量。

每个函数调用时都会创建一个局部命名空间,用于记录函数的变量,包括函数的参数和函数内部创建的变量。

另外,还有内置命名空间,任何模块都能够访问,记录了内置函数和异常。

28 全局变量的调用与修改

调用:在函数中创建的局部变量如果与全局变量同名,这时候如何调用全局变量

在函数中创建的局部变量如果与全局变量同名时,借用内置函数 globals 来获取到全局变量

示例代码:

def global_case():  # 定义函数
    x = 5  # 创建同名局部变量
    result = x * globals()['x']  # 通过globals函数获取全局变量x与局部变量x相乘
    return result  # 返回结果

print(global_case())  # 显示输出结果为:15
修改:如何在函数中修改全局变量(或者叫重新绑定全局变量为其他值)

使用 global 关键字,声明要重新绑定的全局变量,Python 解释器就能够知道,我们是要对已有的全局变量进行修改,而不是创建一个新的同名局部变量。

示例代码:

x = 10 # 创建全局变量

def change_global():  # 定义函数
    global x  # 声明要修改的全局变量
    x = 5  # 修改变量值

change_global()  # 调用函数
print(x)  # 显示输出全局变量x的值,结果为:5

在上方代码中,大家能够看到,我们定义了全局变量x和修改这个全局变量的函数 change_global 。

在修改全局变量的函数 change_global 中我们并没有设定返回值,它只起到修改的作用。

所以,当我们执行了这个函数,再显示输出变量x的值,就是经过修改后的值


补充说明:如果想在内嵌函数中修改外层函数中的局部变量,可以使用关键字 nonlocal 进行声明。使用方法和关键字 global 类似。

示例代码:

def nonlocal_case():
    x = 10 # 创建局部变量

    def change_nonlocal():  # 定义函数
        nonlocal x  # 声明要修改的外部变量
        x = 5  # 修改变量值

    change_nonlocal() # 调用修改函数执行修改
    return x # 返回变量x的值

print(nonlocal_case())  # 显示输出全局变量x的值,结果为:5

29 闭包(closure)

在网上查了闭包的解释,百度百科中是这样说的:闭包由要执行的代码块(内嵌函数)和为自由变量(外部变量)提供绑定的计算环境(作用域/命名空间)组成。

注意,上面这段话中,括号里面的内容是我按照自己的理解添加的。

以我个人的观点,闭包就是由返回的内嵌函数和这个内嵌函数中用到的外部变量(1)以及其他函数(2)打包而成的一个整体。

(1)外部变量,包括:外层函数的参数变量以及外层函数中定义的局部变量

(2)其它函数,包括:外层函数中定义的其他内嵌函数

例如,在本文第一段代码中就有闭包的出现。

为了更清楚的解释闭包的概念,我们来看一段代码。

用户输入合成的宝石数量,然后执行合成计算。

示例代码:

def synthesis():
    count = int(input('请放入宝石:'))
    while True:
        if count < 3:
            count += int(input('宝石太少,请再放入一些宝石:'))
        else:
            break

    def execute():
        result = count // 3  # 调用外部变量进行整除运算
        print('您放入了%s颗宝石,合成了%s颗高级宝石!' % (count,result))

    return execute 

exe = synthesis() # 调用函数
print('------------------开始合成------------------')
exe() #执行闭包内容

这段代码中,外层函数被调用,执行return语句时,会将内嵌函数返回,形成闭包存入变量exe。

exe中的闭包内容包括:外层函数中变量count和内嵌函数excute。

exe()语句会执行闭包中的内容,我们可以认为执行了以下语句。

示例代码:

count = *  # "*"表示外层函数执行后,变量count的最终值
def execute():
    result = count // 3  # 调用外部变量进行整除运算
    print('您的%s颗宝石,合成了%s颗高级宝石!' % (count, result))