Python岗面试官最喜欢问的问题,没有之一!
The following article is from 麦叔编程 Author 小K
来源丨经授权转自 麦叔编程(ID:maishucode)
作者丨小K
“闭包”可能算是计算机科学中的一个难点了,很多小伙伴可能学习Python至今也没有很好地掌握。
但是面试官就很希望问这个问题,那么上来先问你装饰器,再从装饰器跳到闭包的概念。(我就被问到过“闭包”)
要想了解闭包,首先要知道什么是嵌套函数。
什么是嵌套函数?
嵌套函数,顾名思义就是函数套函数,函数内部又定义了函数。
def outer(a):
b = a + 1
def inner():
print(b)
inner()
print(a)
outer(6)
输出结果:
7
6
嵌套函数在实际开发中也是非常重要的,它能把很多功能集合到一个函数中,而且十分pythonic,我们有机会再介绍嵌套函数,本文就让大家简单地了解下。
在进入正题之前,我们还需要了解一个知识点 -- 变量作用域
。
变量作用域
global_var = "maishu"
def print_var():
print(global_var)
print_var()
上面的代码中,函数print_var并没传入参数(变量)global_var
但是该函数也能正确执行,并打印出maishu
。
我们称一个py文件中最外层的变量为全局变量,而函数中的定义变量为局部变量。
我们可以想象成函数内部的变量是肉,而全局变量是土,函数如果有肉吃,那肯定要先吃肉,如果没肉吃,那也不能饿死,就要去吃土了。
food = "土"
def eat():
food = "肉"
print(f"我吃{food}")
eat()
执行结果:
我吃肉
把函数里的肉拿掉之后,
food = "土"
def eat():
print(f"我吃{food}")
eat()
执行结果:
我吃土
❝假如连土都没得吃了,那就只能饿死了(报错)。
❞
通过上面两段不同的代码,是否也能了解变量作用域的概念?
简单地了解嵌套函数和变量作用域之后,我们可以进入正题 -- 闭包
了。
什么是闭包?
我们先看下计算机科学中对闭包是如何定义的:
闭包包含「自由(未绑定到特定对象)变量」,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是「在定义代码块的环境中定义(局部变量)」。
“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(「作用域」)。
在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。
上面的三段文字,肯定是不太好理解的。老规矩,我们还是拿代码说话吧!
我把上文嵌套函数中的第一段代码稍微改造了下,
def outer(a):
b = a + 1
def inner():
print(b)
inner()
上面代码中b
是outer函数的局部变量,在调用outer函数的时候,内部函数inner也会被调用,b
的值被访问到并且打印出来,而当outer函数被调用结束过后,b
变量所占用的内存空间会被释放,就被垃圾回收机制给回收了,原因在上期有解释过,没有return把值返回出去!
上面的代码还只能称为为嵌套函数
,还不能被称为闭包
。
只要把内部函数inner返回出去,就能成为真正的闭包
。
def outer(a):
b = a + 1
def inner():
print(b)
return inner
这两段代码看起来差不多啊,为什么这段代码就是闭包?
「因为此时该函数中的变量b
可以脱离函数outer而存在在内存之中。」
不信我来试试:
def outer(a):
b = a + 1
def inner():
print(b)
return inner
func = outer(9)
func()
执行结果:
10
outer
函数在调用的时候,就把inner
给抛出去了,而自己被回收了,所以此时func
变量是等于inner
这个内部函数的。
就这样b
变量就脱离宿主outer
生存了。
再回到最初定义上,细品下~~~
总结
回到最初的问题上,什么是闭包?也是面试题的标准答法:
闭包必须满足的三个条件:
1、需要有一个内嵌函数;
2、内嵌函数需要引用定义在外部函数中的变量;(下方代码中的b变量,调用后脱离外部函数而存在)
3、内嵌函数需要被返回
def outer(a):
b = a + 1
def inner(): # 内嵌函数
print(b)
return inner # 此处内嵌函数被返回
「你学废闭包了吗?」
4、为什么C++中有函数指针还需要std::function?
5、为什么说 90% 的情况下,immer 能完胜 immutable?
点分享
点点赞
点在看