Python与医药数据处理 第六章
第六章 组合数据类型

| 组合数据类型 | 是否可变 | 是否有序 | 数据维度 | 存储内容 |
|---|---|---|---|---|
| 字符串 | 否 | 是 | 1 | 字符 |
| 元组 | 否 | 是 | 1 | 均有 |
| 列表 | 是 | 是 | 1 | 均有 |
| 集合 | 是 | 否 | 1 | 不可变数据类型 |
| 字典 | 是 | 否 | 2 | 键值对,键是不可变数据类型 |
注:这里的维度只一层该数据类型的维度,不考虑内部数据类型的嵌套,如列表里面存在列表
6.0 前置知识:可变数据类型
# Code 1
a = 1; b = 2
a = b
a = a + 1
print(b)
# Code 2
a = [12, 34, 56]
b = [1, 2, 3, 4]
a = b
a.append([5, 6])
a = a + 1
print(b)
上述两个例子中,Code 1 的运行结果毫无疑问是 \(2\),因为 b 从始至终没有改变过。那么如果我告诉你 Code 2 的运行结果是 \([1, 2, 3, 4, [5, 6]]\) 呢?如果你上课没有认真听,你大概率不会相信,但这是真的
Code 2 里的 b 明明也没有改变过,为什么输出的是 a 改变过的结果呢?因为 a 变的时候 b 也一起变了,这两个变量永远是绑定的
这与数据的存储方式有关,从是否可变的角度,数据分为可变数据类型与不可变数据类型,可变数据类型包括列表、字典、集合,不可变数据类型包括整数、浮点数、布尔值、字符串、元组、冻结集合(不要求了解)。
不可变数据类型在计算机中拥有其固定的地址,不可变数据的地址决定了变量的地址:
>>> a = 1
>>> id(a)
140736593725104
>>> b = 2
>>> id(b)
140736593725136
>>> a = b
>>> id(a)
140736593725136
>>> a = a - 1
>>> id(a) # a 的值回到 1,地址也回到了初值
140736593725104
可变数据类型在创建列表的过程中,地址是随意创建的;在赋值的过程中,被赋值变量地址会永久变更为赋值变量的地址(除非后续任意一方被重新定义或赋值),由于二者地址相同,所以内容也是绑定的,对任意一方进行操作,即是对该地址上的数据进行操作,因此另一个变量也应发生相同的改变,两个变量的内容永远是一样的
>>> a = [12, 34, 56]
>>> id(a)
1257369324096
>>> a = [12, 34, 56]
>>> id(a)
1257369256576
>>> a = [12, 34, 56]
>>> id(a) # 三次对变量 a 进行同一列表内容的赋值,地址都不相同
1257369323200
>>> a = [12, 34, 56]
>>> id(a)
1257369324864
>>> b = [1, 2, 3, 4]
>>> id(b)
1257368984192
>>> a = b
>>> a.append([5, 6])
>>> id(b)
1257368984192
>>> id(a) # 二者 id 相同
1257368984192
>>> print(a)
[1, 2, 3, 4, [5, 6]]
>>> print(b) # 修改后,二者内容相同
[1, 2, 3, 4, [5, 6]]
>>> a = [12, 34, 56] # 对变量 a 重新进行了定义,地址会刷新,但是 b 不会发生改变
>>> id(a)
1257369324096
6.1 序列类型
序列类型是有序的一维(线性)组合数据类型,包括字符串(str)、元组(tuple)、列表(list)三类
6.1.1 共有操作
因为字符串也是序列类型的一种,所以共有操作完全可以参考字符串来理解
- 操作符

- 内置函数

- 内置方法

- 遍历序列
(1)基于索引号遍历
for i in range(len(ls)): # 这应该是最直观的遍历方式了
...
(2)基于元素遍历
for each in ls: # 对元素按照顺序依次读取
...
插一道比较有意思的题目:
ls = ['a', 'b', 'c', 'd', 'd', 'd', 'd']
for i in ls:
if i == 'd':
ls.remove(i)
print(ls) # 答案,输出结果应为:['a', 'b', 'c', 'd', 'd']
基于元素遍历的时候,循环的原理其实是在第 \(k\) 次循环中就选取当前状态下列表里第 \(k\) 的元素赋值给循环变量 \(i\),因此该题目的执行逻辑应如下:
# 进入循环体 ls == ['a', 'b', 'c', 'd', 'd', 'd', 'd']
# 第1次循环:取第1个元素,'a',不符合 if 表达式,结束该次循环
# 此时 ls == ['a', 'b', 'c', 'd', 'd', 'd', 'd']
# 第2次循环:取第2个元素,'b',不符合 if 表达式,结束该次循环
# 此时 ls == ['a', 'b', 'c', 'd', 'd', 'd', 'd']
# 第3次循环:取第3个元素,'c',不符合 if 表达式,结束该次循环
# 此时 ls == ['a', 'b', 'c', 'd', 'd', 'd', 'd']
# 第4次循环:取第4个元素,'d',符合 if 表达式,移除这个 'd',结束该次循环
# 此时 ls == ['a', 'b', 'c', 'd', 'd', 'd']
# 第5次循环:取第5个元素,'d',符合 if 表达式,移除这个 'd',结束该次循环(注意这里取的是此时状态下列表的第5个元素,即倒数第2个 'd')
# 此时 ls == ['a', 'b', 'c', 'd', 'd']
# 第6次循环:取第6个元素,发现此时列表已经没有第6个元素了,循环体终止结束,共进行5次循环
(3)枚举遍历序列
for index, herb in enumerate(ls):
print(index, herb)
(4)多变量遍历序列
for d1, d2, d3, d4 in ["上下左右", "北南西东"]:
print(d1, d2, d3, d4)
6.1.2 生成元组
- 函数多个返回值
x = divmod(5, 3)
- 多变量同步赋值
tp = eval(input("请输入3个整数,用逗号分隔:"))
- 循环遍历
numbers = tuple(i for i in range(10))
6.1.3 元组的个性化操作
元组属于不可变序列,访问和处理速度比列表更快。因此元组的元素是不支持修改的,如果执行修改语句会报错异常 'TypeError'
如果元组的元素是可变数据类型,那么元素的值是可以被改变的,但是不建议这么使用,因为这个时候使用元组本身就毫无意义
6.1.4 生成列表
(1)方括号生成法
ls = [1, 352, 'abc', [], 1]
(2)函数/方法返回生成法
ls1 = sorted('13254')
ls2 = s.split("、")
(3)list生成法
ls = list(zip([1, 2, 3], ('a', 'b', 'c')))
(4)map()映射法
ls = list(map(lambda x: x[0], ls))
(5)列表式生成法
ls1 = [x ** 2 for x in range(10)]
6.1.5 列表的个性化操作
- 操作符

- 内置函数

- 内置方法

基本上看表格都能理解,关于内置方法,简要谈一下几个需要注意的函数:
ls.insert(i, x):添加在原列表中索引号为 \(i-1\) 的元素后面,如
>>> ls = [0, 2, 4, 6, 8]
>>> ls.insert(1, 1) # 在索引号为 0 的元素后面插入
[0, 1, 2, 4, 6, 8]
ls.reverse() 和 ls.sort() 都有对应的独立函数 reversed 和 sorted,其中 sorted() 在第五章内置函数章节有所提及,reversed(ls) 返回的是反转后得到的迭代器,需要用 list() 函数将其转化为列表将其显化
ls2 = list(reversed(ls1))
6.2 集合(set)
集合是一类一维无序可变数据类型,集合的主要特点是不重复性和无序性
集合的元素只能是固定数据类型(不可变数据类型),包括:数字类型、字符串类型、逻辑类型、不包含可变数据类型元素的元组
6.2.1 生成集合
(1)表示法
a = {1, 2, 3}
(2)set() 函数法
a = set('apple')
a = set() # 该语句用以生成空集合
# a = {} 不能用于生成空集合,该命令生成的是空字典
6.2.2 集合的操作
- 操作符

- 内置函数

- 内置方法

6.3 字典(dict)
字典的结构:{<键1>:<值1>, <键2>:<值2>, ..., <键n>:<值n>}
字典是一类二维无序组合数据类型由键值对构成,元素为键值对
键只能取固定数据类型,值不限
字典是无序结构,键具有不重复性
6.3.1 生成字典
生成字典通常使用直接表示法
dic = {<键1>:<值1>, <键2>:<值2>, ..., <键n>:<值n>}
# 花括号内无内容时,生成空字典
6.3.2 字典的个性化操作
- 基本操作
<字典变量[<键>]>:检索键对应的值
<键> in <字典变量>:成员运算,判断键是否在字典里
<字典变量[<键>]> = 值:如果 <键> 为字典内已有的,则更新对应的值;如果 <键> 在字典内没有,就创建新的键值对
- 内置函数
del(<字典变量>[<键>]):删除元素,删除键对应的键值对
- 内置方法

对于返回类型为 dict_keys 和 dict_values 的函数,可以使用 list() 函数等对数据进行显化:
>>> dic = {'a':1,'b':2,'c':3}
>>> dic.keys()
dict_keys(['a', 'b', 'c'])
>>> list(dic.keys())
['a', 'b', 'c']
- 遍历字典
由于“键值对”中的键相当于所以,所以 for 循环的循环变量名是字典的键,如:
dic = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
for i in dic:
print("键:", i)
print("值:", dic.get(i))
6.4 jieba库
jieba.cut(s):精确模式,返回一个可迭代的数据类型
jieba.cut(s, cut_all = True):全模式,返回一个可迭代的数据类型
jieba.cut_for_search(s):搜索引擎模式,返回一个可迭代的数据类型
jieba.lcut(s):精确模式,返回一个列表
jieba.lcut(s, cut_all = True):全模式,返回一个列表
jieba.lcut_for_search(s):搜索引擎模式,返回一个列表
jieba.add_word(w):向用来检索词汇的词库里面添加新词
前六个方法为分词的方法,分词分为精确模式,全模式,搜索引擎模式:
精确模式:将文字按照语义最尽可能精确地切开,适用于文本分析
全模式:把句子中所有可以分成词的词语都扫描出来,速度非常快,但难以消除歧义
搜索引擎模式:在精确模式的基础上,对长词进行进一步切分,将切分出来的词语补充进去
六个分词方法中,后三个 'l' 开头的返回的都是列表类型,方便我们后续进行操作,故一般多使用这三个方法
6.5 词频统计


浙公网安备 33010602011771号