序列

序列是指一组数据,按存放类型分为容器序列与扁平序列,按能否被修改分为不可变序列与可变序列。

容器序列与扁平序列

容器序列存放的是对象的引用,包括listtuplecollections.deque

扁平序列存放的是对象的值,包括strbytesbytearraymemoryviewarray.array

扁平序列的值是字符、字节和数值这种基础类型。

不可变序列与可变序列

不可变序列,包括tuplestrbytes

可变序列,包括listbytearrayarray.arraycollection.dequememoryview

下图左边是父类,右边是子类,可以看出可变序列是从不可变序列继承来的,扩展了可变方法:

列表推导

Python语言魅力在于简洁,这能从最常见的创建列表体现出来,比如我们想把字符串"abc"转换成新列表["a", "b", "c"],常规写法:

symbols = "abc"
codes = []
for symbol in symbols:
codes.append(symbol)
print(codes) # ["a", "b", "c"]

用到了for循环和列表append方法。实际上可以不用append方法,直接:

symbols = "abc"
codes = [symbol for symbol in symbols]

这叫做列表推导,是更加Pythonic的写法。

无论是编写效率还是可阅读性,列表推导都更胜一筹,可以说是构建列表的快捷方式。但是不能滥用,通用原则是,如果列表推导的代码超过了两行,就要考虑用append了。这不是规定,完全可以凭借自我喜好来选择。

笛卡尔积是指多个序列中元素所有组合,我们用列表推导来实现笛卡尔积:

colors = ["black", "white"]
sizes = ["S", "M", "L"]
tshirts = [(color, size) for color in colors for size in sizes]

一行代码搞定!Life is short,use Python,list comprehension is wonderful,amazing。

注意这行代码有两个for循环,等价于:

for color in colors:
for size in sizes:

运行结果是:

[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]

如果换一下顺序:

[(color, size) for color in colors for size in sizes]

等价于:

for size in sizes:
for color in colors:

运行结果是不同的,观察第2个元素:

[('black', 'S'), ('white', 'S'), ('black', 'M'), ('white', 'M'), ('black', 'L'), ('white', 'L')]

生成器表达式

一般接触到生成器时,都要讲yield关键字,看似有点复杂,然而却很简单,生成器就像列表推导一样,只不过是用来生成其他类型序列的,比如元组:

symbols = "abc"
codes = (symbol for symbol in symbols)

它的语法非常简单,把列表推导的中括号[]换成小括号(),就可以了。

语法相似,本质上却有很大区别,我们试着用生成器表达式来实现笛卡尔积,看看会有什么变化:

colors = ["black", "white"]
sizes = ["S", "M", "L"]
tshirts = ((color, size) for color in colors for size in sizes)

运行结果是:

<generator object <genexpr> at 0x000001FD57D2DB30>

generator object,结果是一个生成器对象。因为生成器表达式在每次迭代时才会逐个产出元素,所以这里的结果并不是已经创建好的元组。列表推导才会一次性产生新列表所有元素。

通过迭代把生成器表达式结果输出:

for tshirt in tshirts:
print(tshirt)
('black', 'S')
('white', 'S')
('black', 'M')
('white', 'M')
('black', 'L')
('white', 'L')

生成器表达式可以提升程序性能,比如要计算两个各有1000个元素的列表的笛卡尔积,生成器表达式可以帮忙省掉运行for循环的开销,即一个包含100万个元素的列表。

yield作用和return差不多,后面会讲到。

Tips

本小节内容是我看《流畅的Python》第一遍时记录的知识点:

  1. Python标准库用C实现了丰富的序列类型。
  2. 列表推导,就是指a = [x for x in something]这种写法。
  3. 生成器表达式用于生成列表外的其他类型的序列,它跟列表推导的区别仅仅在于方括号换成圆括号,如b = tuple(x for x in something)
  4. array.array('I', x for x in something) ,array构造方法的第一个参数指定了数组中数字的存储方式。
  5. for tshirt in [c, s for c in colors for s in sizes],列表推导会一次性生成这个列表,存储在内存中,占用资源。for tshirt in ('%s %s' for c in colors for s in sizes),生成器表达式只在循环时逐个产出元素,避免额外的内存占用,省掉了运行for循环的开销。

小结

本文首先介绍了序列的概念,然后演示了Python常规骚操作——列表推导,最后引出了生成器表达式这个看似复杂实则简单的语法。列表是可变的,它有个不可变的孪生兄弟,元组。

参考资料:

《流畅的Python》

Python骚操作从列表推导和生成器表达式开始的更多相关文章

  1. Python基础:08列表解析与生成器表达式

    一:列表解析 列表解析(List comprehensions)来自函数式编程语言Haskell .它可以用来动态地创建列表.它在 Python 2.0 中被加入. 列表解析的语法:     [exp ...

  2. Python学习笔记2:构造序列:列表推导和生成器表达式

    欢迎访问个人网站:www.comingnext.cn 1. 关于Python内置序列类型 a. 按能否存放不同类型的数据区分 容器序列: list.tuple 和collections.deque这些 ...

  3. python 全栈开发,Day14(列表推导式,生成器表达式,内置函数)

    一.列表生成式 生成1-100的列表 li = [] for i in range(1,101): li.append(i) print(li) 执行输出: [1,2,3...] 生成python1期 ...

  4. Python入门之三元表达式\列表推导式\生成器表达式\递归匿名函数\内置函数

    本章目录: 一.三元表达式.列表推导式.生成器表达式 二.递归调用和二分法 三.匿名函数 四.内置函数 ================================================ ...

  5. python之三元表达式、列表推导、生成器表达式、递归、匿名函数、内置函数

    目录 一 三元表达式 二 列表推到 三 生成器表达式 四 递归 五 匿名函数 六 内置函数 一.三元表达式 def max(x,y): return x if x>y else y print( ...

  6. python之生成器(~函数,列表推导式,生成器表达式)

    一.生成器 概念:生成器的是实质就是迭代器 1.生成器的贴点和迭代器一样,取值方式也和迭代器一样. 2.生成器一般由生成器函数或者声称其表达式来创建,生成器其实就是手写的迭代器. 3.在python中 ...

  7. python基础-三元表达式/列表推导式/生成器表达式

    1.三元表达式:如果成立返回if前的内容,如果不成立返回else的内容 name=input('姓名>>: ') res='SB' if name == 'alex' else 'NB' ...

  8. 2018.11.06 生成器函数进阶&列表推导式&生成器表达式

    1.生成器函数进阶 2.列表推导式 3.生成器表达式

  9. python(19)- 列表生成式和生成器表达式练习Ⅰ

    列表表达式 程序一: 常规写法: egg_list=[] for i in range(100): egg_list.append('egg%s' %i) print(egg_list) 列表表达式写 ...

随机推荐

  1. 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!

    前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...

  2. LOG_PATH_IS_UNDEFINED

    问题: SpringBoot + LogBack 写日志,除了正常的日志之外,程序跑起来后会在项目根目录多生成一个 LOG_PATH_IS_UNDEFINED 的文件夹,我的配置是以下: applic ...

  3. JVM内存模型总结,有各版本JDK对比、有元空间OOM监控案例、有Java版虚拟机,综合实践学习!

    作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...

  4. JS内存

    内存是用来存什么的 通俗的来说呢,就是用来存 var let function const 声明的变量. 内存的大小 与操作系统有关,64位1.4G 32位0.7G. 为啥内存大小要这么设计,为啥不是 ...

  5. 【函数分享】每日PHP函数分享(2021-1-11)

    str_shuffle() 随机打乱一个字符串. string str_shuffle ( string $str ) 参数描述 str     输入字符串.返回值:返回打乱后的字符串.实例: < ...

  6. 初识sa-token,一行代码搞定登录授权!

    前言 在java的世界里,有很多优秀的权限认证框架,如Apache Shiro.Spring Security 等等.这些框架背景强大,历史悠久,其生态也比较齐全. 但同时这些框架也并非十分完美,在前 ...

  7. 天梯赛练习 L3-007 天梯地图 (30分) Dijkstra

    题目分析: 本题的题意比较清晰,就是有一个起点和一个终点,给出m条路径,可能是单向的可能是双向的,同时一条路有两个权重,分别是通过这条路需要的时间和这条路的路径长度,题目需要求出两条路径,一条是在最快 ...

  8. 【ORA】ORA-27101快速处理方法

    今天朋友的数据库出了问题,报错如下: 这个问题主要是是spfile和pfile文件不一致导致的, 生成一个pfile,完了用pfile启动数据库即可 SQL> create pfile '/ho ...

  9. logging模块简单用法

    logging模块功能比较多,但一般情况下使用其简单功能就已经足够了. 最简单的用法如下: import logging logging.baiscConfig(level=logging.DEBUG ...

  10. undefined和null区别

    undefined类型只有一个值就是undefined,没有必要显式地声明一个变量为undefined. null类型其实就是一个对象的空指针,所以用typeof null 才会显示为object. ...