第二章(提炼) 序列构成的数组(一)

一. 内置序列类型

        Python标准库用C实现了丰富的序列类型:

  • 容器序列:list、tuple和collections.deque这些序列能存放不同类型的数据;
  • 扁平序列:str、bytes、bytearray、memoryview和array.array,这类序列只能容纳一种类型;

        容器序列存放的是它们所包含的任意类型对象的引用,而扁平序列存放的是值而不是引用。换句话说,扁平序列是一段连续的内存空间。由此可见扁平序列其实更加紧凑,但是它里面只能存放诸如字符、字节和数值这种基础类型。

        序列类型还能按照能否被修改来分类:

  • 可变序列:list、bytearray、array.array、collections.deque和memoryview;
  • 不可变序列:tuple、str、bytes

        下图展示了可变序列(MultableSequence)和不可变序列(Sequence)的差异(注:python内置的序列类型并不是直接从Sequence和MultableSequence这两个抽象基类(ABC)集成而来的):

最基础也是最重要的序列类型该是list了,list是一个可变的容器序列,下面我们开始学习列表推导和生成器表达式。

二. 列表推导和生成器表达式

         列表推导是构建list的快捷方式,而生成器表达式则可以用来创建其它任何类型的序列。

2.1 列表推导

演示1  把一个字符串变成Unicode码位的列表

使用列表推导,上述代码将变得十分简洁:

        通常,我们只用列表推导来创建新的列表,并且尽量保持简洁。如果列表推导超过了2行,可以考虑是不是用for循环代替。注:python会忽略代码里的[]、{}和()中的换行,因此如果代码里有多行的列表、列表推导、生成器表达式、字典这一类的,可以省略掉换行符\。

演示2  python3中列表推导不再有变量泄露的问题

        列表推导、生成器表达式,以及集合推导和字典推导,在python3中都有了自己的局部作用域,就像函数似的。表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量可以被正常引用,局部变量并不会影响到它们。

2.2 列表推导同filter和map的比较

        列表推导可以帮助我们把一个一个序列或是其它可迭代类型中的元素过滤或是加工,然后再新建一个列表。Python内置的filter和map函数组合起来也能达到这一效果,但是性能上打了不小的折扣。

演示3  用列表推导和map/filter组合来创建相同的list

 2.3 笛卡尔积

        笛卡尔积是一个列表,列表里的元素是由输入的可迭代类型的元素对组成的元组,因此笛卡尔积列表的长度等于输入变量长度的乘积。

演示4  使用列表推导计算笛卡尔积

2.4 生成器表达式

        虽然可以用列表推导来初始化元组、数组或其它序列类型,但是生成器表达式是最好的选择。这是因为生成器表达式背后遵循了迭代器协议,可以逐个产出元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。前者显然能够节省内存。

演示5  用生成器表达式初始化元组和数组

注:如果生成器表达式是一个函数调用中唯一的参数,那么不需要使用额外的括号把它括起来。array的构造方法需要2个参数,因此括号是必须的;array构造方法的第一个参数指定了数组中数字的存储方式。

演示6  使用生成器表达式计算笛卡尔积

        用到生成器表达式之后,内存里不会留下一个有6个组合的列表,因为生成器表达式会在每次for循环运行时才生成一个组合。如果要计算1000个元素的列表的笛卡尔积,生成器表达式就能帮忙省略掉for循环的开销,即一个含有100万个元素的列表。

注:原书第十四章专门讲到生成器的工作原理。这里只是简单了解用生成器来初始化列表之外的序列,以及如果用它来避免额外的内存占用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值