python -- 元素和容器

来源:互联网 发布:黄道日与黑道日的算法 编辑:程序博客网 时间:2024/06/05 11:50

元素和容器

重点掌握列表、元组、字典、集合

列表

创建

empty_list = [ ]empty_list =list()weekdays =['星期一','星期二','星期三','星期四','星期五','星期六','星期日’]name =['张三','李四','王五']

Python 的list() 函数可以将其他数据类型转换成列表类型。

list容器可以容纳不同类型的元素,相同元素可以出现多次,这点与set不同哦

>>> list('abc')['a', 'b', 'c’]>>> list('123')['1', '2', '3’]>>> a_tuple = ('hello', 'world', 'python')>>> list(a_tuple)['hello', 'world', 'python’]>>> birthday = '8/27/2017'>>> birthday.split('/')['8', '27', '2017']>>>list = [1,'hello']

获取元素

通过偏移量可以从列表中提取对应位置的元素

>>> marxes = ['Groucho', 'Chico', 'Harpo']>>> marxes[0]'Groucho'>>> marxes[1]'Chico'>>> marxes[2]'Harpo'

包含列表的列表

列表可以包含各种类型的元素,包括其他列表,如下所示:

Quarter=[[1,2,3],[4,5,6],[7,8,9,],[10,11,12]]>>> print(Quarter)[[1, 2, 3], [4, 5, 6], [7, 8,9], [10, 11, 12]]>>> Quarter[1][4, 5, 6]>>> Quarter[1][2]6

列表修改

Quarter=[[1,2,3],[4,5,6],[7,8,9,],[10,11,12]]>>> Quarter[2][2] = 0>>> print(Quarter)[[1, 2, 3], [4, 5, 6], [7, 8, 0], [10, 11, 12]]>>> Quarter[2][2]='0'>>> print(Quarter)[[1, 2, 3], [4, 5, 6], [7, 8, '0'], [10, 11, 12]]

常用操作

Quarter[0:2] 指定范围并使用切片提取元素Quarter.append(‘13’) 使用append()添加元素至尾部Quarter.extend(name) Quarter += others 使用extend()或+=合并列表 Quarter.insert(5, ‘14’) 使用insert()在指定位置插入元素del Quarter[-1] 使用del删除指定位置的元素Quarter.remove(‘13’) 使用remove()删除具有指定值的元素Quarter.pop(1) 使用pop()获取并删除指定位置的元素 pop()  如果不指定,默认弹出最后一个原始,即默认传入-1Quarter.index ([1,2,3])  使用index()查询具有特定值的元素位置‘2' in Quarter 使用in判断值是否存在Quarter.count ([1,2,3])  使用count()记录特定值出现的次数'* '.join(marxes)  使用join()转换为字符串sorted(marxes)/ marxes.sort()  使用sort()重新排列元素len(marxes)  使用len()获取长度>>> a = [1, 2, 3]>>> b = a.copy()>>> c = list(a)>>> d = a[:] 使用=赋值,使用copy()复制

需要注意extend是将后面的list中的元素,遍历出来放到前面list中,而append是直接将后面的list作为一个list放在源list后面

list = ['1','2','3','4']list.append(['5','6'])print(list)list = ['1','2','3','4']list.extend(['5','6'])print(list)list = ['1','2','3','4']list = list.extend(['5','6'])print(list)######################['1', '2', '3', '4', ['5', '6']]['1', '2', '3', '4', '5', '6']None

注意:上面最后一次输出为什么是none,这是初学者很容易出现的问题,因为list的extend或者append函数,都是对源list进行修改,并没有返回值!

在使用list时,需要注意,从一个list A直接用=传给另外一个list B时,是浅拷贝,修改B会导致A也被修改,如果不想被修改,请使用A.copy()/A[:]

a = [1,'a','123']b = ac = a.copy() #a[:]这样也可以 因为.copy是深拷贝,创建一个新的list,#[:]切片操作呢是创建一个新的list来接受切片的返回值,所以都是创建一个新的,所以对原来的不会造成影响b[2] = 0c[1] = 2print(a,b,c)>>>[1, 'a', 0] [1, 'a', 0] [1, 2, '123']

注意copy对于list中嵌套的list可能有陷阱存在,因为嵌套进去的list其实是像是C的指针,指向真实的list

a = [1,2,[3]]b = a.copy()b[0] = 100print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))b[2][0] = [5]print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))# b[2][0] = [7]# print(a,b)print('##########################')c = [1,2,[3]]d = c.copy()d[0] = 100print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))d[2] = [5]print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))#################################[1, 2, [239120930912]] [100, 2, [239120930912]]2145076863816 2145076863816 2145076962192 2145076962192[1, 2, [[5]]] [100, 2, [[5]]]2145076863816 2145076863816 2145076875976 2145076875976##########################[1, 2, [3]] [100, 2, [3]]2145076877896 2145076877896 1902963216 1902963216[1, 2, [3]] [100, 2, [5]]2145076877896 2145076878088 1902963216 1902963280

我们可以从上面的输出结果看到,

a[2]的地址和b[2]完全一致,(2145076863816 2145076863816)

a[2][0]与b[2][0]存储的list真实地址也是同一个

a[2]此时存储的就是指向嵌套list的指针,而a[2][0]是嵌套list的真实地址。

所以我们看到,当我们对于b的嵌套list的修改时,造成a,b两个的值的变化,是因为,我们修改的是嵌套list真实值,(嵌套list的真实地址变化了,从2145076962192 变到2145076875976)。

而a[2]与b[2]这两个指针(实际是同一个指针)仍然指向的同一个list,只不过这个list本身的值被修改了,所以,a和b的值同时发生了变化。

而c,d这两个例子,当我们d[2] = [5]时,是将d[2]里面存储的指针改成了指向list[5]所在的地址,所以对于d[2]的修改,并没有造成c[2]的变化。

图有点丑,不过我想表达的意思已经表达出来了,当然也欢迎大触,来画一副更漂亮的图

切片产生的新list,并不是引用原来的list,可以放心修改,并不会对源list造成改变。

a = [1,2,3,4]b = a[0:2]b[1] = 100print(a,b)>>>[1, 2, 3, 4] [1, 100]

但是对于list嵌套list。仍然会存在陷阱。

a = [1,2,[3]]b = a[:]b[0] = 100print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))b[2][0] = [5]print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))# b[2][0] = [7]# print(a,b)print('##########################')c = [1,2,[3]]d = c[:]d[0] = 100print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))d[2] = [5]print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))#########################[1, 2, [3]] [100, 2, [3]]1686893585224 1686893585224 1902963216 1902963216[1, 2, [[5]]] [100, 2, [[5]]]1686893585224 1686893585224 1686893597384 1686893597384##########################[1, 2, [3]] [100, 2, [3]]1686893599176 1686893599176 1902963216 1902963216[1, 2, [3]] [100, 2, [5]]1686893599176 1686893599368 1902963216 1902963280

注意[]与list() []是代表生成一个list,而list()是将括号内的元祖,每个元素拿出来,充当list中的一个元素,而不是像[],将括号内的内容整个当做一个list的元素

a = list('cat')b = ['cat']print(a,b)['c', 'a', 't']['cat']

所以,新手容易遇到下面的报错问题

a = [1,2,3,4]print(a)print(a.index(1))b = list('1234')print(b)print(b.index('1'))list = ['abc']print(list.index('a'))###################[1, 2, 3, 4]0['1', '2', '3', '4']0##第三个是报错print(c.index('a'))ValueError: 'a' is not in list

上面已经解释了,[]生成的元素以,号为分隔符,看第二行a的输出,而list()这个函数,会将()里面的tuple遍历,每个元素作为list的一个元素,看第五行b的输出,如果想要第三个不报错。可以这样写c = list(‘abc’),这样c里面其实是[‘a’,’b’,’c’]

对copy补充

我们知道除了copy还是deepcopy 那么上面提到的copy陷阱还存在吗

import copya = [1,2,[3]]b = copy.deepcopy(a)b[0] = 100print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]))b[2][0] = [5]print(a,b)print(id(a[2]),id(b[2]),id(a[2][0]),id(b[2][0]),id(b[2][0][0]))# b[2][0] = [7]# print(a,b)print('##########################')c = [1,2,[3]]d = copy.deepcopy(c)d[0] = 100print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))d[2] = [5]print(c,d)print(id(c[2]),id(d[2]),id(c[2][0]),id(d[2][0]))#############################[1, 2, [3]] [100, 2, [3]]1873715484872 1873716953800 1902963216 1902963216[1, 2, [3]] [100, 2, [[5]]]1873715484872 1873716953800 1902963216 1873716953736 1902963280##########################[1, 2, [3]] [100, 2, [3]]1873716953672 1873716953480 1902963216 1902963216[1, 2, [3]] [100, 2, [5]]1873716953672 1873716953416 1902963216 1902963280

首先,我们可以直观的看到,调用deepcopy后,a[2]与b[2]中的指针变化了!但是两个不同的指针却指向同一个list地址(第一行的输出 a[2][0]和b[2][0] 都是1902963216),

在对b[2][0]重新赋值后,b[2][0]变成了list类型,存储了指向b[2][0][0]的指针,在图上可以看到,18开头数字更长的是type是list,而19开头,更短的是int类型。

c,d的变化和调用copy一样

元组

与列表类似,元组也是由任意类型元素组成的序列。与列表不同的是,元组是不可变

的,这意味着一旦元组被定义,将无法再进行增加、删除或修改元素等操作。因此,
元组就像是一个常量列表。

>>> empty_tuple = ()>>> empty_tuple()

创建

创建包含一个或多个元素的元组时,每一个元素后面都需要跟着一个逗号,即使只包

含一个元素也不能省略:

>>> weekdays='星期一',>>> weekdays('星期一’,)

如果创建的元组所包含的元素数量超过1,最后一个元素后面的逗号可以省略,采用tuple来创建也可以省略,号:

>>> weekdays='星期一','星期二','星期三'>>> weekdays('星期一', '星期二', '星期三')>>>a = tuple('1')('1',)

Python 的交互式解释器输出元组时会自动添加一对圆括号。你并不需要这么做——

定义元组真正靠的是每个元素的后缀逗号——但如果你习惯添加一对括号也无可厚非。
可以用括号将所有元素包裹起来,这会使得程序更加清晰:

>>> weekdays=('星期一','星期二','星期三')>>> weekdays('星期一', '星期二', '星期三’)>>> Monday ,Tuesday,Wednesday = weekdays>>> Monday'星期一'

请思考以下小问题:下面的1,2,3 是什么类型 ?

a,b,c = 1,2,3print(a,b,c)

请看下面例子

a,b,c = 1,2,3print(a,b,c)d = 1,2,3print(type((1,2,3)))e,f,g = (1,2,3)print(e,f,g)##############1 2 3<class 'tuple'>1 2 3

我们可以看到,d的类型是tuple,那么1,2,3的类型就是tuple,后面的(1,2,3) 这个写法可能看起来更明确像tuple。我们回顾之前给出的定义

定义元组真正靠的是每个元素的后缀逗号

a,b,c = [5,6,[1,2,3]]print(a,b,c)

有同学说我想直接让c取出来的值为2,而不是像现在取出来的是list

#解1a,b,(e,c,f)= [5,6,[1,2,3]]print(c)#解2 直接在原数据上做修改 这种做法不太通用 a,b,c= [5,6,[1,2,3][1]]print(c)

字典

字典(dictionary)与列表类似,但其中元素的顺序无关紧要,因为它们不是通过像0 或1的偏移量访问的。取而代之,每个元素拥有与之对应的互不相同的键(key),需要通过键来访问元素。键通常是字符串,但它还可以是Python 中其他任意的不可变类型:布尔型、整型、浮点型、元组、字符串,以及其他一些在后面的内容中会见到的类型。字典是可变的,因此你可以增加、删除或修改其中的键值对。

>>> empty_dict = {}>>> empty_dict,type(empty_dict){} <class 'dict'>
>>> e2cn={'apple':'苹果,是一种很甜的水果','cat':'猫,一种很可爱的动物'}>>> e2cn{'apple': '苹果,是一种很甜的水果', 'cat': '猫,一种很可爱的动物’}

可以用dict() 将包含双值子序列的序列转换成字典

>>> lol = [ ['a', 'b'], ['c', 'd'], ['e', 'f'] ]>>> dict(lol){'c': 'd', 'a': 'b', 'e': 'f'}>>>d = dict(["ab", "cd", "ef"]){'a': 'b', 'c': 'd', 'e': 'f'} #可以把字符串转为字典,但是必须每个字符串长度为2
>>> name = {... '三' : '张',... '四' : '李',... '小明': '王',... '小红': '张'... }>>> name{'三': '张', '四': '李', '小明': '王', '小红': '张'}>>> name['二狗']='李'>>> name{'三': '张', '四': '李', '小明': '王', '小红': '张', '二狗': '李'}>>> name2 = {'小红':'王','三丰':'张'}>>> name.update(name2)>>> name{'三': '张', '四': '李', '小明': '王', '小红': '王', '二狗': '李', '三丰': '张'}#update会将name中没有的键值对复制进来,但是如果name2中存在key一样,value却不一致的情况,那么value会被更新成name2中的值,#其实可以看做key相同,则覆盖;如果没有,则追加。>>>name['二狗'] = '王'

常用操作

del name[‘三丰’] 使用del删除具有指定键的元素name.clear() 使用clear()删除所有元素‘小红' in name 使用in判断是否存在name[‘小红’] 使用[key]获取元素name.keys() 使用keys()获取所有键name.values() 使用values()获取所有值name.items() 使用items()获取所有键值对

遍历字典

d = dict(["ab", "cd", "ef"])for item in d.items():    print(item,type(item))for k,v in d.items():    print(k,v)for a in d:    print(a)#################################('a', 'b') <class 'tuple'>('c', 'd') <class 'tuple'>('e', 'f') <class 'tuple'>a bc de face

可以看出,.items()是把字典中的kv对,以tuple的形式拿出来。第二种遍历,则是直接把key,value取出来进行多元赋值。第三种注意,只能取出key。

d = dict(["ab", "cd", "ef"])print(d.get('a','不存在'))print(d.get('d'))print(d.get('d','不存在'))##################bNone不存在

在取值的时候,为了避免报错,我们可以采用get来取值,而不是直接d[‘xxx’]。用get取值,不存在时,默认输出none,可以自定义不存在时的输出结果。

下面是一个小坑,需要注意

d2 = {"name":"zhangsan", "age":23, "salary":6500.0}d5 = d2print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))d5["salary"] = 11000print(d2["salary"])print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))#########################2081072900640 2081072900640 2081071833544 2081071833544110002081072900640 2081072900640 2081071804112 2081071804112

惯例,我们用图说话

由此我们可以看出,d5[“salary”] = 11000,改变的是指针指向的真实地址,而d2与d5的salary键指针是一样的.

排序

d6 = {"a1":["m1", 23], "c1":["n1", 20], "b1":["n1",22]}#按照key排序d7 = sorted(d6.items()) #对dict排序,一定使用dict.items()#按照value中的第2个元素排序d8 = sorted(d6.items(), key=lambda x:x[1][1])   #x表示tuple,那么x[1][1]表示value中的第2个元素print(d8)

集合

集合就像舍弃了值,仅剩下键的字典一样。键与键之间也不允许重复。如果你仅仅想知道

某一个元素是否存在而不关心其他的,使用集合是个非常好的选择。如果需要为键附加其
他信息的话,建议使用字典。

>>> empty_set = set()>>> empty_setset()>>> even_numbers = {0, 2, 4, 6, 8}>>> even_numbers{0, 8, 2, 4, 6}>>> odd_numbers = {1, 3, 5, 7, 9}>>> odd_numbers{9, 3, 1, 5, 7}

常用操作

set( 'letters’ ) 使用set()将其他类型转换为集合set([1,2,3,4,5]) 用列表建立集合set((‘a’,‘b’,‘c’,‘d’)) 用元组建立集合set(name) 当字典作为参数传入set() 函数时,只有键会被使用s.add( x )  将元素 x 添加到集合s中,若重复则不进行任何操作update( x ) 将集合 x 并入原集合s中discard( x ) 将 x 从集合s中移除,若x不存在,不会引发错误remove( x )  将 x 从集合s中移除,若x不存在,会引发错误pop()  集合无序,所以随机删除并返回集合s中某个值x in s set同样支持in操作

合并及运算符

>>> a = {1, 2}>>> b = {2, 3}>>> a & b{2}>>> a.intersection(b){2}>>> a | b{1, 2, 3}>>> a.union(b){1, 2, 3}>>> a - b{1}>>> a.difference(b){1}>>> a ^ b{1, 3}>>> a.symmetric_difference(b){1, 3}>>> a <= bFalse>>> a.issubset(b)False>>> a <= aTrue>>> a.issubset(a)True
原创粉丝点击