列表和元组

1、python的数据结构

1.1、序列类型

python中内置的序列类型:

  • 列表(list)

  • 元组(tuple)

  • 字符串(str)

  • 队列(deque)

  • 字节(bytes)

  • 数组(arrray)

  • 内存视图(memoryview)

    等等

序列类型都共有的操作:迭代、切片、排序、拼接、索引取值、相加、相乘、成员检查等等

1.2、其他类型

  • 字典(dict)(又叫映射)
  • 数字类型:
    • 整形(int)
    • 浮点数(float)
    • 复数(complex)
    • 布尔值(bool)
  • 集合(set)

2、列表和元组

2.1、简介

列表和元组都是python内置的容器序列类型。

容器序列和扁平序列:

  • 容器序列存放的是它们所包含的任意类型的对象的引用,可存放任意类型的数据
  • 扁平里存放的是值而不是引用。即扁平序列其实是一段连续的内存空间,是它里面只能存放诸如字 符、字节和数值这种基础类型。

元组和列表区别在与:元组是不可变的(不可修改),列表是可变的。

在编写代码的过程中,如果我们希望要使用的数据不能被修改,可以使用元组去存储。另外由于元组不可变,并且元组可hash,所以元组可作为字典的键使用(具体介绍见字典一文)。

2.2、序列的通用操作

序列类型通用的操作:迭代、切片、排序、拼接、索引取值、相加、相乘、成员检查等等

2.2.1、索引

序列中的元素从左往右,索引从0开始依次递增。从右往左则是从-1开始依次递减。

>>> a = [1,2,3,4,5]
>>> a[0]
1
>>> a[4]
5
>>> a[-1]
5
>>> a[-5]
1

索引也能从字面量直接取值

>>> 'abcdefg'[2]
'c'
>>> (1,2,3,4,5)[2]
3

弱索引超出序列范围,会抛出IndexError异常

>>> (1,2,3,4,5)[10]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range

2.2.2、切片

索引能访问序列单个元素,切片则是访问序列特定范围的元素。

>>> a
[1, 2, 3, 4, 5]
>>> a[1:3]
[2, 3]
>>> a[1:-2]
[2, 3]

如上,切片需传入两个索引,用以确认切片的范围。注意:切片取值不会包含区间范围的最后一个元素,这样 做带来的好处如下。

  • 当只有最后一个位置信息时,我们可以快速看出切片里有几个元素:list_a[:2] 返回 2个元素的列表。

  • 当起止位置都可见时,我们可以快速计算出切片的长度,用后一个索引减去起始位置索引(stop - start)即可。list_a[3:5],长度为2。

  • 这样做也让我们可以利用任意一个下标来把序列分割成不重叠的两部分,如list_a[:x] 和 list_a[x:] ,以X分隔。

2.2.2.1、切片简写
>>> list_a = list('abcdefg') #序列类型转换。可将可迭代类型数据转换成一个列表
>>> list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list_a[:]  #当不输入索引时,会复值整个序列
['a', 'b', 'c', 'd', 'e', 'f', 'g'] 
>>> list_a[:-3]  #当从序列开始位置取值时,可省略第一个索引
['a', 'b', 'c', 'd']
>>> list_a[2:]   #当切片取值到序列尾部,可省略第二个索引
['c', 'd', 'e', 'f', 'g']
>>> list_a[5:-3]   #当第一个索引在第二个索引后面时,取值一定为空
[]

image-20241020232825476

当当第一个索引在第二个索引后面时

image-20241020233033094

2.2.2.2、切片的步长

切片有三个参数可选

[start, stop[, step]]
开始索引,结束索引,步长(默认为1)

前面我门取值时,使用的默认步长1,即索引+1,挨个取值。步长可根据需求指定,如下

>>> list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list_a[::2] #步长为而,即索引+2取值。
['a', 'c', 'e', 'g'] #索引0,2,4,6位置的值

索引可以为负伤,即倒着取值。 注意:-0 仍然为 0

>>> list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list_a[1:5:-1]  #索引取值方向以正数相反,所以此处为空(将上图箭头反过来)
[]
>>> list_a[5:1:-1] #顺序为5,4,3,2
['f', 'e', 'd', 'c']

步长负数提取看着挺别捏的,好在不常用。经常使用步长为负的情况是将序列倒序

>>> list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list_a[::-1]
['g', 'f', 'e', 'd', 'c', 'b', 'a']

2.2.3、相加

序列可以使用+进行拼接

>>> list_a + list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list_a + 'aaaa'  #不同类型的序列一般不能相加
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list
>>> list_a += [1,2,3]  #可变序列的增量运算会将原序列更改
>>> list_a
['a', 'b', 'c', 'd', 'e', 'f', 'g', 1, 2, 3]

2.2.4、相乘

将序列乘以num时,将重复这个序列num次来创建一个新序列

>>> list_a*3
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> 'abc'*2
'abcabc'
>>> id(a[0])
2391575279872
>>> id(a[2])
2391575279872

注意:序列乘以小于0的数,会被当作0来相乘。不能乘

>>> ['a']*-1
[]
>>> ['a']*0
[]
>>> ['a']*0.5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'float'
>>> 'a'*-1
''

注意:当使用*创建一个包含多个空列表的列表时需注意以下情况

>>> a = [[]]*10
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(2)
>>> a
[[2], [2], [2], [2], [2], [2], [2], [2], [2], [2]]

这里是创建了一个包含10个空列表的列表,但是由于列表里的是另一列表的引用,所以*10后,这10个空列表都指向同一列表。可参考如下方式创建:

>>> [list() for i in range(10)]  #列表推导式,循环初始化10个列表
[[], [], [], [], [], [], [], [], [], []]
>>> a = [list() for i in range(10)]
>>> a[0].append(2)
>>> a
[[2], [], [], [], [], [], [], [], [], []]

或者使用None代替空列表

2.2.5、成员检查

序列的成员检查使用in进行,如下:

>>> 'a' in 'abc'
True
>>> 'a' in 'bc'
False
>>> [1,2] in [[1,2], [3,3]]
True

成员检查即检查特定的值是否包含在指定的序列内。是这返回True,否则返回False。

像这样返回True/False的运算符加布尔运算符

True/False布尔值(bool)

2.2.6、长度、最大值、最小值

如下,即计算序列的长度、最大值、最小值并返回

>>> len([1,2,3])
3
>>> max([1,2,3])
3
>>> min([1,2,3])
1

2.2.7、元素索引和出现次数

序列可使用s.index(x[, i[, j]])方法,找出xs 中首次出现项的索引号(索引号在 i 或其后且在 j 之前)

>>> 'abc'.index('c')
2
>>> 'abcddcdc'.index('c',3,7)
5

s.count(x)计算 x 在 s 中出现的总次数

>>> 'abdksaghdikjasbc'.count('a')
3

2.2.8、比较

相同类型的序列也支持比较。

特别地,tuple 和 list 的比较是通过比较对应元素的字典顺序。 这意味着想要比较结果相等,则每个元素比较结果都必须相等,并且两个序列长度必须相同。

2.3、列表

https://docs.python.org/zh-cn/3/tutorial/datastructures.html#more-on-lists

2.3.1、可变序列操作

bytearray仅接受满足 0 <= x <= 255 值限制的整数)。

运算 结果: 备注
s[i] = x s 的第 i 项替换为 x
s[i:j] = t sij 的切片替换为可迭代对象 t 的内容
del s[i:j] 等同于 s[i:j] = []
s[i:j:k] = t s[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 += t t 的内容扩展 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()s.pop(i) 提取在 i 位置上的项,并将其从 s 中移除 (2)
s.remove(x) s 中移除第一个 s[i] 等于 x 的条目 (3)
s.reverse() 就地将列表中的元素逆序。 (4)

注释:

  1. 如果 k 不等于 1,则 t 必须与它所替换的切片具有相同的长度。

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

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

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

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

    Added in version 3.3: clear()copy() 方法。

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

2.3.2、列表对象的所有方法

  • list.append(x)

    在列表末尾添加一个元素,相当于 a[len(a):] = [x]

  • list.extend(iterable)

    用可迭代对象的元素扩展列表。相当于 a[len(a):] = iterable

  • list.insert(i, x)

    在指定位置插入元素。第一个参数是插入元素位置的索引,因此,a.insert(0, x) 在列表开头插入元素, a.insert(len(a), x) 等同于 a.append(x)

  • list.remove(x)

    从列表中删除第一个值为 x 的元素。未找到指定元素时,触发 ValueError 异常。

  • list.pop(i)

    移除列表中给定位置上的条目,并返回该条目。 如果未指定索引,则 a.pop() 将移除并返回列表中的最后一个条目。 如果列表为空或索引在列表索引范围之外则会引发 IndexError

  • list.clear()

    删除列表里的所有元素,相当于 del a[:]

  • list.index(x[, start[, end]])

    返回列表中第一个值为 x 的元素的零基索引。未找到指定元素时,触发 ValueError 异常。可选参数 startend 是切片符号,用于将搜索限制为列表的特定子序列。返回的索引是相对于整个序列的开始计算的,而不是 start 参数。

  • list.count(x)

    返回列表中元素 x 出现的次数。

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

    就地排序列表中的元素(要了解自定义排序参数,详见 sorted())。

    并非所有数据都可以排序或比较。排序依赖于比较,所以需要序列内元素都能相互比较才能进行排序。

  • list.reverse()

    翻转列表中的元素。

  • list.copy()

    返回列表的浅拷贝。相当于 a[:]

多数列表方法示例:

>>> fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
>>> fruits.count('apple')
2
>>> fruits.count('tangerine')
0
>>> fruits.index('banana')
3
>>> fruits.index('banana', 4)  # 从 4 号位开始查找下一个 banana
6
>>> fruits.reverse()
>>> fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
>>> fruits.append('grape')
>>> fruits
['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
>>> fruits.sort()
>>> fruits
['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
>>> fruits.pop()
'pear'

2.3.3、列表推导式

列表推导式使创建列表的方式更简洁。常见的用法为,对序列或可迭代对象中的每个元素应用某种操作,用生成的结果创建新的列表;或用满足特定条件的元素创建子序列。

例如,创建平方值的列表:

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

等价于:

squares = [x**2 for x in range(10)]

这种写法更简洁、易读。

列表推导式的方括号内包含以下内容:一个表达式,后面为一个 for 子句,然后,是零个或多个 forif 子句。结果是由表达式依据 forif 子句求值计算而得出一个新列表

>>> [(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)]

等价于:

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

嵌套

matrix = [
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]
>>>[[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

等价于:

>>> transposed = []
>>> for i in range(4):
...     # 以下 3 行实现了嵌套的列表组
...     transposed_row = []
...     for row in matrix:
...         transposed_row.append(row[i])
...     transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

2.4、元组

元组是不可变的序列类型,他拥有普通序列的通用操作,除此之外没有用其他新的方法。

>>> tuple([1,2,3])
(1, 2, 3)
>>> (1,2,3)
(1, 2, 3)
>>> t = 12345, 54321, 'hello!'
>>> t
(12345, 54321, 'hello!')
>>> t[0]
12345
# 元组可以嵌套:
>>> u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
# 元组是不可变对象:
>>> t[0] = 88888
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> # 但它们可以包含可变对象:
>>> v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])

构造 0 个或 1 个元素的元组比较特殊:为了适应这种情况,对句法有一些额外的改变。用一对空圆括号就可以创建空元组;只有一个元素的元组可以通过在这个元素后添加逗号来构建(圆括号里只有一个值的话不够明确)。

>>> empty = ()
>>> len(empty)
0
>>> singleton = 'hello',    # <-- 注意末尾的逗号
>>> len(singleton)
1
>>> singleton
('hello',)
posted on 2024-10-31 22:20  莫名丨其妙  阅读(13)  评论(0编辑  收藏  举报