创建列表
在 Python 中,列表 list
是一个有序的序列。
列表用一对 []
生成,中间的元素用 ,
隔开,其中的元素不需要是同一类型,同时列表的长度也不固定。
l = [1, 2.0, 'hello']
l
[1, 2.0, 'hello']
empty_list = []
empty_list
[]
空列表可以用 []
或者 list()
生成:
empty_list = list()
empty_list
[]
列表可以通过其他数据类型强制转换得到,例如元组:
t = (1, 2, 3)
list(t)
[1, 2, 3]
列表操作
与字符串类似,列表也支持以下的操作:
长度
用 len
查看列表长度:
len(l)
3
加法和乘法
列表加法,相当于将两个列表按顺序连接:
a = [1, 2, 3]
b = [3.2, 'hello']
a + b
[1, 2, 3, 3.2, 'hello']
列表与整数相乘,相当于将列表重复相加:
l * 2
[1, 2.0, 'hello', 1, 2.0, 'hello']
索引和切片
列表和字符串一样可以通过索引和分片来查看它的元素。
索引:
a = [10, 11, 12, 13, 14]
a[0]
10
反向索引:
a[-1]
14
分片:
a[2:-1]
[12, 13]
与字符串不同的是,列表的元素可以通过索引来修改:
a = [10, 11, 12, 13, 14]
a[0] = 100
a
[100, 11, 12, 13, 14]
这种赋值也适用于分片,例如,将列表的第2,3两个元素换掉:
a[1:3] = [1, 2]
a
[100, 1, 2, 13, 14]
事实上,对于连续的分片(即步长为 $1$),Python 采用的是整段替换的方法,两者的元素个数并不需要相同,例如,将 [11,12]
替换为 [1, 2, 3, 4]
:
a = [10, 11, 12, 13, 14]
a[1:3] = [1, 2, 3, 4]
a
[10, 1, 2, 3, 4, 13, 14]
这意味着,可以用这种方法来删除列表中一个连续的分片:
a = [10, 1, 2, 11, 12]
a[1:3] = []
a
[10, 11, 12]
对于不连续(间隔 step
不为 $1$)的片段进行修改时,两者的元素数目必须一致:
a = [10, 11, 12, 13, 14]
a[::2] = [1, 2, 3]
a
[1, 11, 2, 13, 3]
删除元素
Python 提供了删除列表中元素的方法 del
。
删除列表中的第一个元素:
a = [1002, 'a', 'b', 'c']
del a[0]
a
['a', 'b', 'c']
删除第二到最后一个元素:
a = [1002, 'a', 'b', 'c']
del a[1:]
a
[1002]
删除间隔的元素:
a = ['a', 1, 'b', 2, 'c']
del a[::2]
a
[1, 2]
测试从属关系
用 in
来看某个元素是否在某个序列(不仅仅是列表)中,用 not in
来判断是否不在某个序列中。
a = [10, 11, 12, 13, 14]
10 in a, 11 not in a
(True, False)
也可以作用于字符串:
s = 'hello world'
'he' in s, 'world' not in s
(True, False)
列表中可以包含各种对象,甚至可以包含列表:
a = [10, 'eleven', [12, 13]]
a[2]
[12, 13]
a[2]
是列表,可以对它再进行索引:
a[2][1]
13
列表方法
不改变列表的方法
列表中某个元素个数 count
l.count(ob)
返回列表中元素 ob
出现的次数。
a = [11, 12, 13, 12, 11]
a.count(11)
2
列表中某个元素位置 index
l.index(ob)
返回列表中元素 ob
第一次出现的索引位置,如果 ob
不在 l
中会报错。
a.index(12)
1
改变列表的方法
向列表添加单个元素
l.append(ob)
将元素 ob
添加到列表 l
的最后。
a = [10, 11, 12]
a.append(11)
a
[10, 11, 12, 11]
append
每次只添加一个元素,并不会因为这个元素是序列而将其展开:
a.append([11, 12])
a
[10, 11, 12, 11, [11, 12]]
向列表添加序列
l.extend(lst)
将序列 lst
的元素依次添加到列表 l
的最后,作用相当于 l += lst
。
a = [10, 11, 12, 11]
a.extend([1, 2])
a
[10, 11, 12, 11, 1, 2]
插入元素
l.insert(idx, ob)
在索引 idx
处插入 ob
,之后的元素依次后移。
a = [10, 11, 12, 13, 11]
# 在索引 3 插入 'a'
a.insert(3, 'a')
a
[10, 11, 12, 'a', 13, 11]
移除元素
l.remove(ob)
会将列表中第一个出现的 ob
删除,如果 ob
不在 l
中会报错。
a = [10, 11, 12, 13, 11]
# 移除了第一个 11
a.remove(11)
a
[10, 12, 13, 11]
弹出元素
l.pop(idx)
会将索引 idx
处的元素删除,并返回这个元素。
a = [10, 11, 12, 13, 11]
a.pop(2)
12
列表排序
l.sort()
会将列表中的元素按照一定的规则排序:
a = [10, 1, 11, 13, 11, 2]
a.sort()
a
[1, 2, 10, 11, 11, 13]
也可以降序排列:
a.sort(reverse=True)
a
[13, 11, 11, 10, 2, 1]
如果不想改变原来列表中的值,可以使用sorted
函数:
a = [10, 1, 11, 13, 11, 2]
b = sorted(a)
print('a =', a)
print('b =', b)
a = [10, 1, 11, 13, 11, 2]
b = [1, 2, 10, 11, 11, 13]
还可以利用 lambda
表达式对一些复杂的数据类型进行排序,例如下面的例子是按照年龄排序:
data_list = [
{'Name': 'ABC', 'Age': 17},
{'Name': 'DEF', 'Age': 19},
{'Name': 'GHI', 'Age': 16},
{'Name': 'JKL', 'Age': 18}
]
sorted(data_list, key=lambda x:x['Age'])
[{'Name': 'GHI', 'Age': 16},
{'Name': 'ABC', 'Age': 17},
{'Name': 'JKL', 'Age': 18},
{'Name': 'DEF', 'Age': 19}]
甚至可以对具有多个属性的对象进行主次关键字排序:
import operator
class Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def __str__(self):
return 'Name: {}, Age: {}, Grade: {}'.format(self.name, \
self.age, self.grade)
定义比较函数,先按成绩排序再按年龄排序:
cmpfun = operator.attrgetter('grade', 'age')
验证结果:
student_list = [
Student('ABC', 17, 90),
Student('DEF', 19, 85),
Student('GHI', 16, 90),
Student('JKL', 18, 95)
]
student_list.sort(key=cmpfun)
for i in student_list:
print(i)
Name: DEF, Age: 19, Grade: 85
Name: GHI, Age: 16, Grade: 90
Name: ABC, Age: 17, Grade: 90
Name: JKL, Age: 18, Grade: 95
列表反向
l.reverse()
会将列表中的元素从后向前排列。
a = [1, 2, 3, 4, 5, 6]
a.reverse()
a
[6, 5, 4, 3, 2, 1]
如果不想改变原来列表中的值,可以使用切片的方法:
a = [1, 2, 3, 4, 5, 6]
b = a[::-1]
print('a =', a)
print('b =', b)
a = [1, 2, 3, 4, 5, 6]
b = [6, 5, 4, 3, 2, 1]
列表推导式
循环可以用来生成列表:
values = [10, 21, 4, 7, 12]
squares = []
for x in values:
squares.append(x**2)
squares
[100, 441, 16, 49, 144]
列表推导式可以使用更简单的方法来创建这个列表:
values = [10, 21, 4, 7, 12]
squares = [x**2 for x in values]
squares
[100, 441, 16, 49, 144]
还可以在列表推导式中加入条件进行筛选。例如在上面的例子中,假如只想保留列表中不大于 $10$ 的数的平方:
values = [10, 21, 4, 7, 12]
squares = [x**2 for x in values if x <= 10]
squares
[100, 16, 49]
也可以使用推导式生成集合和字典:
square_set = {x**2 for x in values if x <= 10}
square_set
{16, 49, 100}
square_dict = {x: x**2 for x in values if x <= 10}
square_dict
{10: 100, 4: 16, 7: 49}
再如,计算上面例子中生成的列表中所有元素的和:
total = sum([x**2 for x in values if x <= 10])
total
165
但是,Python 会生成这个列表,然后在将它放到垃圾回收机制中(因为没有变量指向它),这毫无疑问是种浪费。
为了解决这种问题,与 xrange()
类似,Python 使用产生式表达式来解决这个问题:
total = sum(x**2 for x in values if x <= 10)
total
165
与上面相比,只是去掉了括号,但这里并不会一次性的生成这个列表。
x = range(1000000)
比较一下两者的用时:
%timeit total = sum([i**2 for i in x])
268 ms ± 717 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit total = sum(i**2 for i in x)
259 ms ± 53.9 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)