python的序列类型及其特点_Fluent Python 笔记——序列类型及其丰富的操作
序列的分类
Python 标准库用 C 语言实现了丰富的序列类型的数据结构,如:
容器序列(能存放不同类型的数据):list、tuple、collections.deque 等
扁平序列(只容纳同一类型的数据):str、bytes、bytearray、memoryview、array.array
>>> a_list = [1, '2', True, [1, 2, 3], 4.5]
>>> a_str = 'helloworld'
容器序列存放的是对象的引用,扁平序列存放的是值。即扁平序列是一段连续的内存空间。
>>> a_list = [1, '2', True, [1, 2, 3], 4.5]
>>> embedded_list = a_list[3]
>>> embedded_list
[1, 2, 3]
>>> embedded_list.append(4)
>>> embedded_list
[1, 2, 3, 4]
>>> a_list
[1, '2', True, [1, 2, 3, 4], 4.5]
序列还可以按照是否可变(能够被修改)进行分类:
可变序列:list、bytearray、array.array、collections.deque、memoryview
不可变序列:tuple、str、bytes
>>> a_list = [1, 2, 3]
>>> a_list[0] = 2
>>> a_list
[2, 2, 3]
>>> a_tuple = (1, 2, 3)
>>> a_tuple[0] = 2
Traceback (most recent call last):
File "", line 1, in
TypeError: 'tuple' object does not support item assignment
列表推导
for 循环:
>>> symbols = '!@#$%'
>>> codes = []
>>> for symbol in symbols:
... codes.append(ord(symbol))
...
>>> codes
[33, 64, 35, 36, 37]
列表推导:
>>> symbols = '!@#$%'
>>> codes = [ord(symbol) for symbol in symbols]
>>> codes
[33, 64, 35, 36, 37]
通常的原则是,只用列表推导创建新的列表,并尽量保持简短。
列表推导(包括集合推导、字典推导)、生成器表达式在 Python3 中有自己的局部作用域。
>>> x = 'ABC'
>>> dummy = [ord(x) for x in x]
>>> x
'ABC'
>>> dummy
[65, 66, 67]
列表推导与 filter/map 的比较:
>>> symbols = '$¢£¥€¤'
>>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
>>> beyond_ascii
[162, 163, 165, 8364, 164]
>>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
>>> beyond_ascii
[162, 163, 165, 8364, 164]
作为记录的元组
元组其实是一种数据记录(Record),其中的每个元素都对应记录中一个字段的数据,字段在元组中的位置则可以用来区分其含义。
>>> lax_coordinates = (33.9425, -118.408056)
>>> city, year, pop, area = ('Tokyo', 2003, 32450, 8014)
>>> traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]
>>> for country, _ in traveler_ids:
... print(country)
...
USA
BRA
ESP
元组拆包
元组拆包可以应用到任何可迭代对象上,唯一的要求即可迭代对象中的元素数量与接收这些元素的空档数一致(除非用 * 忽略多余的元素)。
元组拆包(平行赋值):
>>> lax_coordinates = (33.9425, -118.408056)
>>> latitude, longitude = lax_coordinates
>>> latitude
33.9425
>>> longitude
-118.408056
不使用中间变量交换两个变量的值:
>>> a = 1
>>> b = 2
>>> a, b = b, a
>>> a
2
>>> b
1
使用 * 运算符把一个可迭代对象拆开作为函数的参数:
>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
元组拆包可以方便一个函数以元组的方式返回多个值,调用函数的代码就可以轻松地(有选择地)接受这些值。
>>> import os
>>> _, filename = os.path.split('/home/luciano/.ssh/idrsa.pub')
>>> filename
'idrsa.pub'
用 * 处理多余的元素:
>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])
>>> a, b, *rest = range(2)
>>> a, b, rest
(0, 1, [])
>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
具名元组
collections.namedtuple 可以用来创建一个带字段名的元组和一个有名字的类,便于对程序进行调试。其类实例消耗的内存与元组是一样的,跟普通的对象实例相比更小一些(不用 __dict__ 存放实例的属性)。
>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
创建具名元组需要传入两个参数,第一个是类名,第二个是类的各个字段的名称。后者可以是多个字符串组成的可迭代对象或由空格分隔开的字段名组成的字符串。
可以通过字段名或位置获取某个字段的信息。
具名元组的 _fields 属性包含由这个类中所有字段名称组成的元组;_asdict() 方法可以把具名元组以 collections.OrderedDict 的形式返回。
切片
关于切片和区间忽略最后一个元素
在切片和区间操作里不包含最后一个元素是 Python 的风格,同时也符合 C 和其他以 0 为起始下标的语言的习惯。
部分原因如下:
当只有最后一个位置信息时,可以快速看出区间里包含多少个元素:range(3) 和 my_list[:3] 都返回 3 个元素
起止位置都可见时,可以快速算出区间的长度(stop - start),如切片 my_list[3:6] 即包含 6 - 3 = 3 个元素
可以利用任意一个下标把序列分割成不重叠的两部分(my_list[:x] 和 my_list[x:])
step
可以用 s[a:b:c] 的形式对 s 在 a 和 b 之间以 c 为间隔取值。c 值还可以为负,表示反向取值。
>>> s = 'bicycle'
>>> s[::3]
'bye'
>>> s[::-1]
'elcycib'
>>> s[::-2]
'eccb'
对 seq[start:stop:step] 求值时,Python 会调用 seq.__getitem__(slice(start, stop, step))。
对切片赋值
如果把切片放在赋值语句左边,或把它作为 del 操作的对象,则可以对切片所属的序列进行拼接、切除或就地修改等操作。
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[2:5] = [20, 30]
>>> l
[0, 1, 20, 30, 5, 6, 7, 8, 9]
>>> del l[5:7]
>>> l
[0, 1, 20, 30, 5, 8, 9]
>>> l[3::2] = [11, 22]
>>> l
[0, 1, 20, 11, 5, 22, 9]
>>> l[2:5] = [100]
>>> l
[0, 1, 100, 22, 9]
需要注意的是,在对切片进行赋值操作时,赋值语句的右侧必须是个可迭代对象。
对序列使用 + 和 *
Python 程序员一般默认序列都会支持 + 和 * 的拼接操作。在拼接过程中,两个被操作的序列不会发生任何改动,Python 会创建一个新的包含拼接结果的序列。
>>> l = [1, 2, 3]
>>> l * 5
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 5 * 'abcd'
'abcdabcdabcdabcdabcd'
如果 a * n 语句中序列 a 里的元素是对其他可变对象的引用的话,这个式子的结果可能会出乎意料。比如用 my_list = [[]] * 3 来初始化一个有列表组成的列表,实际上得到的列表里包含的三个元素是三个引用,且这三个引用都指向同一列表。
>>> weird_board = [['-'] * 3] * 3
>>> weird_board
[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
>>> weird_board[1][2] = 'O'
>>> weird_board
[['-', '-', 'O'], ['-', '-', 'O'], ['-', '-', 'O']]
其错误的本质等同于如下代码:
>>> row = ['-'] * 3
>>> board = []
>>> for i in range(3):
... board.append(row)
...
>>> board[1][2] = 'O'
>>> board
[['-', '-', 'O'], ['-', '-', 'O'], ['-', '-', 'O']]
即追加同一个行对象(row)到游戏币(board)
正确的做法代码如下:
>>> board = [['-'] * 3 for i in range(3)]
>>> board
[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
>>> board[1][2] = 'O'
>>> board
[['-', '-', '-'], ['-', '-', 'O'], ['-', '-', '-']]
等同于如下代码:
>>> board = []
>>> for i in range(3):
... row = ['-'] * 3
... board.append(row)
...
>>> board
[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]
>>> board[1][2] = 'O'
>>> board
[['-', '-', '-'], ['-', '-', 'O'], ['-', '-', '-']]
即每次迭代中都新建了一个列表,作为新的一行(row)追加到游戏板子(board)
序列的增量赋值
增量赋值运算符 += 和 *= 的行为取决于第一个操作对象。
+= 调用的特殊方法是 __iadd__(自增)。如果某个类没有实现该方法,Python 会退一步调用 __add__。
如 a += b 就会调用 a 中实现的 __iadd__ 方法,同时对于可变序列(如 list、bytearray、array.array),该方法的行为类似于 a.extend(b),在 a 上就地改动。
如 a 没有实现 __iadd__,a += b 的效果就类似于 a = a + b,计算 a + b 得到一个新的对象,再把这个对象赋值给 a。
*= 对应的是 __imul__。
>>> l = [1, 2, 3]
>>> id(l)
2888988078920
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
2888988078920
>>> t = (1, 2, 3)
>>> id(t)
2888988799688
>>> t *= 2
>>> id(t)
2888988107592
作为可变对象的列表运用增量乘法后,ID 没变;而作为不可变对象的元组运用增量乘法后,新的元组被创建。
因此对于不可变序列做重复拼接操作效率会很低,每次都会有一个新对象。但字符串除外,由于对字符串做 += 等操作太普遍,CPython 专门做了优化。在为字符串初始化内存时,程序会预留额外的可扩展空间。
list.sort 与 sorted
list.sort 方法会就地排序列表,即在原列表的基础上完成排序,不会再另外复制一份。也因此其返回值为 None。
内置的 sorted 函数则会新建一个列表作为返回值。它可以接收任何形式的可迭代对象(包含不可变序列和生成器),最后返回的始终是排序好的列表。
>>> fruits = ['grape', 'raspberry', 'apple', 'banana']
>>> sorted(fruits)
['apple', 'banana', 'grape', 'raspberry']
>>> fruits
['grape', 'raspberry', 'apple', 'banana']
>>> sorted(fruits, key=len)
['grape', 'apple', 'banana', 'raspberry']
>>> fruits
['grape', 'raspberry', 'apple', 'banana']
>>> fruits.sort()
>>> fruits
['apple', 'banana', 'grape', 'raspberry']
参考资料
python的序列类型及其特点_Fluent Python 笔记——序列类型及其丰富的操作相关推荐
- python同时输出名字和时间_Python学习笔记 (2) :字符串输出、操作、格式化和日期、时间格式化...
一.字符串输出及运算 1.常用输出格式及方法 1 print('1234567890')#单引号 2 print("1234567890")#双引号 3 print("& ...
- python序列类型举例说明_Python基础__Python序列基本类型及其操作(1)
本节考虑的Python的一个中要的内置对象序列, 所谓的序列即一个有序对象的集合.这里的对象可以是数字.字符串等.根据功能的不同将序列分为字符串.列表.元组,本文将以下这几种对象做一些介绍. 一. 字 ...
- python定义一个数列_第二章 数列和序列类型
一.Python变量 1.定义 学习数据类型之前,先来学习以下什么是python变量? 直白意思就是给数据起个名字.变量是计算机内存中的一块区域,变量可以存储规定范围内的值,而且值可以改变. 2.数据 ...
- Python回顾与整理5:映像和集合类型
0.说明 依然是按照前面介绍的几种序列类型的思路来总结字映像类型和集合类型,即先做一个介绍,再讨论可用操作符.工厂函数.内建函数和方法. 1.映射类型:字典 映射类型被称做哈希表,而Python中的字 ...
- python索引右往左_[Python笔记]序列(一)索引、分片
Python包含6种内建序列:列表.元组.字符串.Unicode字符串.buffer对象.xrange对象. 这些序列支持通用的操作: 索引 索引是从0开始计数:当索引值为负数时,表示从最后一个元素( ...
- python中异常的处理及断言,包括异常类型、异常捕获、主动跑出异常和断言
一.异常类型介绍 什么是异常?异常即是一个事件,该事件会在程序执行过程中发生,会影响程序的正常执行,一般情况下,在python无法正常处理程序时就会发生一个异常.异常是python对象,表示一个错误. ...
- python集合类型_Python 的集合(set)类型
本文简单介绍了Python语言里set类型自带的方法,set类型表示元素和集合的从属关系(membership),和列表等序列相比,最大的特点是无序.可以跟数学里的集合概念完全对应起来. 目录 概念 ...
- python内置函数用来返回数值型序列中所有元素之和_语句x = 3==3, 5执行结束后,变量x的值为_学小易找答案...
[判断题]不可以在同一台计算机上安装多个Python版本. [填空题]表达式[1, 2, 3]*3的执行结果为 [填空题]使用切片操作在列表对象x的开始处增加一个元素3的代码为 [填空题]Python ...
- python内置对象是什么_Python的内置对象类型——元组、文件,python
元组 元组是序列,但它具有不可变性,和字符串类似,它支持任意类型,任意嵌套以及常见的序列操作. 特点:任意对象的有序集合:通过偏移获取:属于不可变序列类型:固定长度,异构,任意嵌套,对象引用的数组. ...
最新文章
- 信息安全系统设计基础第3周学习总结
- Silverlight实例教程 - Out of Browser的自定义应用
- delphi 窗体透明详解TransparentColorValue,窗体透明控件不透明
- 【小白学习PyTorch教程】五、在 PyTorch 中使用 Datasets 和 DataLoader 自定义数据
- Android(2)-----Fragment //(第七周后的知识)
- Elasticsearch head插件
- Servlet 编写过滤器
- 10.docker build
- 如何通过XRD计算晶格常数
- 第三代CAN-XL通信技术CiA 610有什么特点
- 踩坑!穿山甲广告Android SDK接入
- 图文解说S参数(进阶篇)
- 小酷智慧地图3D导览v1.0.87打卡定位 地图打卡
- 关于在word中插入页码以及目录的操作
- 第11章组件装饰和视觉效果-DecoratedBox装饰盒子-背景图效果
- 加油卡html界面6,油卡核销.html
- 苹果Ipad锁屏密码忘记之后,如何不会变成砖
- java中的1L是啥意思?
- 全国计算机等级考试二级C语言程序设计五合一 新版上机题库pdf
- 前端电商项目实战,如何从 0 开始创造一个【考拉海购官网】?( 共6节教程 )
热门文章
- Chrome浏览器报错:Origin null is not allowed by Access-Control-Allow-Origin.
- C++基础知识简答题
- 2022年考研结束了
- 华为这个事,是不是刷KPI?
- [教程]win10 ,ubuntu双系统安装避坑指南
- 10.5 0819吉米牛逼
- java loadlibrary_java – System.loadLibrary不起作用.链中的第二个lib的UnsatisfiedLinkError...
- date js 半年_moment.js 搜索栏获取最近一周,一个月,三个月,半年,一年时间
- semihost/ITM机制浅析以及使用JLINK通过ITM调试stm32单片机
- Datawhale组队-Pandas(下)文本数据(打卡)