前面我们学习了基本数据类型和变量,现在我们学习Python的四种集合,列表(List)和元组(tuple),字典(Dict),无序列表(Set)
List (列表)是 Python 内置的一种数据类型。是一种有序的集合,可以随时添加和删除其中的元素。
那为什么要有 List (列表)呢?
我们用一个例子来说明。
现在有一个团队要出去玩,要先报名。如果用我们之前学过的知识,那么就是用一个字符串变量把他们都记录起来。
name1 = 'Smith'
name2 = 'Johnny'
name3 = 'Allen'
但是这样太麻烦了,而且也不美观。
在编程中,一定要学会偷懒,避免「重复性工作」。如果有一百个成员,那么你及时是复制粘贴,也会把你写烦。
这时候就可以使用列表了。
name = ['Smith', 'Johnny', 'Allen']
就这样,一行代码就可以存放 N 多个名字了。
其实列表就是用中括号 []
括起来的数据,里面的每一个数据就叫做元素。每个元素之间使用逗号分隔。
而且列表的数据元素不一定是相同的数据类型。
比如:
name = ['Smith', 'Johnny', 'Allen']
这里有字符串类型,还有整数类型。
我们尝试把他打印出来,看看打印的结果是怎样的。
结果如下:
就像一开始的例子,我们有时候不需要把全部人员的姓名都打印出来,有时候我们需要知道第 3 个报名的人是谁?前两名报名的是谁?
那么怎么从列表中取出来呢?
换种问法就是,怎么去访问列表中的值?
这时候我们可以通过列表的下标索引来访问列表中的值,同样你也可以使用方括号的形式截取字符。
例如:
name = ['Smith', 'Johnny', 'Allen']
# 通过索引来访问列表
print(name[2])
# 通过方括号的形式来截取列表中的数据
print(name[0:2])
输出的结果:
可见,我们需要知道知道 name
这个列表中第三个报名的是谁?只需要用 name[2]
就可以了。
这里你会问,为什么是 2 ,不是 3 呢?
这是因为在编程世界中,都是从 0 开始的,而不是我们生活习惯中从 1 开始。
所以需要知道第三个是谁?
那就是 name[2]
就可以了。
从例子来看,我们还把 name[0:2]
的结果打印出来了。
从打印结果来看,只打印了第一,第二个元素内容。
这里可能会有疑问?
为什么不是打印前三个啊,不是说 2 就是第 3 个吗?
那是因为这是左闭右开区间的。
所以 name[0:2]
的意思就是从第 0 个开始取,取到第 2 个,但是不包含第 2 个。
还是那句话,为了更好的理解,可以多去尝试,多去玩编程。
所以你可以尝试下下面的各种方式:
name = ['Smith', 'Johnny', 'Allen']
print(name[0:2])
print(name[:2])
print(name[:])
print(name[1:2])
看看输出的结果:
根据输出的结果和上面讲到的知识,就很容易理解其中的一些用法了。
还是一开始的例子,我们用代码记录了报名人的名字,那后面可能会有新人加入,也有可能会发现一开始写错名字了,想要修改。
这时候怎么办呢?
这时候可以通过索引对列表的数据项进行修改或更新,也可以使用 append() 方法来添加列表项。
name = ['Smith', 'Johnny', 'Allen']
# 通过索引对列表的数据项进行修改或更新
name[1]='Jack'
print(name)
# 使用 append() 方法来添加列表项
name.append('张三')
print(name)
输出的结果:
那既然这样,肯定会有人中途退出的。
那么我们就需要在列表中,把他的名字去掉。
这时候使用 del 语句来删除列表的的元素
name = ['Smith', 'Johnny', 'Allen']
print(name)
# 使用 del 语句来删除列表的的元素
del name[2]
print(name)
输出的结果:
你看输出的结果,列表中已经没有了 四点水
这个数据了。证明已经删除成功了。
列表对 +
和 *
的操作符与字符串相似。+
号用于组合列表,*
号用于重复列表。
Python 表达式 | 结果 | 描述 |
---|---|---|
len([1, 2, 3]) | 3 | 计算元素个数 |
[1, 2, 3] + [4, 5, 6] | [1, 2, 3, 4, 5, 6] | 组合 |
['Hi!'] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 复制 |
3 in [1, 2, 3] | True | 元素是否存在于列表中 |
for x in [1, 2, 3]: print x, | 1 2 3 | 迭代 |
函数&方法 | 描述 |
---|---|
len(list) | 列表元素个数 |
max(list) | 返回列表元素最大值 |
min(list) | 返回列表元素最小值 |
list(seq) | 将元组转换为列表 |
list.append(obj) | 在列表末尾添加新的对象 |
list.count(obj) | 统计某个元素在列表中出现的次数 |
list.extend(seq) | 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) |
list.index(obj) | 从列表中找出某个值第一个匹配项的索引位置 |
list.insert(index, obj) | 将对象插入列表 |
list.pop(obj=list[-1]) | 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 |
list.remove(obj) | 移除列表中的一个元素(参数是列表中元素),并且不返回任何值 |
list.reverse() | 反向列表中元素 |
list.sort([func]) | 对原列表进行排序 |
最后通过一个例子来熟悉了解 List 的操作
例子:
#-*-coding:utf-8-*-
#-----------------------list的使用----------------------------------
# 1.一个产品,需要列出产品的用户,这时候就可以使用一个 list 来表示
user=['liangdianshui','twowater','两点水']
print('1.产品用户')
print(user)
# 2.如果需要统计有多少个用户,这时候 len() 函数可以获的 list 里元素的个数
len(user)
print('\n2.统计有多少个用户')
print(len(user))
# 3.此时,如果需要知道具体的用户呢?可以用过索引来访问 list 中每一个位置的元素,索引是0从开始的
print('\n3.查看具体的用户')
print(user[0]+','+user[1]+','+user[2])
# 4.突然来了一个新的用户,这时我们需要在原有的 list 末尾加一个用户
user.append('茵茵')
print('\n4.在末尾添加新用户')
print(user)
# 5.又新增了一个用户,可是这个用户是 VIP 级别的学生,需要放在第一位,可以通过 insert 方法插入到指定的位置
# 注意:插入数据的时候注意是否越界,索引不能超过 len(user)-1
user.insert(0,'VIP用户')
print('\n5.指定位置添加用户')
print(user)
# 6.突然发现之前弄错了,“茵茵”就是'VIP用户',因此,需要删除“茵茵”;pop() 删除 list 末尾的元素
user.pop()
print('\n6.删除末尾用户')
print(user)
# 7.过了一段时间,用户“liangdianshui”不玩这个产品,删除了账号
# 因此需要要删除指定位置的元素,用pop(i)方法,其中i是索引位置
user.pop(1)
print('\n7.删除指定位置的list元素')
print(user)
# 8.用户“两点水”想修改自己的昵称了
user[2]='三点水'
print('\n8.把某个元素替换成别的元素')
print(user)
# 9.单单保存用户昵称好像不够好,最好把账号也放进去
# 这里账号是整数类型,跟昵称的字符串类型不同,不过 list 里面的元素的数据类型是可以不同的
# 而且 list 元素也可以是另一个 list
newUser=[['VIP用户',11111],['twowater',22222],['三点水',33333]]
print('\n9.不同元素类型的list数据')
print(newUser)
上一节刚说了一个有序列表 List ,现在说另一种有序列表叫元组:tuple 。
tuple 和 List 非常类似,但是 tuple 一旦初始化就不能修改。 也就是说元组(tuple)是不可变的,那么不可变是指什么意思呢?
元组(tuple) 不可变是指当你创建了 tuple 时候,它就不能改变了,也就是说它也没有 append(),insert() 这样的方法,但它也有获取某个索引值的方法,但是不能赋值。
那么为什么要有 tuple 呢?
那是因为 tuple 是不可变的,所以代码更安全。
所以建议能用 tuple 代替 list 就尽量用 tuple 。
元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。
tuple1=('两点水','twowter','liangdianshui',123,456)
tuple2='两点水','twowter','liangdianshui',123,456
创建空元组
tuple3=()
元组中只包含一个元素时,需要在元素后面添加逗号
tuple4=(123,)
如果不加逗号,创建出来的就不是 元组(tuple),而是指 123
这个数了。
这是因为括号 () 既可以表示元组(tuple),又可以表示数学公式中的小括号,这就产生了歧义。
所以如果只有一个元素时,你不加逗号,计算机就根本没法识别你是要进行整数或者小数运算还是表示元组。
因此,Python 规定,这种情况下,按小括号进行计算,计算结果自然是 123
,而如果你要表示元组的时候,就需要加个逗号。
具体看下图 tuple4 和 tuple5 的输出值
元组下标索引也是从 0 开始,元组(tuple)可以使用下标索引来访问元组中的值。
#-*-coding:utf-8-*-
tuple1=('两点水','twowter','liangdianshui',123,456)
tuple2='两点水','twowter','liangdianshui',123,456
print(tuple1[1])
print(tuple2[0])
输出的结果:
可能看到这个小标题有人会疑问,上面不是花了一大段来说 tuple 是不可变的吗?
这里怎么又来修改 tuple (元组) 了。
那是因为元组中的元素值是不允许修改的,但我们可以对元组进行连接组合,还有通过修改其他列表的值从而影响 tuple 的值。
具体看下面的这个例子:
输出的结果:
('两点水', 'twowater', 'liangdianshui', [123, 456])
('两点水', 'twowater', 'liangdianshui', [789, 100])
可以看到,两次输出的 tuple 值是变了的。我们看看 tuple1 的存储是怎样的。
可以看到,tuple1 有四个元素,最后一个元素是一个 List ,List 列表里有两个元素。
当我们把 List 列表中的两个元素 124
和 456
修改为 789
和 100
的时候,从输出来的 tuple1 的值来看,好像确实是改变了。
但其实变的不是 tuple 的元素,而是 list 的元素。
tuple 一开始指向的 list 并没有改成别的 list,所以,tuple 所谓的“不变”是说,tuple 的每个元素,指向永远不变。注意是 tupe1 中的第四个元素还是指向原来的 list ,是没有变的,我们修改的只是列表 List 里面的元素。
tuple 元组中的元素值是不允许删除的,但我们可以使用 del 语句来删除整个元组
与字符串一样,元组之间可以使用 +
号和 *
号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。
Python 表达式 | 结果 | 描述 |
---|---|---|
len((1, 2, 3)) | 3 | 计算元素个数 |
(1, 2, 3) + (4, 5, 6) | (1, 2, 3, 4, 5, 6) | 连接 |
('Hi!',) * 4 | ('Hi!', 'Hi!', 'Hi!', 'Hi!') | 复制 |
3 in (1, 2, 3) | True | 元素是否存在 |
for x in (1, 2, 3): print(x) | 1 2 3 | 迭代 |
方法 | 描述 |
---|---|
len(tuple) | 计算元组元素个数 |
max(tuple) | 返回元组中元素最大值 |
min(tuple) | 返回元组中元素最小值 |
tuple(seq) | 将列表转换为元组 |
最后跟列表一样,来一个实例,大家也可以多尝试,去把元组的各种玩法玩一遍。
name1 = ('一点水', '两点水', '三点水', '四点水', '五点水')
name2 = ('1点水', '2点水', '3点水', '4点水', '5点水')
list1 = [1, 2, 3, 4, 5]
# 计算元素个数
print(len(name1))
# 连接,两个元组相加
print(name1 + name2)
# 复制元组
print(name1 * 2)
# 元素是否存在 (name1 这个元组中是否含有一点水这个元素)
print('一点水' in name1)
# 元素的最大值
print(max(name2))
# 元素的最小值
print(min(name2))
# 将列表转换为元组
print(tuple(list1))
运行结果:
上一章节,我们学习了列表(List) 和 元组(tuple) 来表示有序集合。
而我们在讲列表(list)的时候,我们用了列表(list) 来存储用户的姓名。
那么如果我们为了方便联系这些童鞋,要把电话号码也添加进去,该怎么做呢?
用 list 可以这样子解决:
name = [['johnny1', '25'], ['johnny2', '18'], ['johnny3', '19'], ['johnny4', '20'], ['johnny5', '21']]
但是这样很不方便,我们把电话号码记录下来,就是为了有什么事能及时联系上这些童鞋。
如果用列表来存储这些,列表越长,我们查找起来耗时就越长。
这时候就可以用 dict (字典)来表示了,Python 内置了 字典(dict),dict 全称 dictionary,如果学过 Java ,字典就相当于 JAVA 中的 map,使用键-值(key-value)存储,具有极快的查找速度。
name = {'johnny1': '25', 'johnny2': '18', 'johnny3': '19', 'johnny4': '20', 'johnny5': '21'}
字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 ,格式如下所示:
dict = {key1 : value1, key2 : value2 }
注意:键必须是唯一的,但值则不必。值可以取任何数据类型,但键必须是不可变的。
创建 dict(字典)实例:
dict1={'jack':'18' ,'johnny':'25' ,'allen':'33'}
dict2={'abc':1234,1234:'abc'}
我们知道了怎么创建列表了,回归到一开始提出到的问题,为什么使用字典能让我们很快的找出某个童鞋的电话呢?
输出的结果:
131456780002
可以看到,如果你知道某个人的名字,也就是 key 值, 就能很快的查找到他对应的电话号码,也就是 Value 。
这里需要注意的一点是:如果字典中没有这个键,是会报错的。
向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对
#-*-coding:utf-8-*-
dict1={'jack':'18' ,'johnny':'25' ,'allen':'33'}
print(dict1)
# 新增一个键值对
dict1['jack']='44'
print(dict1)
# 修改键值对
dict1['jack']='55'
print(dict1)
输出的结果:
{'jack': '18', 'johnny': '25', 'allen': '33'}
{'jack': '44', 'johnny': '25', 'allen': '33'}
{'jack': '55', 'johnny': '25', 'allen': '33'}
通过 del
可以删除 dict (字典)中的某个元素,也能删除 dict (字典)
通过调用 clear()
方法可以清除字典中的所有元素
#-*-coding:utf-8-*-
dict1={'jack':'18' ,'johnny':'25' ,'allen':'33'}
print(dict1)
# 通过 key 值,删除对应的元素
del dict1['johnny']
print(dict1)
# 删除字典中的所有元素
dict1.clear()
print(dict1)
# 删除字典
del dict1
输出的结果:
{'jack': '18', 'johnny': '25', 'allen': '33'}
{'jack': '18', 'allen': '33'}
{}
(1) dict (字典)是不允许一个键创建两次的,但是在创建 dict (字典)的时候如果出现了一个键值赋予了两次,会以最后一次赋予的值为准
例如:
#-*-coding:utf-8-*-
dict1={'jack':'18' ,'johnny':'25' ,'allen':'33','dennis':'44'}
print(dict1)
print(dict1['johnny'])
输出的结果:
{'jack': '18', 'johnny': '25', 'allen': '33', 'dennis': '44'}
25
(2) dict (字典)键必须不可变,可是键可以用数字,字符串或元组充当,但是就是不能使用列表
例如:
#-*-coding:utf-8-*-
dict1={'liangdianshui':'111111' ,123:'222222' ,(123,'tom'):'333333','twowater':'444444'}
print(dict1)
输出结果:
{'liangdianshui': '111111', 123: '222222', (123, 'tom'): '333333', 'twowater': '444444'}
(3) dict 内部存放的顺序和 key 放入的顺序是没有任何关系
和 list 比较,dict 有以下几个特点:
而list相反:
方法和函数 | 描述 |
---|---|
len(dict) | 计算字典元素个数 |
str(dict) | 输出字典可打印的字符串表示 |
type(variable) | 返回输入的变量类型,如果变量是字典就返回字典类型 |
dict.clear() | 删除字典内所有元素 |
dict.copy() | 返回一个字典的浅复制 |
dict.values() | 以列表返回字典中的所有值 |
popitem() | 随机返回并删除字典中的一对键和值 |
dict.items() | 以列表返回可遍历的(键, 值) 元组数组 |
python 的 set 和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素。
set 和 dict 类似,但是 set 不存储 value 值的。
创建一个 set,需要提供一个 list 作为输入集合
set1=set([123,456,789])
print(set1)
输出结果:
{456, 123, 789}
传入的参数 [123,456,789]
是一个 list,而显示的 {456, 123, 789}
只是告诉你这个 set 内部有 456, 123, 789 这 3 个元素,显示的顺序跟你参数中的 list 里的元素的顺序是不一致的,这也说明了 set 是无序的。
还有一点,我们观察到输出的结果是在大括号中的,经过之前的学习,可以知道,tuple (元组) 使用小括号,list (列表) 使用方括号, dict (字典) 使用的是大括号,dict 也是无序的,只不过 dict 保存的是 key-value 键值对值,而 set 可以理解为只保存 key 值。
回忆一下,在 dict (字典) 中创建时,有重复的 key ,会被后面的 key-value 值覆盖的,而 重复元素在 set 中自动被过滤的。
set1=set([123,456,789,123,123])
print(set1)
输出的结果:
{456, 123, 789}
通过 add(key) 方法可以添加元素到 set 中,可以重复添加,但不会有效果
set1=set([123,456,789])
print(set1)
set1.add(100)
print(set1)
set1.add(100)
print(set1)
输出结果:
{456, 123, 789}
{456, 123, 100, 789}
{456, 123, 100, 789}
通过 remove(key) 方法可以删除 set 中的元素
set1=set([123,456,789])
print(set1)
set1.remove(456)
print(set1)
输出的结果:
{456, 123, 789}
{123, 789}
因为 set 是一个无序不重复元素集,因此,两个 set 可以做数学意义上的 union(并集), intersection(交集), difference(差集) 等操作。
例子:
set1=set('hello')
set2=set(['p','y','y','h','o','n'])
print(set1)
print(set2)
# 交集 (求两个 set 集合中相同的元素)
set3=set1 & set2
print('\n交集 set3:')
print(set3)
# 并集 (合并两个 set 集合的元素并去除重复的值)
set4=set1 | set2
print('\n并集 set4:')
print(set4)
# 差集
set5=set1 - set2
set6=set2 - set1
print('\n差集 set5:')
print(set5)
print('\n差集 set6:')
print( set6)
# 去除海量列表里重复元素,用 hash 来解决也行,只不过感觉在性能上不是很高,用 set 解决还是很不错的
list1 = [111,222,333,444,111,222,333,444,555,666]
set7=set(list1)
print('\n去除列表里重复元素 set7:')
print(set7)
运行的结果:
{'h', 'l', 'e', 'o'}
{'h', 'n', 'o', 'y', 'p'}
交集 set3:
{'h', 'o'}
并集 set4:
{'h', 'p', 'n', 'e', 'o', 'y', 'l'}
差集 set5:
{'l', 'e'}
差集 set6:
{'p', 'y', 'n'}
去除列表里重复元素 set7:
{555, 333, 111, 666, 444, 222}