列表
列表(list
),是一种结构化的、非标量类型,它的值是有序序列,每个值都可以通过索引进行标识。
列表定义
- 列表用 [ ] 表示,是有序集合,索引从0开始,最后一个索引可用 -1 表示
- 列表是一种序列类型,创建后可以随意被修改
- 使用方括号 [ ] 或 list() 创建,元素间用逗号 , 分隔
- 列表中各元素类型可以不同,无长度限制
- 方括号 [ ] 真正创建一个列表,赋值仅传递引用
列表类型操作函数和方法
方法名称 | 功能 |
---|---|
s[i] = x | 替换列表s第i元素为x |
ls[i: j: k] = lt | 用列表lt替换ls切片后所对应元素子列表 |
ls += lt | 更新列表ls,将列表lt元素增加到列表ls中 |
*ls = n | 更新列表ls,其元素重复n次 |
ls.clear() | 删除列表ls中所有元素 |
ls.copy() | 生成一个新列表,赋值ls中所有元素 |
ls.insert(i,x) | 在列表ls的第i位置增加元素x |
ls.pop(i) | 将列表ls中第i位置元素取出并删除该元素,默认返回最后元素 |
ls.remove(x) | 将列表ls中出现的第一个元素x删除 |
ls.reverse() | 将列表ls中的元素反转 |
ls.extend() | 将多个值附加到列表末尾;拼接不修改原来序列的值,但是extend修改;a[len(a) : ] = b效果同extend; |
append() | 在末尾直接添加 |
del() | 如果知道索引,可用del |
sort() | 永久对原列表排序,不返回排序后列表的副本; sort(reverse = True) 反序 |
sorted() | 临时排序,返回排序后列表的副本、reverse():永久反转列表元素,不返回任何值 |
sort(key,reverse) | 将其设置为一个用于排序的函数; reverse(True、False) 是否按相反顺序对列表排序 |
遍历整个列表
for 变量名 in 列表名:
每个缩进代码行都是循环一部分
复制列表
同时省略起始和终止索引,eg、 player[:] ;如果只是将变量复制,两个变量将同时指向同一个列表;或者调用方法 copy(); 或者 list(列表名)
列表切片
- 支持正向索引(0)和负向索引(-1);
- 默认步长为1;
#格式:
li[start : end : step]
#start是切片起点索引,end是切片终点索引,但切片结果不包括终点索引的值。step是步长默认是1。
#在step的符号一定的情况下,start和end可以混合使用正向和反向索引,无论怎样,你都要保证
#start和end之间有和step方向一致元素间隔,否则会切出空列表
li=["A","B","C","D"]
t=li[0:2]
t=li[0:-2]
t=li[-4:-2]
t=li[-4:2]
#上面的结果都是一样的;t为["A","B"]
2
3
4
5
6
7
8
9
10
11
12
t=li[-1:-3:-1]
t=li[-1:1:-1]
t=li[3:1:-1]
t=li[3:-3:-1]
#上面的结果都是一样的;t为["D","C"]
2
3
4
5
t=li[-1:-3]
t=li[-1:1]
t=li[3:1]
t=li[3:-3]
#都切出空列表
2
3
4
5
#省略start 和 end表示以原列表全部为目标
t=li[::-1] t--->["C","B","A"] #反向切,切出全部
t=li[:] t--->["A","B","C","D"] #正向切全部
2
3
列表生成式
列表推导
列表推导可以帮助我们把一个序列或是其他可迭代类型中的元素过滤或是加工,然后再新建一个列表。Python 内置的 filter 和 map 函数组合起来也能达到这一效果,但是可读性上打了不小的折扣。
>>> colors = ['black', 'white'] >>> sizes = ['S', 'M', 'L'] >>> tshirts = [(color, size) for color in colors for size in sizes] >>> tshirts [('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]
1
2
3
4
5
6
7
8
9
10
11生成器表达式
虽然也可以用列表推导来初始化元组、数组或其他序列类型,但是生成器表达式是更好的选择。这是因为生成器表达式背后遵守了迭代器协议,可以逐个地产出元素,而不是先建立一个完整的列表,然后再把这个列表传递到某个构造函数里。前面那种方式显然能够节省内存。
生成器表达式的语法跟列表推导差不多,只不过把方括号换成圆括号而已。
>>> symbols = '$¢£¥€¤' >>> tuple(ord(symbol) for symbol in symbols) (36, 162, 163, 165, 8364, 164)
1
2
3
4
5如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环:
>>> L = [] >>> for x in range(1, 11): ... L.append(x * x) ... >>> L [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
1
2
3
4
5
6但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:
>>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
1
2写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来
for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
[x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100]
1
2还可以使用两层循环,可以生成全排列:
[m + n for m in 'ABC' for n in 'XYZ'] ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
1
2列表生成式也可以使用两个变量来生成list:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> [k + '=' + v for k, v in d.items()] ['y=B', 'x=A', 'z=C']
1
2
3
4if ... else
以下代码正常输出偶数:
>>> [x for x in range(1, 11) if x % 2 == 0] [2, 4, 6, 8, 10]
1
2但是,我们不能在最后的if加上else:
>>> [x for x in range(1, 11) if x % 2 == 0 else 0] File "<stdin>", line 1 [x for x in range(1, 11) if x % 2 == 0 else 0] SyntaxError: invalid syntax
1
2
3
4
5这是因为跟在for后面的if是一个筛选条件,不能带else,否则如何筛选?
另一些童鞋发现把if写在for前面必须加else,否则报错:
>>> [x if x % 2 == 0 for x in range(1, 11)] File "<stdin>", line 1 [x if x % 2 == 0 for x in range(1, 11)] ^ SyntaxError: invalid syntax
1
2
3
4
5
6这是因为for前面的部分是一个表达式,它必须根据x计算出一个结果。因此,考察表达式:x if x % 2 == 0,它无法根据x计算出结果,因为缺少else,必须加上else:
>>> [x if x % 2 == 0 else -x for x in range(1, 11)] [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
1
2上述for前面的表达式x if x % 2 == 0 else -x才能根据x计算出确定的结果。可见,在一个列表生成式中,for前面的if ... else是表达式,而for后面的if是过滤条件,不能带else。连接列表代价更高,因为创建了一个新列表,并复制了对象。
下面的代码演示了如何定义列表、如何遍历列表以及列表的下标运算。
list1 = [1, 3, 5, 7, 100]
print(list1) # [1, 3, 5, 7, 100]
# 乘号表示列表元素的重复
list2 = ['hello'] * 3
print(list2) # ['hello', 'hello', 'hello']
# 计算列表长度(元素个数)
print(len(list1)) # 5
# 下标(索引)运算
print(list1[0]) # 1
print(list1[4]) # 100
# print(list1[5]) # IndexError: list index out of range
print(list1[-1]) # 100
print(list1[-3]) # 5
list1[2] = 300
print(list1) # [1, 3, 300, 7, 100]
# 通过循环用下标遍历列表元素
for index in range(len(list1)):
print(list1[index])
# 通过for循环遍历列表元素
for elem in list1:
print(elem)
# 通过enumerate函数处理列表之后再遍历可以同时获得元素索引和值
for index, elem in enumerate(list1):
print(index, elem)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
下面的代码演示了如何向列表中添加元素以及如何从列表中移除元素。
list1 = [1, 3, 5, 7, 100]
# 添加元素
list1.append(200)
list1.insert(1, 400)
# 合并两个列表
# list1.extend([1000, 2000])
list1 += [1000, 2000]
print(list1) # [1, 400, 3, 5, 7, 100, 200, 1000, 2000]
print(len(list1)) # 9
# 先通过成员运算判断元素是否在列表中,如果存在就删除该元素
if 3 in list1:
list1.remove(3)
if 1234 in list1:
list1.remove(1234)
print(list1) # [1, 400, 5, 7, 100, 200, 1000, 2000]
# 从指定的位置删除元素
list1.pop(0)
list1.pop(len(list1) - 1)
print(list1) # [400, 5, 7, 100, 200, 1000]
# 清空列表元素
list1.clear()
print(list1) # []
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
和字符串一样,列表也可以做切片操作,通过切片操作我们可以实现对列表的复制或者将列表中的一部分取出来创建出新的列表,代码如下所示。
fruits = ['grape', 'apple', 'strawberry', 'waxberry']
fruits += ['pitaya', 'pear', 'mango']
# 列表切片
fruits2 = fruits[1:4]
print(fruits2) # apple strawberry waxberry
# 可以通过完整切片操作来复制列表
fruits3 = fruits[:]
print(fruits3) # ['grape', 'apple', 'strawberry', 'waxberry', 'pitaya', 'pear', 'mango']
fruits4 = fruits[-3:-1]
print(fruits4) # ['pitaya', 'pear']
# 可以通过反向切片操作来获得倒转后的列表的拷贝
fruits5 = fruits[::-1]
print(fruits5) # ['mango', 'pear', 'pitaya', 'waxberry', 'strawberry', 'apple', 'grape']
2
3
4
5
6
7
8
9
10
11
12
13
下面的代码实现了对列表的排序操作。
list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
list2 = sorted(list1)
# sorted函数返回列表排序后的拷贝不会修改传入的列表
# 函数的设计就应该像sorted函数一样尽可能不产生副作用
list3 = sorted(list1, reverse=True)
# 通过key关键字参数指定根据字符串长度进行排序而不是默认的字母表顺序
list4 = sorted(list1, key=len)
print(list1)
print(list2)
print(list3)
print(list4)
# 给列表对象发出排序消息直接在列表对象上进行排序
list1.sort(reverse=True)
print(list1)
2
3
4
5
6
7
8
9
10
11
12
13
14
我们还可以使用列表的生成式语法来创建列表,代码如下所示。
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17