前面介绍了函数可以包含内部函数,甚至可以从父函数返回内部函数。现在做好准备,下面将进入函数式编程中较深的领域。内部函数不仅可以从父函数返回,还可以捕获并携带父函数的某些状态。下面对前面的get_speak_func示例做些小改动来逐步说明这一点:
仔细看看内部函数whisper和yell,注意其中并没有text参数。但不知何故,内部函数仍然可以访问在父函数中定义的text参数。它们似乎捕捉并记住了这个参数的值。拥有这种行为的函数被称为词法闭包(lexical closure),简称闭包。闭包在程序流不在闭包范围内的情况下,也能记住封闭作用域中的值。实际上,这意味着函数不仅可以返回行为,还可以预先配置这些行为。用另一个例子来演示一下:
这个例子中,make_adder作为工厂函数来创建和配置各种adder函数。注意,这些adder函数仍然可以访问make_adder函数中位于封闭作用域中的参数n。虽然Python中所有函数都是对象,但反之不成立。有些对象不是函数,但仍然可以调用,因此在许多情况下可以将其当作函数来对待。如果一个对象是可调用的,意味着可以使用圆括号函数调用语法,甚至可以传入调用参数。这些都由__call__方法完成:
当然,不是所有对象都可以调用,Python内置了callable函数,用于检查一个对象是否可以调用。
lambda是单表达式函数Python中的lambda关键字可用来快速声明小型匿名函数。lambda函数的行为与使用def关键字声明的常规函数一样,可以用于所有需要函数对象的地方。
lambda函数只能含有一个表达式,不能使用语句或注解,不能使用返回语句。执行lambda函数时会计算其中的表达式,然后自动返回表达式的结果,所以其中总是有一个隐式的返回表达式。应该在什么时候使用lambda函数呢?从技术上讲,每当需要提供一个函数对象时,就可以使用lambda表达式。而且lambda是匿名的,不需要分配名字。因此,lambda能方便灵活的快速定义Python函数。
上面的例子按照每个元组中的第2个值对元组列表进行排序。这种情况下,用lambda函数能快速修改排序顺序。下面是另一个示例:
希望你能从中看出lambda带来的灵活性。lambda也可以像词法闭包那样工作。词法闭包是什么?这只是对某种函数的一个奇特称呼,该函数能记住来自封闭词法作用域的值,即使程序流已经不在作用域中也不例外。
在上面的例子中,即使是在make_adder函数(封闭的作用域)中定义的,但对于x + n ,lambda仍然可以访问n的值。
不应过度使用lambda
以上这种方式虽然在技术上可行且足够花哨,但会让那些工期很紧并且需要快速修复bug的人觉得难以理解。将lambda和map()或filter()结合起来构建复杂的表达式也很难让人理解,此时用列表解析式或生成器表达式通常会清晰不少:
今天就到这,下一节我会介绍Python中非常重要的特性:装饰器!
深入理解python特性_深入理解Python特性(2)
最新推荐文章于 2023-04-14 09:04:15 发布