前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python嵌套函数 闭包

Python嵌套函数 闭包

作者头像
猫叔Rex
发布2022-01-24 13:35:26
9350
发布2022-01-24 13:35:26
举报
文章被收录于专栏:科学计算科学计算

1. 什么是嵌套函数

  嵌套函数就是在函数中定义函数,英文叫nested function

代码语言:javascript
复制
def outer(x):
    def inner():
        print(x)
    inner()

这也很好理解,在函数outer中定义了另外一个函数inner,而inner也必须在outer中被调用才能执行。

我们还可以直接把内容定义的函数当做返回值:

代码语言:javascript
复制
def outer(x):
    def inner():
        print(x)
    return inner()

这样outer这个函数其实返回的是None,它只是会打印出输入参数x的值

代码语言:javascript
复制
outer(10)
>>> 10

当然,也有的地方直接返回函数名,而不是返回函数的执行结果:

代码语言:javascript
复制
def outer2(x):
    def inner(y):
        print(x+y)
    return inner

这是由于我们返回的是函数名,因此在使用的时候,后面需要跟参数:

代码语言:javascript
复制
foo = outer2(10)
foo(5)
>>> 15

2. 变量作用域

  两个函数处于不同的层次,肯定会有作用域的问题,关于Python中的作用域,网上的文章一大堆,这里我们说一下初学者们可能会忽略的东西。Python的函数中是不能对全局变量进行赋值,只能读取全局变量的值,但listdict除外,这是因为list和dict都是可变类型,而Number、String、Tuple和Sets这些都是不可变类型。

代码语言:javascript
复制
a = 1
def inc():
    a += 1
    return a
inc()

执行这段代码就会提示:

代码语言:javascript
复制
UnboundLocalError: local variable 'a' referenced before assignment
  • 但如果我们在函数内部把全局变量a的值打印出来,不去对它进行写操作:
代码语言:javascript
复制
a = 1
def prt():
    print(a)
prt()

这段代码是可以正确执行的。

  • 如果我们就是想在函数中修改全局变量的值,可以使用global关键字:
代码语言:javascript
复制
a = 1
def inc():
    global a
    a += 1
    return a
inc()
  • 如果在函数中重新定义一个名字一样的变量:
代码语言:javascript
复制
a = 1
def inc():
    a = 2
    return a
print(inc())
print(a)
>>> 2
>>> 1

这样的话,函数内部定义的变量a只是个局部变量,它是不会影响到全局变量a的。

  • 如果我们操作的是list:
代码语言:javascript
复制
a = [1]
def inc():
    a[0] += 1
    return a[0]
inc()

这段代码是可以执行的,我们也可以为list中添加其他元素:

代码语言:javascript
复制
a = [1]
def inc():
    a.append(2)
    return a
inc()
  • 如果重新定义相同名字的list,也只会是局部变量,不影响全局的list:
代码语言:javascript
复制
a = [1]
def inc():
    a = [2,3]
    return a
print(inc())
print(a)
>>> [2, 3]
>>> [1]
  • 嵌套函数的变量作用域跟上面所讲的基本是一致的,只是如果内部的函数想使用外部函数的变量,需要使用关键字nonlocal
代码语言:javascript
复制
def outer():
    a = 10
    def inner():
        nonlocal a
        a += 1
        print(a)
    inner()
outer()
>>> 11

3. 闭包

  说到嵌套函数,就必须要讲闭包,英文是Closures,什么是闭包?百度百科的解释如下:

代码语言:javascript
复制
闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

如何创建闭包?需要满足下面三点:

  • 闭包函数必须有内嵌函数
  • 内嵌函数需要引用该嵌套函数上一级中的变量
  • 闭包函数必须返回内嵌函数

所以我们在上面定义的outer2中的inner(),就会形成一个闭包。我们把前面的例子在展示一遍:

代码语言:javascript
复制
def outer2(x):
    def inner(y):
        print(x+y)
    return inner
foo = outer2(10)
foo(5)
>>> 15

为什么叫闭包呢?因为即便我们把outer2删除调,再执行foo()也是有效的,不会因为离开它的执行空间而被销毁导致无迹可寻。

代码语言:javascript
复制
del outer2
foo(6)
>>> 16

闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量。

代码语言:javascript
复制
foo.__closure__
>>> (<cell at 0x0000000004FE4408: int object at 0x00000000734D6D60>,)
foo.__closure__[0].cell_contents  
>>> 10

其他函数也有__closure__属性,只不过都是None。

4. 什么时候使用闭包

  闭包可以避免使用全局值,并提供某种形式的数据隐藏,也提供了一种面向对象的解决方案。

  当一个类只包含一个方法,此时比较适合使用闭包。但如果类中包含的方法比较多,还是直接使用class来定义比较合适。

代码语言:javascript
复制
def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier

闭包的使用:

代码语言:javascript
复制
# Multiplier of 3
times3 = make_multiplier_of(3)

# Multiplier of 5
times5 = make_multiplier_of(5)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 傅里叶的猫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 什么是嵌套函数
  • 2. 变量作用域
  • 3. 闭包
  • 4. 什么时候使用闭包
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档