Python教程学习 (3)

参考:

5. 数据结构 — Python 3.12.0 文档

数据结构

列表详解

list.append(x)

相当于a[len(a):] = [x],注意:a[len(a)]=[x](少了冒号),a[len(a):]=x(x没有方括号)都是错误的写法。

list.extend(iterable)

TODO:

list.insert(i, x)

list.remove(x)

list.pop([i])

如果不带i,则删除并返回列表的最后一个元素

list.clear()

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

返回列表中第一个值为 x 的元素的索引。这个写法太复杂,实际上就是有以下几种调用方式:

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

start, end用于将搜索限制为列表的特定子序列,但索引值始终以原始序列为起点。

list.count(x)

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

*是Python教程学习 (2)(写文章-CSDN创作中心)中讲到的特殊参数,用于表明其后的参数必须是仅限关键字参数。也就是说,后面的参数在传递实参的时候,必须给出形参名。当然,形参定义了默认参数的话,也可以不传递参数。因此,sort()可以不带参数调用。

>>> a = [1, 2, 3, 4, 5, 6]
>>> a.reverse()
>>> a
[6, 5, 4, 3, 2, 1]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5, 6]

还有,不是所有数据都可以排序或比较。例如,[None, 'hello', 10] 就不可排序,因为整数不能与字符串对比,而 None 不能与其他类型对比。list.reverse()

list.copy()

注意,这个copy是浅拷贝

用列表实现堆栈

append()和pop()函数可以实现堆栈的功能

用列表实现队列

列表也可以实现队列,但是列表作为队列的效率很低。因为,在列表末尾添加和删除元素非常快,但在列表开头插入或移除元素却很慢(因为所有其他元素都必须移动一位)

实现队列最好用collections.deque。这里用到了from...import...语句。

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")
>>> queue.append("Graham")
>>> queue.popleft()
'Eric'
>>> queue.popleft()
'John'
>>> queue
deque(['Michael', 'Terry', 'Graham'])

列表推导式

看这个列表的创建方式

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

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

>>> [(x, y) for x in range(1, 4) for y in [3, 1, 4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

在推导式中,for语句是从左向右解析的,例如:

>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

上例中的"for elem in vec for num in elem"相当于两层for循环,因此是取遍二维数组的每一个元素:

>>> for elem in vec:
...   for num in elem:

嵌套的列表推导式

下面这个例子使用了推导式嵌套, 注意比较下面这个例子和前面一个例子

>>> 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]]

>>> # Similar to this
>>> transposed = []
>>> for i in range(4):
...   transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

为什么这个例子第二个for循环相当于外循环,而前面一个例子的第二个for循环相当于内循环?原因在于第二个例子使用了嵌套推导式。如果去掉了表示推导式嵌套的方括号,结果如下:

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

于是得出:如果没有嵌套,后面的for循环作为内层循环;如果有嵌套,内层嵌套作为内层循环

下面的例子中,用内置函数替代复杂的流程语句。关于zip()函数,这里先简单提一下:"

更正式的说法: zip() 返回元组的迭代器,其中第 i 个元组包含的是每个参数迭代器的第 i 个元素。

不妨换一种方式认识 zip() :它会把行变成列,把列变成行。这类似于 矩阵转置 。"

>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

另外,*matrix是解包实参列表,有点像c语言的取内容,但其实不太一样。这里可以理解为*matrix得到的是三个列表[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]。但这仅仅是一种理解,*matrix本身不能单独存在。

del语句

del语句可以看作更加强大的删除list元素的功能。del是按照索引删除的,可以删除一个元素,也可以删除一个切片。因此,del a[:]相当于clear()。

另外,del a是删除整个变量,之后如果没有再次给a赋值,则使用a会报错。

元组和序列

关于元组(tuple),注意以下几个特殊之处:

  • 输入时,圆括号可有可无,不过经常是必须的。输出时,都有圆括号。
  • 元组是 immutable (不可变的),即不允许为元组中的单个元素赋值。但是元组可以包含mutable (可变的)的列表。例如
>>> v = ([1, 2, 3], [3, 2, 1])
>>> v[0][1]=4
>>> v
([1, 4, 3], [3, 2, 1])
  • 元组可包含异质元素序列,而列表元素一般为同质类型,可迭代访问。比如整数和字符串就是异质的
  • 用一对空圆括号就可以创建空元组;只有一个元素的元组可以通过在这个元素后添加逗号来构建
>>> empty = ()
>>> singleton = 'hello',    # <-- note trailing comma
>>> len(empty)
0
>>> singleton
('hello',)

集合

集合是由不重复元素组成的无序容器。

创建集合用花括号或 set() 函数。注意,创建空集合只能用 set(),不能用 {}{} 创建的是空字典,下一小节介绍数据结构:字典。

支持合集、交集、差集、对称差分等数学运算。

>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a
{'c', 'r', 'b', 'd', 'a'}
>>> b
{'l', 'm', 'c', 'z', 'a'}
>>> a - b
{'d', 'r', 'b'}
>>> a | b
{'l', 'm', 'c', 'r', 'b', 'd', 'z', 'a'}
>>> a & b
{'c', 'a'}
>>> a ^ b  # letters in a or b but not both
{'z', 'l', 'm', 'd', 'r', 'b'}

和列表推导式类似,集合也支持推导式。

字典

字典有点像C++ STL的map。字典在其他语言中可能会被称为“关联存储”或“关联数组”。字典的key可以是任何不可变类型。如果元组没有包含不可变的元素(如列表),则元组也可以作为key。反之,如果一个元组直接或间接地包含了任何可变对象,则不能作为键。

花括号 {} 用于创建空字典。另一种初始化字典的方式是,在花括号里输入逗号分隔的键值对,这也是字典的输出方式。

del 可以删除键值对。对字典执行 list(d) 操作,返回该字典中所有键的列表,按插入次序排列(如需排序,请使用 sorted(d))。检查字典里是否存在某个键,使用关键字 in

dict() 构造函数可以直接用键值对序列创建字典。

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}

字典推导式可以用任意键值表达式创建字典。

>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

但奇怪的是,下面的表达式是有问题的:

>>> {x: y for x in range(6) for y in range(1, 7)}
{0: 6, 1: 6, 2: 6, 3: 6, 4: 6, 5: 6}

>>> {x: y for x in range(6) for y in [2, 3, 4, 5, 6, 7]}
{0: 7, 1: 7, 2: 7, 3: 7, 4: 7, 5: 7}

关键字是比较简单的字符串时,直接用关键字参数指定键值对更便捷:

>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}

循环的技巧

  • 当对字典执行循环时,可以使用 items() 方法同时提取键及其对应的值
  • 在序列中循环时,用 enumerate() 函数可以同时取出位置索引和对应的值
  • 同时循环两个或多个序列时,用 zip() 函数可以将其内的元素一一匹配
  • 为了逆向对序列进行循环,可以求出欲循环的正向序列,然后调用 reversed() 函数
  • 按指定顺序循环序列,可以用 sorted() 函数,在不改动原序列的基础上,返回一个重新的序列
  • 使用 set() 去除序列中的重复元素。使用 sorted()set() 则按排序后的顺序,循环遍历序列中的唯一元素
  • 一般来说,在循环中修改列表的内容时,创建新列表比较简单,且安全。我理解这个说法针对的是类似下面的操作
>>> import math
>>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
>>> for value in raw_data:
...   if math.isnan(value):
...     raw_data.remove(value)
...
>>> raw_data
[56.2, 51.7, 55.3, 52.5, 47.8]

上面的例子中,直接查找并删除raw_data这个列表中的NaN,虽然结果是对的,但这种做法是不推荐的。正确的操作见原文中的例子。

深入条件控制

比较运算符 innot in 用于执行确定一个值是否存在(或不存在)于某个容器中的成员检测。 运算符 isis not 用于比较两个对象是否是同一个对象。 所有比较运算符的优先级都一样,且低于任何数值运算符。

比较操作支持链式操作。例如,a < b == c 校验 a 是否小于 b,且 b 是否等于 c

比较操作可以用布尔运算符 andor 组合,并且,比较操作(或其他布尔运算)的结果都可以用 not 取反。

布尔运算符 andor 是所谓的 短路 运算符,这点和c语言一样。用作普通值而不是布尔值时,短路运算符的返回值通常是最后一个求了值的参数;这点和c语言是不一样的,c的布尔表达式返回的一定是true或false。

>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> non_null
'Trondheim'

上面的例子中对两个字符串执行or操作的定义尚不清楚,TODO

注意,Python 与 C 不同,在表达式内部赋值必须显式使用 海象运算符 :=。 这避免了 C 程序中常见的问题:要在表达式中写 == 时,却写成了 =

序列和其他类型的比较

序列对象可以与相同序列类型的其他对象比较。这种比较使用 字典式 顺序。

当比较不同类型的对象时,只要待比较的对象提供了合适的比较方法,就可以使用 <> 进行比较。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值