第二章 序列构成的数组

2.1内置序列类型概览

Python标准库用C实现了丰富的序列模型,列举如下:

1>    序列模型 list、tuple和collection.deque这些序列能存放不同类型的序列

2>    扁平模型 str、bytes、bytearray、memoryview和array.array这类序列只能存放一种类型

容器序列存放的是它们所包含任意类型对象的引用,而扁平序列存放的是值而不是引用。

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

1>    可变序列    list  bytearray  array.array  collections.deque  memoryview

2>    不可变序列  tuple  str  bytes

下图显示了可变序列(MutableSequence)和不可变序列(Sequence)的差异,同时也能看出前者从后者那里继承了一些方法。了解基类可以帮助我们总结出那些完整的序列类型包含了哪些功能。

2.2 列表推导和生成器表达式

       列表推导是构建列表的快捷方式,而生成器表达式则可以创建其他任何类型的序列。( 列表推导(list comprehension)简称为listcomps;生成器表达式(generator expression)则称为genexps )

2.2.1 列表推导和可读性

  通常原则:只用列表推导创建新的列表,并且尽量保持简短。如果列表推导的代码超过了两行就要考虑是不是得用for循环重写。Python会忽略代码里[]、{}、() 中的换行,故在多行的列表、列表推导、生成器表达式、字典这一类的,可以省略不太好看的续行符 \ 。

 1 symbols = ‘hseksdth‘
 2 codes = []
 3 """
 4 ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。
 5 """
 6 for symbol in symbols:
 7     codes.append(ord(symbol))
 8 print(codes) #[104, 115, 101, 107, 115, 100, 116, 104]
 9
10 symbols = ‘dgshsgjh‘
11 codes = [ord(symbol) for symbol in symbols]
12 print(codes) # [100, 103, 115, 104, 115, 103, 106, 104]
13
14 x = ‘ABC‘
15 dummy = [ord(x) for x in x]
16 print(dummy) # [65, 66, 67]

2.2.2 列表推导同filtermap的比较

Filter和map合起来做的事情,列表推导也可以做,而且还不需要借助难以理解和阅读的lambda表达式:

如下示例:

1 symbols = ‘$%#*&‘
2 dummy = [ord(x) for x in symbols]
3 beyound_ascii = [ord(s) for s in symbols if ord(s) > 36]
4 beyound_asciii = list(filter(lambda c:c>36,map(ord,symbols)))
5 print(beyound_ascii)    # [37, 42, 38]
6 print(dummy)            #  [36, 37, 35, 42, 38]
7 print(beyound_asciii)   #  [37, 42, 38]

2.2.3 笛卡尔积

用列表推导可以生成两个或以上的可迭代类型的笛卡尔积,笛卡尔积是一个列表,列表里的元素是由输入的可迭代类型的元素对构成的元组,因此笛卡尔积的列表长度等于输入变量的乘积。

如下示例:

1 colors = [‘black‘,‘white‘]
2 sizes = [‘S‘,‘M‘,‘L‘]
3 tshirts = [(color,size) for color in colors for size in sizes]
4 print(tshirts)
5 输出:[(‘black‘, ‘S‘), (‘black‘, ‘M‘), (‘black‘, ‘L‘), (‘white‘, ‘S‘), (‘white‘, ‘M‘), (‘white‘, ‘L‘)]
6
7 tshirts2 = [(color,size) for size in  sizes for color in colors]
8 print(tshirts2)
9 输出:[(‘black‘, ‘S‘), (‘white‘, ‘S‘), (‘black‘, ‘M‘), (‘white‘, ‘M‘), (‘black‘, ‘L‘), (‘white‘, ‘L‘)]

列表推导的作用只有一个:生成列表。如果想生成其他类型的序列,生成器表达式就派上了用场。

2.2.3 生成器表达式

虽然也可以用列表推导来初始化元组、数组或其他序列类型,但是生成器表达式是更好的选择。这是因为生成器表达式背后遵循了迭代器协议,可以逐个的产生元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。生成器表达式的语法跟列表推到差不多,只不过把方括号换成圆括号。

如下示例:

 1 symbols = ‘*&%$#@‘
 2 print(tuple(ord(symbol)for symbol in symbols))
 3 输出:(42, 38, 37, 36, 35, 64)
 4
 5 print(array.array(‘I‘,(ord(symbol)for symbol in symbols)))
 6 输出:array(‘I‘, [42, 38, 37, 36, 35, 64])
 7
 8 colors = [‘R‘,‘G‘,‘B‘]
 9 sizes = [‘S‘,‘M‘,‘L‘]
10 for tshirt in (‘%s %s‘%(c,s)for c in colors for s in sizes):
11      print(tshirt)
12 输出:
13 R S
14 R M
15 R L
16 G S
17 G M
18 G L
19 B S
20 B M
21 B L

【注】1、 如果生成器表达式是一个函数调用过程中的唯一参数,那么不需要额外再用括号把它括起来。

2、array的构造方法需要两个参数,因此括号是必须的。array构造方法的第一个参数指定了数组中数字的存储方式。(后面会讲到生成器的工作原理,这里一笔带过)

2.3 元组不仅仅是不可变的列表

2.3.1 元组和记录

元组其实是对数据的记录:元组中每个元素都存放了记录中一个字段的数据,外加这个字段的位置。正是这个位置信息给数据赋予了意义。如果只把元组理解为不可变的列表,其它的信息---它所含有的元素的总数和它们的位置—似乎变得可有可无。但如果把元组当做一些字段的集合,那么数量和位置信息就变得非常重要了。

如下示例:

 1 lax_coordinates = (55.236,864.1259)
 2 city,year,pop,chg,area = (‘Tokyo‘,2019,1547,0.152,8746)
 3 traveler_ids = [(‘USA‘,‘1857642‘),(‘BRA‘,‘845696‘),(‘BHY‘,‘45963‘)]
 4 for passport in sorted(traveler_ids):
 5      print(‘%s/%s‘%passport)
 6 输出:
 7 BHY/45963
 8 BRA/845696
 9 USA/1857642
10
11 for country,_ in traveler_ids:
12      print(country)
13 输出:
14 USA
15 BRA
16 BHY

【注】1、在迭代过程中,passport变量被绑定到每个元组上。

2、%格式运算符能被匹配到对应元组元素上。

3、for 循环可以分别提取元组里的元素,也叫作拆包(unpacking)。因为元组中第二个元素对我们没什么用,所以将它赋给 ‘_’ 占位符。

2.3.2 元组拆包

  元组拆包可以应用到任何可迭代的对象上,唯一的硬性要求是:被可迭代对象中元素数量必须跟接受这些元素的元组空挡数一致,除非我们用 * 号来表示忽略多余的元素。

最好辨认的元组拆包形式就是平行赋值,也就是说把一个可迭代对象里的元素,一并赋值到由对应的变量组成的元组中。

1 lax_corrdinates = (33.1258,-56.4895)
2 latitude,longtitude = lax_corrdinates
3 print(latitude)
4 print(longtitude)
5 输出:33.1258
6      -56.4895

还可以用 * 运算把一个可迭代运算拆开作为函数的参数。

1 b,a = a,b           # 这种写法可以在不使用中间变量的情况下交换 a,b 的值
2 print(divmod(20,8)) # divmod 把除数和余数运算结合起来,返回包含商和余数的元组
3 t = (20,8)
4 print(divmod(*t))
5 quotient,remainder = divmod(*t)
6 print(quotient,remainder)
7 输出:(2, 4)
8      (2, 4)
9       2 4

下面一个示例,元组拆包的用法则是让一个函数可以用元组的形式返回多个值,然后调用函数的代码就能轻松地接受这些返回值。比如os.path.split() 函数就会返回以路径和最后一个文件名组成的元组(path,last_part):

1 filepath,filename = os.path.split(‘/home/download/myfile/study.docx‘)
2 print(‘filepath = ‘,filepath)
3 输出:filepath =  /home/download/myfile
4 print(‘filename = ‘,filename)
5 输出:filename =  study.docx
6 print(‘full path = ‘+filepath+‘/‘+filename)
7 输出:full path = /home/download/myfile/study.docx

在进行拆包的时候,我们不总是对元组里所有的数据都感兴趣,_占位符能帮助处理这种情况,如上所示。

除此之外,元组拆包中使用 * 也可以帮助我们将注意力集中在部分元素上面,如下示例用 * 来处理剩下的元素。在python中,函数用*args来获取不确定数量的参数算是一种经典写法。

1 a,b,*rest = range(10)
2 print(a,b,rest)
3 输出:0 1 [2, 3, 4, 5, 6, 7, 8, 9]
4 a1,b1,*rest1 = range(2)
5 print(a1,b1,rest1)
6 输出:0 1 []

在平行赋值中,*前缀只能用在一个变量名前面,但是这个变量可以出现在赋值表达式的任意位置

1 a,*body,c,d = range(5)
2 print(a,body,c,d)
3 输出:0 [1, 2] 3 4
4 *head,b,c,d = range(5)
5 print(head,b,c,d)
6 输出:[0, 1] 2 3 4

2.3.3 嵌套元组拆包

接受表达式的元组可以是嵌套的,例如 (a,b,(c,d)) 。只要这个接受元组的嵌套结构符合表达式本身的嵌套结构,python 就可以做出正确的对应。

如下示例:

 1 metro_areas = [
 2         (‘Tokyo‘,‘JP‘,50.3654,(12.458,63.45896)),
 3         (‘ShangHai‘, ‘JSH‘, 62.3789, (85.34596, 111.25)),
 4         (‘GuangHou‘, ‘GZ‘, 50.3654, (23.214, 98.125)),
 5         (‘Zhengzhou‘, ‘ZH‘, 50.3654, (658.145, 985.12)),
 6         (‘LaSha‘, ‘LS‘, 50.3654, (528.461, 753.159)),
 7     ]
 8
 9 print(‘{:15}|{:^9}|{:^9}‘.format(‘‘,‘lat.‘,‘long.‘))
10 fmt = ‘{:15}|{:9.4f}|{:9.4f}‘
11 for name,cc,pop,(latitude,longitude) in metro_areas:
12        print(fmt.format(name,latitude,longitude))
13 输出:
14                     |  lat.    |  long.
15 Tokyo               |  12.4580 |  63.4590
16 ShangHai            |  85.3460 | 111.2500
17 GuangHou            |  23.2140 |  98.1250
18 Zhengzhou           | 658.1450 | 985.1200
19 LaSha               | 528.4610 | 753.1590

【注】python3之前,元组可以作为形参放在函数声明中,例如:def fn(a,(b,c),d),然而Python3 不在支持这种形式。

2.3.4 具名元组

collections.namedtuple是一个工厂函数,它用来构建一个带字段名的元组和一个有名字的类。

用namedtuple构建的类的实例所消耗的内存跟元组是一样的,因为字段名都被存在对应的类里面。这个实例跟普通的对象实例比起来也要小一些,因为Python不会用__dict__来存放这些实例的属性。

 1 City = namedtuple(‘City‘,‘name country population coordinates‘)
 2 tokyo = City(‘Tokyo‘,‘JP‘,36.4598,(86.56987,84.1259))
 3 print(‘tokyo = ‘,tokyo)
 4 print(‘tokyo.population = ‘,tokyo.population)
 5 print(‘tokyo.coordinates = ‘,tokyo.coordinates)
 6 print(‘City._fields = ‘,City._fields)
 7 输出:
 8 tokyo =  City(name=‘Tokyo‘, country=‘JP‘, population=36.4598, coordinates=(86.56987, 84.1259))
 9 tokyo.population =  36.4598
10 tokyo.coordinates =  (86.56987, 84.1259)
11 City._fields =  (‘name‘, ‘country‘, ‘population‘, ‘coordinates‘)

由上可知:

1、创建一个具名元组需要两个参数:类名/类的各个字段名。后者可以是由数个字符串组成的可迭代的对象,或者是由空格分隔开的字段名组成的字符串。

2、存放在对应字段里的数据要以一串参数的形式传入到构造函数中(注意:元组的构造函数只接受单一的可迭代对象)

3、可通过字段名或者位置来获取一个字段的信息

具名元组也有自己的属性,列举几个最有用的:_fields类属性、类方法_make(iterable)和实例方法_asdict()

1 Latlong = namedtuple(‘Latlong‘,‘lat long‘)
2 delhi_data = (‘Delhi NCR‘,‘IN‘,21.459,Latlong(25.465,87.1276))
3 delhi = City._make(delhi_data)
4 print(‘delhi._asdict() = ‘,delhi._asdict())
5 输出:delhi._asdict() =  OrderedDict([(‘name‘, ‘Delhi NCR‘), (‘country‘, ‘IN‘), (‘population‘, 21.459), (‘coordinates‘, Latlong(lat=25.465, long=87.1276))])

由上可知:

1、_fields属性是一个包含这个类所有字段名称的元组

2、用_make()通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟City(*delhi_data) 是一样的

3、_asdict() 把具名元组以collections.OrderedDict的形式返回,我们可以利用它把元组里的信息友好的呈现出来

原文地址:https://www.cnblogs.com/IamJiangXiaoKun/p/10217443.html

时间: 2024-10-12 20:34:26

第二章 序列构成的数组的相关文章

流畅的python第二章序列构成的数组学习记录

python内置序列类型概览 列表推导和生成器表达式 列表推导是构建列表的快捷方式,而生成器表达式可以用来创建其他任何类型的序列 列表推导的示例 >>>test = [i*2 for i in range(3)] >>>test [0,2,4] 使用列表推导通常的原则是,只能列表推导来创建新的列表,并且尽量保持简短. python2中列表推导可能有变量泄露问题,而python3解决了变量泄露问题 列表推导和map/filter的对比 生成器表达式 虽然也可以用列表推导来

第二章 数学运算、数组、文字处理

第二章 数学运算.数组.文字处理.md 知识要点 数学运算 数组的使用 seq tr sort uniq cut 等命令 数学运算 整数运算 常用的运算符 加法运算符:+ 减法运算符:- 乘法运算符:/ 求模运算符:% 求幂运算符:** 常用整数运算 第一种 declare -i a=10*20; echo $a 少用 第二种 a=$(expr 10'*'20); echo $a 少用 第三种 a=$[10*2]; echo $a []中的变量无需加$ echo $[RANDOM%10] 求0-

python基础教程(第2版)第二章读后总结;

python第二章 序列是一种数据结构:典型的序列包括:列表,字符串,元组 数据结构是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合,这些数据元素 可以是数字或者字符,甚至可以是其他数据结构,在python中,最近本的数据结构是序列,序列中的每个元素被 分配一个序号-----即元素的位置,也成为索引,第一个索引是0,第二个则是1,以此类推. 列表和元组的主要区别: 列表可以修改,元组则不能,但他们都统称为序列; 列表的各个元素通过逗号分离,写在方括号中: 元组的各个元素通过逗号分离

Delphi知识点与技术概述【第二章 核心类库】

第三章 核心类库 Delhpi可视化编程依赖于庞大的巨型类库.Delphi 标准类库包含了数百个类以及数以千计的方法. 内容提要: *RTL包.CLX与VCL CLX用作linux中,VCL用作Windows中 VCL是一个独立的大型库(组件,控件,非可视组件,数据集合,数据感应控件,等等). 库的核心非可视化组件与类属于RTL包. Vcl结构: CLX结构: BaseCLX VisualCLX DateCLX NetCLX 库的VCL专用部分: VCL还提供了Windows专用的: Delph

Java基础知识二次学习-- 第二章 基础语法与递归补充

第二章 基础语法与递归补充   时间:2017年4月24日10:39:18 章节:02章_01节,02章_02节 视频长度:49:21 + 15:45 内容:标识符,关键字与数据类型 心得:由字母,下划线,$,数字组成,应该由字母,下划线$开头,同时应该避开java保留字符 变量是内存中的一小块区域,使用变量名来访问这块区域 执行过程中的内存管理(疑问:这里的内存和Jvm的一样吗?) code segment 存放代码 data segment 静态变量 字符串常量 stack 栈 局部变量 h

《程序员的自我修养》 第二章——编译和链接

摘自http://blog.chinaunix.net/uid-26548237-id-3839979.html <程序员的自我修养>第二章——编译和链接 2.1 被隐藏了的过程    C语句的经典,“Hello World”程序几乎是每个程序员闭着眼睛都能写出的,编译运行一气呵成,基本成了程序入门和开发环境测试的默认标准. #include <stdio.h> int main() { printf("Hello World\n"); return 0; 在L

第二章 算法基础 思考题2-1

package chap02; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Random; import org.junit.Test; /*** * 在归并排序中对小数组采用插入排序 * * @author xiaojintao * */ public class ques2_1 { /** * 归并排序算法 * * @param a * @return */ static void m

算法导论(Introduction to Algorithms )— 第二章 算法入门 — 2.1 插入排序

一.插入排序:INSERTION-SORT 1.适用范围: which is an efficient algorithm for sorting a small number of elements. 对于少量元素的排序,插入排序是一种高效的算法. 2.原理: Insertion sort works the way many people sort a hand of playing cards. We start with an empty left hand and the cards

Laxcus大数据管理系统(5)- 第二章 数据组织

第二章 数据组织 在数据的组织结构设计上,Laxcus严格遵循数据和数据描述分离的原则,这个理念与关系数据库完全一致.在此基础上,为了保证大规模数据存取和计算的需要,我们设计了大量新的数据处理技术.同时出于兼顾用户使用习惯和简化数据处理的目的,继续沿用了一些关系数据库的设计和定义,其中不乏对SQL做适量的修订.在这些变化中,核心仍然是以关系代数的理念去处理数据,以及类自然语言风格的数据描述.所以用户在使用体验上,和关系数据库相比,不会感觉到有太多的差异. 本章将介绍Laxcus数据结构的组成,并