在平时python web开发中,经常会使用list和tuple,下面对于这两个的使用以及区别做一下整理。

list

list是一种有序的集合,可以随时添加和删除其中的元素。

交集、并集和差集:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [2, 5, 8, 11, 0]

# intersection
intersection = list(set(a).intersection(set(b)))
# union
union = list(set(a).union(set(b)))
# difference
difference = list(set(a).difference(set(b)))

当然也可以用list表达式,但是如果list较大的话,效率上要存在问题。

append、extend和insert:
– append() 追加单个元素到List的尾部,只接受一个参数,参数可以是任何数据类型,被追加的元素在List中保持着原结构类型

In [1]: l1 = [1,2,3,4]
In [2]: l2 = [5,6,7]
In [3]: l1.append(l2)
In [4]: l1
Out[4]: [1, 2, 3, 4, [5, 6, 7]]
  • extend() 将一个列表中每个元素分别添加到另一个列表中,只接受一个参数
In [5]: l3 = [1,2,3,4]
In [6]: l4 = [5,6,7]
In [7]: l3.extend(l4)
In [8]: l3
Out[8]: [1, 2, 3, 4, 5, 6, 7]
  • insert是在某个位置插入一个元素
In [9]: l5 = [1,2,3,4]
In [10]: l5.insert(1, 9)
In [11]: l5
Out[11]: [1, 9, 2, 3, 4]

浅拷贝和深拷贝:
对于浅拷贝:
1、对于 不可 变类型 Number String Tuple,浅复制仅仅是地址指向,不会开辟新空间。
2、对于 可 变类型 List、Dictionary、Set,浅复制会开辟新的空间地址(仅仅是最顶层开辟了新的空间,里层的元素地址还是一样的),进行浅拷贝
3、浅拷贝后,改变原始对象中为可变类型的元素的值,会同时影响拷贝对象的;改变原始对象中为不可变类型的元素的值,只有原始类型受影响。 (操作拷贝对象对原始对象的也是同理)

import copy

l1 = [11, 12]
l2 = [21, 22]
num = 555

allOne = [l1, l2,num]

# 浅拷贝,创建出一个对象,并把旧对象元素的 引用地址 拷贝到新对象当中。
# 也就是说,两个对象里面的元素通过浅拷贝指向的还是同一个地址
allOne2 = copy.copy(allOne)

l1[0] = 16   # 此处修改,会使得 allOne 和 allOne2的第0个元素的值都发生改变,因为l1是List,是可变对象
allOne[2] = 666   # 此处修改,只会allOne的num的值,因为不可变对象一旦重新复制,地址就会发生改变。(不可变嘛)

num = 777   # 此处不会改变 allOne 和 allOne2的值,因为相当于 777 复制给一个全新的地址,这个num跟其他num已经没关系了

print(allOne)
print(allOne2)

print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))

print("===")
print("id allOne2:"+str(id(allOne2)))
print("id allOne2[0]:"+str(id(allOne2[0])))
print("id allOne2[1]:"+str(id(allOne2[1])))
print("id allOne2[2]:"+str(id(allOne2[2])))

输出如下:

[[16, 12], [21, 22], 666]
[[16, 12], [21, 22], 555]
id allOne:4467341640
id allOne[0]:4471819912
id allOne[1]:4467342920
id allOne[2]:4466847696
===
id allOne2:4471820232
id allOne2[0]:4471819912
id allOne2[1]:4467342920
id allOne2[2]:4466081744

对于深拷贝:
1、浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)
2、经过深拷贝后,原始对象和拷贝对象所有的子元素地址都是独立的了
3、可以用分片表达式进行深拷贝
4、字典的copy方法可以拷贝一个字典

import copy

l1 = [11, 12]
l2 = [21, 22]
num = 555

allOne = [l1, l2,num]

# 浅拷贝,除了顶层拷贝,还对子元素也进行了拷贝(本质上递归浅拷贝)
# 经过深拷贝后,原始对象和拷贝对象所有的元素地址都没有相同的了
allOne2 = copy.deepcopy(allOne) # copy.deepcopy 深拷贝

allOne[1] = [113,114]
allOne2[2] = [227,228]

print(allOne)
print(allOne2)

print("id allOne:"+str(id(allOne)))
print("id allOne[0]:"+str(id(allOne[0])))
print("id allOne[1]:"+str(id(allOne[1])))
print("id allOne[2]:"+str(id(allOne[2])))

print("===")
print("id allOne2:"+str(id(allOne2)))
print("id allOne2[0]:"+str(id(allOne2[0])))
print("id allOne2[1]:"+str(id(allOne2[1])))
print("id allOne2[2]:"+str(id(allOne2[2])))

输出如下:

[[11, 12], [113, 114], 555]
[[11, 12], [21, 22], [227, 228]]
id allOne:4549589640
id allOne[0]:4554067720
id allOne[1]:4554067848
id allOne[2]:4548329424
===
id allOne2:4554067912
id allOne2[0]:4554067784
id allOne2[1]:4554067592
id allOne2[2]:4554100808

tuple

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改。

关于只有一个元素的tuple,注意下面两个写法:

>>> t = (1)
>>> t
1

>>> t = (1,)
>>> t
(1,)

第一种写法结果是1,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。
第二种写法才表示只有一个元素的tuple,只有1个元素的tuple定义时必须加一个逗号,

关于可变的tuple:

>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])

我们先看看定义的时候tuple包含的3个元素:

当我们把list的元素’A’和’B’修改为’X’和’Y’后,tuple变为:

表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!

关于namedtuple:
对于以下元组:

>>> s = ('Jack', 21, 'male', '5788666@qq.com')

要得到该对象的名字,年龄,性别及邮箱的方法为:s[0],s[1],s[2],s[3]。那么如果程序中充斥了大量的这种没有意义的索引数字,则会影响代码的可读性,可以考虑通过namedtuple来增加代码可读性:

>>> from collections import namedtuple
>>> Student = namedtuple('Student', ['name', 'age', 'sex', 'email'])
>>> s = Student('Jim', 21, 'male', '123@qq.com')
>>> s.name
'Jim'
>>> s.age
21

参考

1、python中如何对list之间求交集,并集和差集
2、python3浅拷贝与深拷贝的区别和理解
3、python 高级进阶之命名元组

发表评论

电子邮件地址不会被公开。 必填项已用*标注