最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Python3萌新入门笔记(20)

Python教程 小楼一夜听春语 8376浏览 0评论

这一篇教程,我们先来看一段代码。

示例代码:

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

刚才的这段代码,可能不太容易理解。

因为里面包含了几部分我们没有接触过的内容。

第一部分,我们先来了解一下函数嵌套。

在Python中可以在函数的内部再定义函数。

大家能够看到,在上方代码中函数outside的内部,又定义了一个函数inside。

这种结构就是函数嵌套。

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

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

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

示例代码:(接上一段代码)

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

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

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

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

大家可以通过运行以下代码进行对比。

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

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

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

    return inside

outside()

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

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

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

    return inside()

outside()

第二部分,我们来了解变量的作用域。

在上方代码中,我们能够看到有3个变量的名称都是x。

这3个x并非同一个变量,只是名称一样,它们的特点可以这么理解:

  • 最外层的变量x是全局变量
  • 函数outside中和inside定义的变量x,都是局部变量。
  • 函数outside中的变量x,相对于内嵌的函数inside,它是外部变量。

这3个变量有着不同的作用域。

如上图所示,3个x变量的作用域如下:

  • 最外层的变量x,它的作用域是整个模块中。
  • 函数outside中的变量x,作用域是函数outside内部以及内嵌函数inside。
  • 函数inside中的变量x,作用域是函数inside内部。

也就是说,全局变量作用域是当前模块内,而局部变量作用域是函数以及内嵌函数中。

但是,这里大家可能会有疑问,既然全局变量作用域是全局的,那么在函数中又创建同名变量不是冲突了吗?

这个不用担心,当在函数中创建与全局变量同名的局部变量时,在函数内部会自动屏蔽同名的全局变量。

所以,在本文开头的代码中,显示输出的结果并不相同。

下图就是3个变量x的值输出显示时的过程。

到这里,我们有必要来了解一下作用域的概念。

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

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

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

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

第三部分,我们来了解如何在函数中读取与修改全局变量。

首先,我们先来看读取全局变量。

一般情况下,我们在函数中可以直接读取全局变量。

这里我们看一段根据半径计算圆形周长的代码。

示例代码:

radius = 21  # 创建半径的变量并赋值

def get_perimeter():  # 定义获取周长的函数
    perimeter = round(2 * 3.14 * radius,2)  # 创建周长的变量保存计算结果
    return perimeter  # 返回结果

print(get_perimeter()) # 显示输出结果为:131.88

在上方代码中,我们定义了全局变量radius,在函数中我们可以直接调用这个变量参与计算。

但是,如果我们在函数中创建的局部变量如果与全局变量同名,这时候怎么调用全局变量呢?

我们可以借用内置函数globals来获取到全局变量。

示例代码:

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

print(global_case())  # 显示输出结果为:15

接下来,我们来看如何在函数中修改全局变量(或者叫重新绑定全局变量为其他值)。

当我们创建了某个全局变量,在函数中无法直接修改这个变量。

就像之前的代码中,即便在函数中给x赋值(例如x=1),也只是创建了一个新的局部变量,而不是对全局变量x进行修改。

那么,如何在函数中修改全局变量呢?

我们可以使用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

第四部分,我们来了解一下闭包(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))

本节知识点:

1、嵌套函数;

2、作用域的概念;

3、函数中对外部变量与全局变量的修改;

4、闭包的概念。

本节英文单词与中文释义:

1、inside:内部

2、outside:外部

3、radius:半径

4、perimeter:周长

5、case:情形

6、synthesis:合成

7、execute:执行

练习:独立完成宝石合成的示例代码。

转载请注明:魔力Python » Python3萌新入门笔记(20)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (12)

  1. 头像
    已阅,支持一下作者 🙂
    走路爱走神6年前 (2018-05-25)回复
  2. 头像
    补充说明:如果想在内嵌函数中修改外层函数中的局部变量,可以使用关键字nonlocal进行声明。使用方法和关键字global类型。 这句话的最后一个字写错了,应该是类似?
    走路爱走神6年前 (2018-05-25)回复
  3. 头像
    闭包还是没理解啊
    chensir6年前 (2018-10-26)回复
  4. 头像
    感谢楼楼。
    善天果5年前 (2019-03-07)回复
  5. 头像
    def hecheng():
        count = int(input('请放入宝石:'))
        while True:
            if count < 3:
                x = 3 - count
                count += int(input('至少需放入3颗普通宝石,请再放入%s颗' % x))
            elif count % 3 != 0:
                x = 3 - count % 3
                count += int(input('放入的普通宝石必须是3的倍数,请再放入%s颗' % x))
            else:
                break
        def jieguo():
            gaoji = count // 3
            print('--------合成中---------')
            print('您放入了%s颗宝石,合成出%s颗高级宝石' % (count, gaoji))
        return jieguo()
    exe = hecheng()
    
    ============老师,为什么加了EXE()这句后调用函数就提示出错,去掉那一句就没有问题,我的是PYTHON3.7.3
    金金金金金金金金金qq5年前 (2019-06-24)回复
    • 小楼一夜听春语
      我的代码return的是一个函数对象,你的代码return的是一个函数返回值。
      小楼一夜听春语5年前 (2019-06-25)回复
    • 头像
      去掉结果后面的()应该可以
      寒风5年前 (2019-08-24)回复
  6. 头像
    第三部分:补充说明:关键字 nonlocal 的用法那里有个错别字,应该是:和关键字 global 类似,小楼老师您写成了类型。 附上练习答案,最近在学英文 💡 def synthesis(): num = int(input("Please input the number of jewels: ")) while 1: if num < 3: num += int(input("The number of jewels is too less, please input more: ")) else: break def execute(): result = num // 3 print("Congratulations! You put %s jewels and synthesis %s sophisticated jewels!" % (num, result)) return execute exe = synthesis() print("=====================Start to synthesis======================") exe()
    Lo5年前 (2019-06-28)回复
  7. 头像
    其实我很好奇,评论中引用代码是怎么做到的?回复支持 markdown 吗? ```python print("hello!") ```
    Lo5年前 (2019-06-28)回复
    • 小楼一夜听春语
      不支持,我加的。
      小楼一夜听春语5年前 (2019-06-30)回复
  8. 头像
    老师我不明白这个为什么要用内嵌函数,还是单纯为了举这样的例子而写的呢?
    寒风5年前 (2019-08-24)回复
  9. 头像
    def hecheng_baohsi(): count=int(input('请放入宝石:')) while True: if count<3: count+=int(input('宝石数量不够,请继续放入宝石')) else: break print('--------开始合成--------') he_cheng_shu=count//3 print('您总共放入了%s颗宝石,合成了%s颗高级宝石'%(count,he_cheng_shu)) hecheng_baohsi()
    寒风5年前 (2019-08-24)回复