Python 语言及其应用 Chapter_4_Note_3 闭包_匿名函数lambda_生成器

我们又来到了闭包,上次看其他教程就是从闭包开始崩溃的,感觉这本教材还算通俗些,先做点笔记吧。


讲闭包前,先讲一下关于内部函数

内部函数
在Python 中,可以在函数中定义另外一个函数:
>>> def outer(a, b):
... def inner(c, d):
... return c + d
... return inner(a, b)
...
>>>
>>> outer(4, 7)
11
当需要在函数内部多次执行复杂的任务时,内部函数是非常有用的,从而避免了循环和代
码的堆叠重复。对于这样一个字符串的例子,内部函数的作用是给外部的函数增加字符串
参数:
>>> def knights(saying):
... def inner(quote):
... return "We are the knights who say: '%s'" % quote
... return inner(saying)
...
>>> knights('Ni!')
"We are the knights who say: 'Ni!'"


闭包
内部函数可以看作一个闭包。闭包是一个可以由另一个函数动态生成的函数,并且可以改
变和存储函数外创建的变量的值。

下面的例子以之前的knights() 为基础。现在,调用新的函数knight2(),把inner() 函数
变成一个叫inner2() 的闭包。可以看出有以下不同点。
• inner2() 直接使用外部的saying 参数,而不是通过另外一个参数获取
• knights2() 返回值为inner2 函数,而不是调用它。
>>> def knights2(saying):
... def inner2():
... return "We are the knights who say: '%s'" % saying
... return inner2
...

inner2() 函数可以得到saying 参数的值并且记录下来。return inner2 这一行返回的是
inner2 函数的复制(没有直接调用)。所以它就是一个闭包:一个被动态创建的可以记录
外部变量的函数。
用不同的参数调用knights2() 两次:
>>> a = knights2('Duck')
>>> b = knights2('Hasenpfeffer')
那么a 和b 会是什么类型?
>>> type(a)
<class 'function'>
>>> type(b)
<class 'function'>
它们是函数,同时也是闭包:

>>> a
<function knights2.<locals>.inner2 at 0x10193e158>
>>> b
<function knights2.<locals>.inner2 at 0x10193e1e0>
如果调用它们,它们会记录被knights2 函数创建时的外部变量saying:
>>> a()
"We are the knights who say: 'Duck'"
>>> b()
"We are the knights who say: 'Hasenpfeffer'"



匿名函数:lambda()函数
Python 中,lambda 函数是用一个语句表达的匿名函数。可以用它来代替小的函数。
首先,举一个使用普通函数的例子。定义函数edit_story(),参数列表如下所示:
• words——单词列表
• func——遍历列表中单词的函数
>>> def edit_story(words, func):
... for word in words:
... print(func(word))

现在,需要一个单词列表和一个遍历单词的函数。对于单词,可以选择我的猫从某一台阶
上掉下时发出的声音:
>>> stairs = ['thud', 'meow', 'thud', 'hiss']
对于函数,它要将每个单词的首字母变为大写,然后在末尾加上感叹号 , 用作猫画报的标
题非常完美:
>>> def enliven(word): # 让这些单词更有情感
... return word.capitalize() + '!'
混合这些“配料”:
>>> edit_story(stairs, enliven)
Thud!
Meow!
Thud!
Hiss!
最后,到了lambda。enliven() 函数可以简洁地用下面的一个lambda 代替:
>>>
>>> edit_story(stairs, lambda word: word.capitalize() + '!')
Thud!
Meow!
Thud!
Hiss!
>>>
lambda 函数接收一个参数word。在冒号和末尾圆括号之间的部分为函数的定义。
通常,使用实际的函数(例如enliven())会比使用lambda 更清晰明了。但是,当需要定
义很多小的函数以及记住它们的名字时,lambda 会非常有用。尤其是在图形用户界面中,
可以使用lambda 来定义回调函数。请参见附录A 中的例子。


这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

举个简单的例子,定义一个generator,依次返回数字1,3,5:

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:

>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

我的理解是,生成器碰到yield以后,就中断,但是保存进度,下一次调用的时候继续从中断的地方往后走。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值