python -- 元素和容器

元素和容器

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

列表

创建

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()  如果不指定,默认弹出最后一个原始,即默认传入-1
Quarter.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 = a
c = a.copy() 
#a[:]这样也可以 因为.copy是深拷贝,创建一个新的list,
#[:]切片操作呢是创建一个新的list来接受切片的返回值,所以都是创建一个新的,所以对原来的不会造成影响
b[2] = 0
c[1] = 2
print(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] = 100
print(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] = 100
print(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] = 100
print(a,b)
>>>[1, 2, 3, 4] [1, 100]

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

a = [1,2,[3]]
b = a[:]
b[0] = 100
print(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] = 100
print(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 copy

a = [1,2,[3]]
b = copy.deepcopy(a)
b[0] = 100
print(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] = 100
print(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,3
print(a,b,c)

请看下面例子

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

d = 1,2,3
print(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

#解1
a,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 b
c d
e f
a
c
e

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

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

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

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

d2 = {"name":"zhangsan", "age":23, "salary":6500.0}
d5 = d2
print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))
d5["salary"] = 11000
print(d2["salary"])
print(id(d2), id(d5),id(d2['salary']),id(d5['salary']))
#########################
2081072900640 2081072900640 2081071833544 2081071833544
11000
2081072900640 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_set
set()
>>> 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 <= b
False
>>> a.issubset(b)
False
>>> a <= a
True
>>> a.issubset(a)
True
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值