Python 06-序列

本文详细介绍了Python中的序列类型,包括可变序列如列表和不可变序列如元组,以及序列操作如拼接、索引、切片、计数和排序。列表作为栈和队列的使用方法,以及列表推导式的概念也被阐述。此外,还讨论了range对象和二进制序列类型。重点讲解了列表的可变操作,如添加、删除、排序和方法应用。
摘要由CSDN通过智能技术生成

Python 06-序列

​ Python有三种基本序列类型:list, tuplerange 对象。 以及为处理 二进制数据文本字符串 而特别定制的附加序列类型。

序列分为两种:

  • 可变序列:list,bytearray
  • 不可变序列:tuple,range,str,bytes

1、序列的通用操作

​ 大多数序列类型,包括可变类型和不可变类型都支持下表中的操作。 collections.abc.Sequence ABC 被提供用来更容易地在自定义序列类型上正确地实现这些操作。

​ 此表按优先级升序列出了序列操作。 在表格中,st 是具有相同类型的序列,n, i, jk 是整数而 x 是任何满足 s 所规定的类型和值限制的任意对象。

innot in 操作具有与比较操作相同的优先级。 + (拼接) 和 * (重复) 操作具有与对应数值运算相同的优先级。

运算结果:注释
x in s如果 s 中的某项等于 x 则结果为 True,否则为 False(1)
x not in s如果 s 中的某项等于 x 则结果为 False,否则为 True(1)
s + tst 相拼接(6)(7)
s * nn * s相当于 s 与自身进行 n 次拼接(2)(7)
s[i]s 的第 i 项,起始为 0(3)
s[i:j]sij 的切片(3)(4)
s[i:j:k]sij 步长为 k 的切片(3)(5)
len(s)s 的长度
min(s)s 的最小项
max(s)s 的最大项
s.index(x[, i[, j]])xs 中首次出现项的索引号(索引号在 i 或其后且在 j 之前)(8)
s.count(x)xs 中出现的总次数

相同类型的序列也支持比较。 特别地,tuple 和 list 的比较是通过比较对应元素的字典顺序。 这意味着想要比较结果相等,则每个元素比较结果都必须相等,并且两个序列长度必须相同。 (完整细节请参阅语言参考的 比较运算 部分。)

注释:

  1. 虽然 innot in 操作在通常情况下仅被用于简单的成员检测,某些专门化序列 (例如 str, bytesbytearray) 也使用它们进行子序列检测:

    >>> "gg" in "eggs"
    True
    
  2. 小于 0n 值会被当作 0 来处理 (生成一个与 s 同类型的空序列)。 请注意序列 s 中的项并不会被拷贝;它们会被多次引用。 这一点经常会令 Python 编程新手感到困扰;例如:

    >>> lists = [[]] * 3
    >>> lists
    [[], [], []]
    >>> lists[0].append(3)
    >>> lists
    [[3], [3], [3]]
    

    具体的原因在于 [[]] 是一个包含了一个空列表的单元素列表,所以 [[]] * 3 结果中的三个元素都是对这一个空列表的引用。 修改 lists 中的任何一个元素实际上都是对这一个空列表的修改。 你可以用以下方式创建以不同列表为元素的列表:

    >>> lists = [[] for i in range(3)]
    >>> lists[0].append(3)
    >>> lists[1].append(5)
    >>> lists[2].append(7)
    >>> lists
    [[3], [5], [7]]
    

    进一步的解释可以在 FAQ 条目 如何创建多维列表? 中查看。

  3. 如果 ij值,则索引顺序是相对于序列 s 的末尾: 索引号会被替换为 len(s) + ilen(s) + j。 但要注意 -0 仍然为 0

  4. sij 的切片被定义为所有满足 i <= k < j 的索引号 k 的项组成的序列。 如果 ij 大于 len(s),则使用 len(s)。 如果 i 被省略或为 None,则使用 0。 如果 j 被省略或为 None,则使用 len(s)。 如果 i 大于等于 j,则切片为空。

  5. sij 步长为 k 的切片被定义为所有满足 0 <= n < (j-i)/k 的索引号 x = i + n*k 的项组成的序列。 换句话说,索引号为 i, i+k, i+2*k, i+3*k,以此类推,当达到 j 时停止 (但一定不包括 j)。 当 k 为正值时,ij 会被减至不大于 len(s)。 当 k 为负值时,ij 会被减至不大于 len(s) - 1。 如果 ij 被省略或为 None,它们会成为“终止”值 (是哪一端的终止值则取决于 k 的符号)。 请注意,k 不可为零。 如果 kNone,则当作 1 处理。

  6. 拼接不可变序列总是会生成新的对象。 这意味着通过重复拼接来构建序列的运行时开销将会基于序列总长度的乘方。 想要获得线性的运行时开销,你必须改用下列替代方案之一:

    • 如果拼接 str 对象,你可以构建一个列表并在最后使用 str.join() 或是写入一个 io.StringIO 实例并在结束时获取它的值
    • 如果拼接 bytes 对象,你可以类似地使用 bytes.join()io.BytesIO,或者你也可以使用 bytearray 对象进行原地拼接。 bytearray 对象是可变的,并且具有高效的重分配机制
    • 如果拼接 tuple 对象,请改为扩展 list
    • 对于其它类型,请查看相应的文档
  7. 某些序列类型 (例如 range) 支持遵循特定模式的项序列,因此并不支持序列拼接或重复。

  8. xs 中找不到时 index 会引发 ValueError。 不是所有实现都支持传入额外参数 ij。 这两个参数允许高效地搜索序列的子序列。 传入这两个额外参数大致相当于使用 s[i:j].index(x),但是不会复制任何数据,并且返回的索引是相对于序列的开头而切片的开头。

2、可变序列的操作

以下表格中的操作是在可变序列类型上定义的。 collections.abc.MutableSequence ABC 被提供用来更容易地在自定义序列类型上正确实现这些操作。

表格中的 s 是可变序列类型的实例,t 是任意可迭代对象,而 x 是符合对 s 所规定类型与值限制的任何对象 (例如,bytearray 仅接受满足 0 <= x <= 255 值限制的整数)。

运算结果:注释
s[i] = xs 的第 i 项替换为 x
s[i:j] = tsij 的切片替换为可迭代对象 t 的内容
del s[i:j]等同于 s[i:j] = []
s[i:j:k] = ts[i:j:k] 的元素替换为 t 的元素(1)
del s[i:j:k]从列表中移除 s[i:j:k] 的元素
s.append(x)x 添加到序列的末尾 (等同于 s[len(s):len(s)] = [x])
s.clear()s 中移除所有项 (等同于 del s[:])(5)
s.copy()创建 s 的浅拷贝 (等同于 s[:])(5)
s.extend(t)s += tt 的内容扩展 s (基本上等同于 s[len(s):len(s)] = t)
s *= n使用 s 的内容重复 n 次来对其进行更新(6)
s.insert(i, x)在由 i 给出的索引位置将 x 插入 s (等同于 s[i:i] = [x])
s.pop([i])提取在 i 位置上的项,并将其从 s 中移除(2)
s.remove(x)删除 s 中第一个 s[i] 等于 x 的项目。(3)
s.reverse()就地将列表中的元素逆序。(4)

注释:

  1. t 必须与它所替换的切片具有相同的长度。

  2. 可选参数 i 默认为 -1,因此在默认情况下会移除并返回最后一项。

  3. 当在 s 中找不到 xremove() 操作会引发 ValueError

  4. 当反转大尺寸序列时 reverse() 方法会原地修改该序列以保证空间经济性。 为提醒用户此操作是通过间接影响进行的,它并不会返回反转后的序列。

  5. 包括 clear()copy() 是为了与不支持切片操作的可变容器 (例如 dictset) 的接口保持一致。 copy() 不是 collections.abc.MutableSequence ABC 的一部分,但大多数具体的可变序列类都提供了它。

    3.3 新版功能: clear()copy() 方法。

  6. n 值为一个整数,或是一个实现了 __index__() 的对象。 n 值为零或负数将清空序列。 序列中的项不会被拷贝;它们会被多次引用,正如 通用序列操作 中有关 s * n 的说明。

3、列表 — class list

列表是可变序列,通常用于存放同类项目的集合(其中精确的相似程度将根据应用而变化)。

3.1、 列表介绍

class list(object) — 继承 object

  • 构造函数 list( iterable=(),/ )
  • 可以用多种方式构建列表:
    • 使用一对方括号来表示空列表: []
    • 使用方括号,其中的项以逗号分隔: [a], [a, b, c]
    • 使用列表推导式: [x for x in iterable]
    • 使用类型的构造器: list() 或 list(iterable)
    • 函数产生的结果,比如:sorted() 返回的结果

3.2、 列表的方法

除了支持通用列表方法和可变列表方法以外,还有自己的特别的方法

  • sort(*, key=None, reverse=False)

    • 此方法会对列表进行原地排序,只使用 < 来进行各项间比较。 异常不会被屏蔽 —— 如果有任何比较操作失败,整个排序操作将失败(而列表可能会处于被部分修改的状态)。

    • sort() 接受两个仅限以关键字形式传入的参数 (仅限关键字参数): *

    • key 指定带有一个参数的函数,用于从每个列表元素中提取比较键 (例如 key=str.lower)。 对应于列表中每一项的键会被计算一次,然后在整个排序过程中使用。 默认值 None 表示直接对列表项排序而不计算一个单独的键值。

    • 可以使用 functools.cmp_to_key() 将 2.x 风格的 cmp 函数转换为 key 函数。

    • reverse 为一个布尔值。 如果设为 True,则每个列表元素将按反向顺序比较进行排序。

    • sort() 方法确保是稳定的。 如果一个排序确保不会改变比较结果相等的元素的相对顺序就称其为稳定的 — 这有利于进行多重排序(例如先按部门、再接薪级排序)。

      有关排序示例和简要排序教程,请参阅 排序指南

      s = [1, 3, 5, 7, 2, 4, 6, 8]
      s.sort()
      print(s)
      s.sort(reverse=1)
      print(s)
      
      t = [1, 3, 5, 7, 2, 4, 6, 8]
      
      
      def greater(arg):
          return arg > 5
      
      
      t.sort(key=greater)
      print(t)
      t.sort(key=greater,reverse=1)
      print(t)
      
      

3.3、 列表作为栈使用

列表方法使得列表作为堆栈非常容易,最后一个插入,最先取出(“后进先出”)。

  • 要添加一个元素到堆栈的顶端,使用 append() 。
  • 要从堆栈顶部取出一个元素,使用 pop() ,不用指定索引。
  • 在列表的末尾添加和弹出元素非常快,

3.4、列表作为队列使用

列表也可以用作队列,但是在列表的开头插入或弹出元素却很慢 (因为所有的其他元素都必须移动一位)。

若要实现一个队列,可使用 collections.deque,它被设计成可以快速地从两端添加或弹出元素。

3.5、列表推导式

  • 常规建立列表

    >>> squares = []
    >>> for x in range(10):
    ...     squares.append(x**2)
    ...
    >>> squares
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
  • 使用map函数

    squares = list(map(lambda x: x**2, range(10)))
    
  • 使用推导式
    列表推导式的结构是由一对方括号所包含的以下内容:一个表达式,后面跟一个 for 子句,然后是零个或多个 for 或 if 子句。 其结果将是一个新列表,由对表达式依据后面的 for 和 if 子句的内容进行求值计算而得出。

    # [] 表示列表
    # x ** 2 表达式元素项,x的值由后面的子句得出
    # x 从range里获得 [0~10)
    squares = [x**2 for x in range(10)]  # 整个代码很简洁
    
    >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]  # 三个子句
    [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
    
    • 列表推导式可以使用复杂的表达式

      >>> from math import pi
      >>> [str(round(pi, i)) for i in range(1, 6)]  # 表达式是嵌套的函数
      ['3.1', '3.14', '3.142', '3.1416', '3.14159']
      
    • 嵌套的列表推导式

      matrix = [
          [1, 2, 3, 4],
          [5, 6, 7, 8],
          [9, 10, 11, 12],
      ]
      print(matrix)
      # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
      
      # 表达式 [row[i] for row in matrix] 返回一个列表,每个列表的元素是 matrix[0][i]~matrix[2][i]
      matrix2 = [[row[i] for row in matrix] for i in range(4)]
      print(matrix2)
      # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
      

4、元组 — class tuple

​ 元组是不可变序列,通常用于储存异构数据的多项集(例如由 enumerate() 内置函数所产生的二元组)。 元组也被用于需要同构数据的不可变序列的情况(例如允许存储到 setdict 的实例)。

4.1 介绍

class tuple(object) — 继承 object

  • 构造函数 tuple(iterable=(), /)

  • 可以用多种方式构建元组:

    • 使用一对圆括号来表示空元组: ()
    • 使用一个后缀的逗号来表示单元组: a, 或 (a,)
    • 使用以逗号分隔的多个项: a, b, c or (a, b, c)
    • 使用内置的 tuple(): tuple() 或 tuple(iterable)
    • 构造器将构造一个元组,其中的项与 iterable 中的项具有相同的值与顺序。 iterable 可以是序列、支持迭代的容器或其他可迭代对象。 如果 iterable 已经是一个元组,会不加改变地将其返回。 例如,tuple(‘abc’) 返回 (‘a’, ‘b’, ‘c’) 而 tuple( [1, 2, 3] ) 返回 (1, 2, 3)。 如果没有给出参数,构造器将创建一个空元组 ()。
  • 请注意决定生成元组的其实是逗号而不是圆括号。 圆括号只是可选的,生成空元组或需要避免语法歧义的情况除外。 例如,f(a, b, c) 是在调用函数时附带三个参数,而 f((a, b, c)) 则是在调用函数时附带一个三元组。

  • 元组实现了所有 通用 序列的操作。

  • 对于通过名称访问相比通过索引访问更清晰的异构数据多项集,collections.namedtuple() 可能是比简单元组对象更为合适的选择。

5、range 对象

range 类型表示不可变的数字序列,通常用于在 for 循环中循环指定的次数。

5.1、介绍

class range(object) — 继承 object

  • 构造函数
    • range(stop) -> range object
    • range(start, stop[, step]) -> range object
      • start:开始
      • stop:结束
      • step:步长
  • range 类型相比常规 list 或 tuple 的优势在于一个 range 对象总是占用固定数量的(较小)内存,不论其所表示的范围有多大(因为它只保存了 start, stop 和 step 值,并会根据需要计算具体单项或子范围的值)。

5.2 用法示例

>>> r = range(0, 20, 2)
>>> r
range(0, 20, 2)
>>> 11 in r
False
>>> 10 in r
True
>>> r.index(10)
5
>>> r[5]
10
>>> r[:5]
range(0, 10, 2)
>>> r[-1]
18

6、二进制序列类型

bytes, bytearray, memoryview

​ 操作二进制数据的核心内置类型是 bytes 和 bytearray。 它们由 memoryview 提供支持,该对象使用 缓冲区协议 来访问其他二进制对象所在内存,不需要创建对象的副本。

  • bytes 对象 — 由单个字节构成的不可变序列

    class bytes([source[, encoding[, errors]]])

    首先,表示 bytes 字面值的语法与字符串字面值的大致相同,只是添加了一个 b 前缀:

    • 单引号: b'同样允许嵌入 "双" 引号'
    • 双引号: b"同样允许嵌入 '单' 引号"
    • 三重引号: b'''三重单引号''', b"""三重双引号"""
  • bytearray 对象 — 对应于 bytes 对象的可变序列。

    class bytearray([source[, encoding[, errors]]])

    bytearray 对象没有专属的字面值语法,它们总是通过调用构造器来创建:

    • 创建一个空实例: bytearray()
    • 创建一个指定长度的以零值填充的实例: bytearray(10)
    • 通过由整数组成的可迭代对象: bytearray(range(20))
    • 通过缓冲区协议复制现有的二进制数据: bytearray(b’Hi!’)
  • 相关的方法

    • bytes.count(sub[, start[, end]])
      bytearray.count(sub[, start[, end]])
    • bytes.decode(encoding=“utf-8”, errors=“strict”)
      bytearray.decode(encoding=“utf-8”, errors=“strict”)
    • bytes.endswith(suffix[, start[, end]])
      bytearray.endswith(suffix[, start[, end]])
    • bytes.find(sub[, start[, end]])
      bytearray.find(sub[, start[, end]])
    • bytes.index(sub[, start[, end]])
      bytearray.index(sub[, start[, end]])
    • bytes.join(iterable)
      bytearray.join(iterable)
    • static bytes.maketrans(from, to)
      static bytearray.maketrans(from, to)
    • ytes.partition(sep)
      bytearray.partition(sep)
    • bytes.replace(old, new[, count])
      bytearray.replace(old, new[, count])
    • bytes.rfind(sub[, start[, end]])
      bytearray.rfind(sub[, start[, end]])
    • bytes.center(width[, fillbyte])
      bytearray.center(width[, fillbyte])
    • bytes.split(sep=None, maxsplit=-1)
      bytearray.split(sep=None, maxsplit=-1)
    • bytes.strip([chars])
      bytearray.strip([chars])
    • bytes.capitalize()
      bytearray.capitalize()
    • bytes.expandtabs(tabsize=8)
      bytearray.expandtabs(tabsize=8)
    • bytes.zfill(width)
      bytearray.zfill(width)

7、常见问题

7.1、如何在Python中创建数组?

答:使用列表。😆

7.2、如何创建多维列表

r, c = 2, 3
A = [[None] * c for i in range(r)]
A[0][0] = 1
A[0][1] = 2
print(A)

7.3、如何将方法应用于一系列对象?

可以使用列表推导式:

result = [obj.method() for obj in mylist]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值