查看原文
其他

Python岗面试官最喜欢问的问题,没有之一!

IT服务圈儿 2023-02-06

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   # 此处内嵌函数被返回

「你学废闭包了吗?」

1、21个MySQL表设计的经验准则

2、一分钟看懂TCP粘包拆包

3、推荐 5 个开源的 yyds 效率神器

4、为什么C++中有函数指针还需要std::function?

5、为什么说 90% 的情况下,immer 能完胜 immutable?

点分享

点点赞

点在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存