Lambda 表达式

你可以使用 Lambda 表达式创建匿名函数,即没有名称的函数。lambda 表达式非常适合快速创建在代码中以后不会用到的函数。尤其对高阶函数或将其他函数作为参数的函数来说,非常实用。

我们可以使用 lambda 表达式将以下函数

def multiply(x, y):
return x * y

简写为:

double = lambda x, y: x * y

Lambda 函数的组成部分

  1. 关键字 lambda 表示这是一个 lambda 表达式。
  2. lambda 之后是该匿名函数的一个或多个参数(用英文逗号分隔),然后是一个英文冒号 :。和函数相似,lambda 表达式中的参数名称是随意的。
  3. 最后一部分是被评估并在该函数中返回的表达式,和你可能会在函数中看到的 return 语句很像。

练习:Lambda 与 Map

map() 是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个将该函数应用到可迭代对象的每个元素的迭代器。下面的代码使用 map() 计算 numbers 中每个列表的均值,并创建列表 averages。测试运行这段代码,看看结果如何。

通过将 mean 函数替换为在 map() 的调用中定义的 lambda 表达式,重写这段代码,使代码更简练。

numbers = [
[34, 63, 88, 71, 29],
[90, 78, 51, 27, 45],
[63, 37, 85, 46, 22],
[51, 22, 34, 11, 18]
] def mean(num_list):
return sum(num_list) / len(num_list) averages = list(map(mean, numbers))
print(averages)

我这么改:

mean = lambda num_list: sum(num_list) / len(num_list)
averages = list(map(mean, numbers))

但其实可以直接将lambda整个写到map参数中averages = list(map(lambda x: sum(x) / len(x), numbers))

练习:Lambda 与 Filter

filter() 是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个由可迭代对象中的特定元素(该函数针对该元素会返回 True)组成的迭代器。下面的代码使用 filter()cities 中获取长度少于 10 个字符的名称以创建列表 short_cities。测试运行这段代码,看看结果如何。

通过将 is_short 函数替换为在 filter() 的调用中定义的 lambda 表达式,重写这段代码,使代码更简练。

cities = ["New York City", "Los Angeles", "Chicago", "Mountain View", "Denver", "Boston"]

def is_short(name):
return len(name) < 10 short_cities = list(filter(is_short, cities))
print(short_cities)

改为

short_cities = list(filter(lambda x: len(x) < 10, cities))

迭代器和生成器

迭代器是每次可以返回一个对象元素的对象,例如返回一个列表。我们到目前为止使用的很多内置函数(例如 enumerate)都会返回一个迭代器。

迭代器是一种表示数据流的对象。这与列表不同,列表是可迭代对象,但不是迭代器,因为它不是数据流。

生成器是使用函数创建迭代器的简单方式。也可以使用类定义迭代器,更多详情请参阅此处。

下面是一个叫做 my_range 的生成器函数,它会生成一个从 0 到 (x - 1) 的数字流。

def my_range(x):
i = 0
while i < x:
yield i
i += 1

注意,该函数使用了 yield 而不是关键字 return。这样使函数能够一次返回一个值,并且每次被调用时都从停下的位置继续。关键字 yield 是将生成器与普通函数区分开来的依据。

练习:实现 my_enumerate

请自己写一个效果和内置函数 enumerate 一样的生成器函数。

如下所示地调用该函数:

lessons = ["Why Python Programming", "Data Types and Operators", "Control Flow", "Functions", "Scripting"]

for i, lesson in my_enumerate(lessons, 1):
print("Lesson {}: {}".format(i, lesson))

应该会输出:

Lesson 1: Why Python Programming
Lesson 2: Data Types and Operators
Lesson 3: Control Flow
Lesson 4: Functions
Lesson 5: Scripting

my_enumerate 函数实现:

def my_enumerate(iterable, start=0):
""" return enumerate iterable """
for x in zip(range(start, len(iterable)+start), iterable):
yield x

练习:Chunker

如果可迭代对象太大,无法完整地存储在内存中(例如处理大型文件时),每次能够使用一部分很有用。

实现一个生成器函数 chunker,接受一个可迭代对象并每次生成指定大小的部分数据。

如下所示地调用该函数:

for chunk in chunker(range(25), 4):
print(list(chunk))

应该会输出:

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
[20, 21, 22, 23]
[24]

chunker 函数实现如下:

def chunker(iterable, size):
"""Yield successive chunks from iterable of length size."""
for i in range(0, len(iterable), size):
yield iterable[i:i + size]

可迭代的range()很强大,可以用len()也可以用切片。

为何要使用生成器?

你可能会疑问,为何要使用生成器,而不使用列表。下面这段摘自 stack overflow 页面 的内容回答了这个问题:

生成器是构建迭代器的 “懒惰” 方式。当内存不够存储完整实现的列表时,或者计算每个列表元素的代价很高,你希望尽量推迟计算时,就可以使用生成器。但是这些元素只能遍历一次。

另一种详细的解释如下(详细说明参见 该 stack overflow 页面。)

由于使用生成器是一次处理一个数据,在内存和存储的需求上会比使用list方式直接全部生成再存储节省很多资源。

由此区别,在处理大量数据时,经常使用生成器初步处理数据后,再进行长期存储,而不是使用 list。因为无论使用生成器还是 list,都是使用过就要丢弃的临时数据。既然功能和结果一样,那就不如用生成器。

但是生成器也有自己的局限,它产生的数据不能回溯,不像list可以任意选择。

lambda 和 iterable的更多相关文章

  1. JAVA入门

    编译型语言:高级语言代码经过编译器,一次性翻译为特定系统可以硬件执行的机器码,并包装成该平台所识别的可执行程序. 但是不同平台(系统)的机器码不同,所以编译后的可执行程序无法移植到其他平台.但是因为是 ...

  2. 20155237 2016-2017-2 《Java程序设计》第5周学习总结

    20155237 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 语法与继承架构 使用try...catch 与C语言中程序流程和错误处理混在一起不同,Jav ...

  3. Python——day14 三目运算、推导式、递归、匿名、内置函数

    一.三目(元)运算符 定义:就是 if...else...语法糖前提:简化if...else...结构,且两个分支有且只有一条语句注:三元运算符的结果不一定要与条件直接性关系​ cmd = input ...

  4. day 14 递归、匿名函数、内置函数

    三目运算符 # 三目(元)运算符:就是 if...else...语法糖# 前提:简化if...else...结构,且两个分支有且只有一条语句# 注:三元运算符的结果不一定要与条件直接性关系​cmd = ...

  5. day 14 三元运算符,列表字典推导式,递归,匿名函数,内置函数(排序,映射,过滤,合并)

    一.三元运算符 就是if.....else..... 语法糖 前提:if和else只有一条语句 #原始版 cmd=input('cmd') if cmd.isdigit(): print('1') e ...

  6. day14(1)--递归、匿名函数、内置函数

    一.递归 定义:本质上是回溯和递推 回溯:询问答案的过程 递推:推出答案的过程 前提: 回溯到一个有结果的值开始递推 回溯与递推的条件要有规律 方式: 直接递归:自己调用自己 间接递归:通过别人来调用 ...

  7. day14 十四、三元运算符,推导式,匿名内置函数

    一.三元(目)运算符 1.就是if...else...语法糖 前提:if和else只有一条语句 # 原来的做法 cmd = input('cmd:>>>') if cmd.isdig ...

  8. python基础——10(三元运算符、匿名函数)

    一.三元运算符 本质是if--else--的语法糖 前提:简化if--else--的结构,且两个分支有且只有一条语句 案例: a = 20 b = 30 res = a if a > b els ...

  9. Python解释器路径寻找规则

    Python编辑器路径寻址总结 Python编程优化 这场表演邀请了三位角色:run.sh.main.py.path.sh,拍摄场地选在了 Windows -> Git Bash 群演1号 ru ...

随机推荐

  1. h3c_7506e引擎主备镜像同步

    备份引擎的镜像文件不匹配会导致主引擎无法识别备引擎解决方法:1.备份主引擎上的启动文件同步到备引擎    ftp ip地址    get 在ftp服务器的镜像文件名 为其命名为本地文件(均为源文件名) ...

  2. inno安装客户端,写注册表url调用客户端

    [Registry] Root: HKCR; SubKey: xxx; ValueData: "xxx"; ValueType: string; Flags: CreateValu ...

  3. SQL注入学习(一)

    注入攻击的本质:web应用程序没有过滤用户输入或过滤不严谨,直接把用户输入的恶意数据当做代码执行 两个条件: 1.用户能够控制输入 2.原本程序要执行的代码,拼接了用户输入的数据 注入类型 SQL注入 ...

  4. Linux第九节课学习笔记

    fdisk可添加.删除.转换分区. 创建主分区:n-p-w:扩展分区:n-e:逻辑分区:n-l. SWAP分区专用格式化命令mkswap,专用挂载命令swapon. 磁盘容量配额中,硬限制必须,软限制 ...

  5. test markdown to html

    软件版本 PHP 5.5.25 Yaf 2.3.2 域名 正式域名 gm.mgame.qihoo.net demo域名 demo.gm.mgame.qihoo.net 配置 配置目录 后台配置 con ...

  6. C++ Object实体类

    *暂未完成,因为无尽BUG滚滚来. 好长时间没写完,一是能力不够,二是我还得给老板写WEB的代码.可是我不会WEB!js和PHP简直就是世界上最好的语言,因为它们能够让人更快地进入极乐世界. 让我写一 ...

  7. centos7 升级openssh到openssh-8.0p1版本

    环境介绍 centos7.3和centos7.6升级完毕测试登录ssh以及重启后登录ssh均无问题. 前期请自行配置好yum源(如果不会请百度) 整个过程不需要卸载原先的openssl包和openss ...

  8. ActiveMQ (三)—持久化消息

    ActiveMQ的另一个问题就是只要是软件就有可能挂掉,挂掉不可怕,怕的是挂掉之后把信息给丢了,所以本节分析一下几种持久化方式: 一.持久化为文件 ActiveMQ默认就支持这种方式,只要在发消息时设 ...

  9. centos7配置iscsi

    什么是ISCSI iscsi--internet small computer system interface互联小型计算机系统接口,将数据包封装在TCP/IP协议中传输,使用普通网线和网络设备即可 ...

  10. JS:Math 对象方法

    Math 对象方法方法     描述Math.ceil(x)     对数进行上舍入.(向上取整:大于等于x的最小整数)Math.floor(x)     对数进行下舍入.(小于等于x的最大整数)Ma ...