一、引言
在Python入门(上)介绍了Python语言的变量、数据类型、语句和异常等基本语法要素。数据类型中的整型、浮点型和布尔型三种数据类型是基础的数据类型,此外,容器数据类型是Python比较高级的数据类型,属于Python数据结构,包括:列表、元组、字典、集合和字符串。
二、列表
列表是由序列构成的数组,有序且无固定大小限制,能够保存任意数据任意类型的Python对象,且同一个列表中各对象的数据类型可以不一致,Python中列表关键字为list。
>>> dir(list)
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> datas = list()
>>> print(datas)
[]
>>> datas.append(2) # 添加元素2
>>> print(datas)
[2]
>>> datas[0] = 3 # 更新元素
>>> print(datas)
[3]
>>> datas.insert(0, 5) # 插入元素到指定位置
>>> print(datas)
[5, 3]
>>> datas.append(6) # 添加元素6,默认为队尾
>>> print(datas)
[5, 3, 6]
>>> datas.index(3) # 获取元素索引
1
>>> datas.reverse() # 列表倒序
>>> print(datas)
[6, 3, 5]
>>> datas.pop() # 删除最后一个元素
5
>>> print(datas)
[6, 3]
>>> datas.pop(0) # 删除指定元素
6
>>> print(datas)
[3]
>>> 6 in datas # 判断6是否存在列表中,不建议此方法,数据量大时效率很低
False
三、元组
元组可以简单理解为“不可变列表”,但不能仅仅局限于此,元组还能用作没有字段名的记录,这是比较容易忽略的一个重点,,Python中元组关键字为tuple。
元组用于没有字段名的记录的功能经常被忽略,这里重点介绍下,如果只把元组理解为不可变的列表,那其他信息——它所含有的元素的总数和它们的位置——似乎就变得可有可无,这和列表好像就没有什么区别,而且还不能任意扩展和修改。但是如果把元组当作一些字段的集合,那么数量和位置信息就变得非常重要了。
>>> a, b = tuple([1,2,3,4]), (1,2,3,4) # 元组的初始化,多种定义方式
>>> print(a)
(1, 2, 3, 4)
>>> print(b)
(1, 2, 3, 4)
>>> a == b # 回想下在Python中 == 和 is的区别
True
>>> a is b
False
>>> c = a + b # 元组相加组成新的元组
>>> c
(1, 2, 3, 4, 1, 2, 3, 4)
>>> a1,b1,c1 = a # 解压出错,因为数量不一致
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
>>> a1,b1,c1,d1 = a
>>> a1,b1,c1,d1
(1, 2, 3, 4)
四、数组
虽然列表既灵活又简单,但面对各类需求时,还是可能会有更好的选择。比如,要存放 1000 万个浮点数的话,数组(array)的效率要高得多,因为数组在背后存的并不是 float 对象,而是数字的机器翻译,也就是字节表述。这一点就跟 C 语言中的数组一样。再比如说,如果需要频繁对序列做先进先出的操作,deque(双端队列)的速度应该会更快,Python中数组关键字为array。
>>> from array import array
>>> from random import random
>>> floats = array('d', (random() for i in range(10**7))) # 建立双精度类型的数组,有100万个浮点数
>>> len(floats) # 查看长度
10000000
>>> type(floats) # 查看数据类型
<class 'array.array'>
>>> floats[-1] # 查看最后一个数据
0.7809365968607413
五、字符串
“字符串”是个相当简单的概念:一个字符串是一个字符序列。至于字符的定义在此就不多加描述了,Python中字符串关键字为str。
>>> t1 = 'i love Python!' # 使用单引号的字符串
>>> print(t1, type(t1)) # 查看字符串和其的数据类型
i love Python! <class 'str'>
>>> t2 = "I love Python!" # 使用双引号的字符串
>>> print(t2, type(t2))
I love Python! <class 'str'>
>>> print(5 + 8) # 数字相加
13
>>> print('5' + '8') # 数字字符相加,这是已不表示整数,而是表示这个5或者8这个字符
58
>>> str1 = 'I Love LsgoGroup'
>>> str1[2:6] # 字符串切片
'Love'
>>> str += " best!" # 字符串拼接
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +=: 'type' and 'str'
>>> str1 += " best!" # 字符串拼接
>>> print(str1)
I Love LsgoGroup best!
>>> str1.capitalize() # 字符串首字母大写,非常使用,原本已经是大写了,用其它例子测试吧
'I love lsgogroup best!'
>>> str1.upper() # 转换为大写
'I LOVE LSGOGROUP BEST!'
>>> str1.lower() # 转换为小写
'i love lsgogroup best!'
此外还涉及字符串的格式化输出等内容,这里留到Python输入输出部分再做具体学习。
六、字典
字典类型是Python语言的基石,即使我们开发的任何Python源码里面没有使用字典,但它仍然活跃在所有Python程序的背后:模块的命名空间、实例属性和函数的关键字参数中都可以看到字典的身影。简单来说,字典就是映射,其性能出众的根本原因是散列表,Python中字典关键字为dict。
字典有个重要的要求:只有可散列的数据类型才能用作这些映射里的键(只有键有这个要求,值并不需要是可散列的数据类型),什么是可散列的数据类型?如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,可用hash函数校验是否是可散列的。
>>> hash(1)
1
>>> hash(2)
2
>>> hash('2')
-576363104648924840
>>> hash([1,2,3,4])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash((1,2,3,4))
590899387183067792
>>> # 字典的多种创建方式
>>> a = dict(one=1, two=2, three=3)
>>> print(a)
{'one': 1, 'two': 2, 'three': 3}
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> print(b)
{'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True
>>> a is b
False
>>> a.keys() # 获取字典键
dict_keys(['one', 'two', 'three'])
>>> a.values() # 获取键值
dict_values([1, 2, 3])
>>> a['one'] = 11 # 更新
>>> print(a)
{'one': 11, 'two': 2, 'three': 3}
>>> a.pop('one') # 移除指定键
11
>>> print(a)
{'two': 2, 'three': 3}
>>> a['newone'] = 1 # 添加新值
>>> print(a)
{'two': 2, 'three': 3, 'newone': 1}
>>> for key, value in a.items(): # 字典遍历
... print(key, value)
...
two 2
three 3
newone 1
七、集合
集合在Python数据结构中,属于较为年轻的成员,实际开发中使用率较低,本质上是许多唯一对象的集合,在Python中集合关键字为set。
特别注意事项:空集合创建是用se(),而不是{},{}创建的是字典
>>> a = set() # 空集合
>>> b = {} # 空字典
>>> type(a), type(b)
(<class 'set'>, <class 'dict'>)
>>> basket = set() # 创建空集合
>>> basket.add('apple') # 添加元素
>>>> basket.add('apple') # 重复添加
>>> basket.add('banana') # 添加新的元素
>>> print(basket) # 查看集合
{'apple', 'banana'}
>>> basket.remove('apple') # 移除元素
>>> print(basket)
{'banana'}
集合的唯一特性非常适合用于去重。
集合读取一般是使用for循环遍历读取。
多个集合可以实现集合数学上的操作,例如并、交、补等。
>>> set_a = set('apples')
>>> set_b = set('bananas')
>>> set_a, set_b
({'p', 'a', 'e', 's', 'l'}, {'b', 'n', 's', 'a'})
>>> set_a & set_b # 交集
{'s', 'a'}
>>> set_a | set_b # 并集
{'p', 'b', 'n', 'a', 'e', 's', 'l'}
>>> set_a - set_b # 补集或差集
{'e', 'p', 'l'}
八、序列
序列并不是指具体的一类数据类型,指支持一些通用的序列操作的数据类型,它包括字符串、列表、元组、集合和字典,例如都支持返回最大或最小值的函数,但比较特殊的是,集合和字典不支持索引、切片、相加和相乘操作。
>>> max([1,2,3,4])
4
>>> max((1,2,3,4))
4
>>> max({1,2,3,4})
4
>>> max('1234')
'4'
>>> max({1:'a', 2:'b', 3:'c', 4:'d'})
4
九、总结
Python容器类型(数据结构)概念和使用其实是非常简单的,相比其它编程语言的学习,入门的学习陡峭度是非常低的,但背后的逻辑和高阶使用还是需要去理解的,当然也需要花一定时间的,依旧推荐《Python学习手册》和《流畅的Python》书籍,入门学习可以看前者,后者的话建议有一定Python基础之后再看,虽也是入门书籍,但没有一定的实际Python经验,理解和感受不会太直观。