《python可以这样学》第二章

Python序列

列表与列表推导式

列表创建与删除

创建列表对象

>>> a_list = list((3, 5, 7, 9, 11))
>>> a_list = []         #创建空列表

list()函数

将元组、range对象、字符串、字典、集合、或其他类型的可迭代对象类型的数据转换为列表

将元组转换为列表

>>> a_list = list((3, 5, 7, 9, 11))
>>> a_list
[3, 5, 7, 9, 11]

 将range对象转换为列表

>>> list(range(1, 10, 2))
[1, 3, 5, 7, 9]

将字符串转换为列表

>>> list('hello world')
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']

 将集合转换为列表

>>> list({3, 7, 5})
[3, 5, 7]

将字典的“键”转换为列表

>>> list({'a':3, 'b':9, 'c':78})
['a', 'b', 'c']

 将字典的“键:值”对转换为列表

>>> list({'a':3, 'b':9, 'c':78}.items())
[('a', 3), ('b', 9), ('c', 78)]

 正向索引和反向索引

>>> x = list(range(10))       #创建列表
>>> import random
>>> random.shuffle(x)         #把列表中的元素打乱顺序
>>> x
[0, 7, 5, 9, 1, 2, 4, 8, 6, 3]
>>> x[0]
0
>>> x[1]
7
>>> x[-1]
3
>>> x[-2]
6

 del命令删除列表、字典等可变序列中的部分元素,而不能删除元组、字符串等不可变序列中的部分元素

删除列表中指定位置的元素和列表对象

>>> x = [1, 2, 3]
>>> del x[1]
>>> x
[1, 3]
>>> 
>>> del x
>>> x
Traceback (most recent call last):
  File "<pyshell#87>", line 1, in <module>
    x
NameError: name 'x' is not defined

 删除字典中部分元素

>>> x = {'a':3, 'b':6, 'c':9}
>>> del x['a']
>>> x
{'b': 6, 'c': 9}

不允许删除和修改元组中的元素

>>> x = (1, 2, 3)
>>> del x[0]
Traceback (most recent call last):
  File "<pyshell#95>", line 1, in <module>
    del x[0]
TypeError: 'tuple' object doesn't support item deletion
>>> x[0] = 4
Traceback (most recent call last):
  File "<pyshell#96>", line 1, in <module>
    x[0] = 4
TypeError: 'tuple' object does not support item assignment

列表常用方法

1、append()、insert()、extend()

向列表尾部追加一个元素

append()

>>> x = [1, 2, 3]
>>> id(x)
46775496
>>> x.append(4)
>>> x
[1, 2, 3, 4]

任意指定位置插入一个元素

insert()

>>> x
[1, 2, 3, 4]
>>> 
>>> x.insert(0, 0)
>>> x
[0, 1, 2, 3, 4]
>>> x.insert(3, 3.5)
>>> x
[0, 1, 2, 3.5, 3, 4]

将另一个列表中的所有元素追加至当前列表的尾部

extend()

在尾部追加多个元素

列表在内存中的地址不变

>>> x.extend([5, 6, 7])
>>> x
[0, 1, 2, 3.5, 3, 4, 5, 6, 7]
>>> id(x)
46775496

增加元素,返回新列表

>>> x = [1, 2, 3]
>>> id(x)
45846344
>>> x = x + [4]
>>> x
[1, 2, 3, 4]
>>> id(x)
46750984
>>> x = x * 2
>>> x
[1, 2, 3, 4, 1, 2, 3, 4]
>>> id(x)
46749064

2、pop()、remove()、clear()

删除并返回指定位置(默认是最后一个)上的元素

 pop()

弹出并返回尾部元素

>>> x = [1, 2, 3, 4, 5, 6, 7]
>>> x.pop()
7

 弹出并返回指定位置的元素(元素的下标已经发生改变)

>>> x.pop(0)
1
>>> 
>>> x.pop(3)
5
>>> 
>>> x.pop(1)
3
>>> x.pop(2)
6

删除所有元素

>>> x
[2, 4]
>>> 
>>> x.clear()
>>> 
>>> x
[]

删除列表中第一个值与指定值相等的元素

remove()

删除首个值为2的元素

>>> x = [1, 2, 1, 1, 2]
>>> x
[1, 2, 1, 1, 2]
>>> x.remove(2)
>>> x
[1, 1, 1, 2]

删除指定位置上的元素

>>> del x[3]
>>> x
[1, 1, 1]

3、count()、index()

返回列表中指定元素出现的次数

count()

>>> x = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
>>> x.count(3)
3
>>> x.count(5)
0

返回指定元素在列表中首次出现的位置,如果该元素不在列表中则抛出异常

>>> x.index(2)
1
>>> x.index(4)
6
>>> x.index(5)
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    x.index(5)
ValueError: 5 is not in list
>>> 
>>> 5 in x
False
>>> 3 in x
True
>>> 

4、sort()、reverse()

按照指定的规则对所有元素进行排序,默认规则是直接比较元素大小

sort()

随机乱序

>>> x = list(range(11))
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> import random
>>> random.shuffle(x)
>>> x
[0, 5, 1, 4, 9, 6, 8, 2, 10, 7, 3]

按指定规则排序

>>> x.sort(key = lambda item : len(str(item)), reverse = True)
>>> x
[10, 0, 5, 1, 4, 9, 6, 8, 2, 7, 3]

默认排序

>>> x.sort()
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

逆序

reverse()

>>> x.reverse()
>>> x
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

按转换为字符串后的大小排序

>>> x.sort(key = str)
>>> x
[0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]

5、sorted()和reversed()

内置函数sorted()返回新列表,内置函数reversed()返回一个逆序排列后的迭代对象,都不对原列表做任何修改。

>>> x = list(range(11))
>>> import random
>>> random.shuffle(x)     #打乱顺序
>>> x
[3, 9, 1, 10, 5, 8, 6, 7, 2, 4, 0]
>>> sorted(x)                 #默认排序
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> sorted(x, key = lambda item : len(str(item)), reverse = True)         #以指定规则排序   
[10, 3, 9, 1, 5, 8, 6, 7, 2, 4, 0]
>>> sorted(x, key = str)        
[0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
[3, 9, 1, 10, 5, 8, 6, 7, 2, 4, 0]
>>> reversed(x)                   #逆序
<list_reverseiterator object at 0x0000000002B1A630>
>>> list(reversed(x))
[0, 4, 2, 7, 6, 8, 5, 10, 1, 9, 3]

排序方法的key参数

>>> gameresult = [['bob', 95.0, 'A'], ['alan', 86.0, 'C'], ['mandy', 83.5, 'A'], ['rob', 89.3, 'E']]
>>> from operator import itemgetter

按子列表第三个元素进行升序排序

>>> sorted(gameresult, key=itemgetter(2))
[['bob', 95.0, 'A'], ['mandy', 83.5, 'A'], ['alan', 86.0, 'C'], ['rob', 89.3, 'E']]

按第三个元素升序,然后按第一个升序

>>> sorted(gameresult, key=itemgetter(2, 0))
[['bob', 95.0, 'A'], ['mandy', 83.5, 'A'], ['alan', 86.0, 'C'], ['rob', 89.3, 'E']]

……

>>> sorted(gameresult, key=itemgetter(2, 0), reverse = True)
[['rob', 89.3, 'E'], ['alan', 86.0, 'C'], ['mandy', 83.5, 'A'], ['bob', 95.0, 'A']]

以一个列表内容为依据,对另一个列表内容进行排序

>>> list1 = ["what", "I am", "sorting", "by"]
>>> list2 = ["something", "else", "to", "sort"]
>>> pairs = zip(list1, list2)       #把两个列表中的对应位置元素配对

……

>>> [item[1] for item in sorted(pairs, key=lambda x:x[0], reverse=True)]
['something', 'to', 'sort', 'else']

把第二个元素升序、第三个元素降序排序

>>> x = [[1, 2, 3], [2, 1, 4], [2, 2, 1]]
>>> sorted(x, key=lambda item:(item[1], -item[2]))
[[2, 1, 4], [1, 2, 3], [2, 2, 1]]

先按长度排序,长度一样的正常排序

>>> x = ['aaaa', 'bc', 'd', 'b', 'ba']
>>> sorted(x, key=lambda item:(len(item), item))
['b', 'd', 'ba', 'bc', 'aaaa']

内置函数对列表的操作

返回列表中所有元素的最大值和最小值

max()和min()

>>> x = list(range(11))
>>> import random
>>> random.shuffle(x)
>>> x
[7, 4, 2, 1, 10, 9, 6, 5, 8, 0, 3]
>>> max(x)
10
>>> max(x, key=str)
9
>>> min(x)
0

返回列表中所有元素之和

sum()

>>> sum(x)
55

返回列表中元素个数

len()

>>> len(x)
11

多列表元素重新组合

>>> list(zip(x, [1]*11))
[(7, 1), (4, 1), (2, 1), (1, 1), (10, 1), (9, 1), (6, 1), (5, 1), (8, 1), (0, 1), (3, 1)]

zip()函数也可以用于一个序列或迭代对象

>>> list(zip(range(1, 4)))
[(1,), (2,), (3,)]

如果两个列表不等长,以短的为准

>>> list(zip(['a' 'b', 'c'], [1, 2]))
[('ab', 1), ('c', 2)]

枚举列表元素,返回enumerate对象

>>> x = list(range(11))
>>> import random
>>> random.shuffle(x)
>>> x
[6, 4, 3, 7, 1, 10, 9, 2, 5, 8, 0]
>>> enumerate(x)
<enumerate object at 0x0000000002C03CA8>
>>> list(enumerate(x))        #enumerate对象可迭代
[(0, 6), (1, 4), (2, 3), (3, 7), (4, 1), (5, 10), (6, 9), (7, 2), (8, 5), (9, 8), (10, 0)]
>>> 

 map()

将一个函数依次作用(或映射)到序列或迭代器对象的每个元素上,并返回一个map对象作为结果

>>> list(map(str, range(5)))      #转换为字符串
['0', '1', '2', '3', '4']
>>> def add5(v):                  #单参数函数
    return v + 5

>>> list(map(add5, range(10)))    #把单参数函数映射到一个序列的所有元素
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> 
>>> def add(x, y):                #可以接受2个参数的函数
    return x + y

>>> list(map(add, range(5), range(5, 10))) #把双参数函数映射到两个序列上
[5, 7, 9, 11, 13]
>>> list(map(lambda x, y:x+y, range(5), range(5, 10)))
[5, 7, 9, 11, 13]
>>> [add(x, y) for x, y in zip(range(5), range(5, 10))]
[5, 7, 9, 11, 13]

reduce()

将一个接收2个参数的函数以累计的方式从左到右依次作用到一个序列或迭代器对象的所有元素上

>>> from functools import reduce
>>> seq = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> reduce(add, range(10))        #add是上一段代码中定义的函数
45
>>> reduce(lambda x, y:x+y, seq)  #使用lambda表达式实现相同功能
45

filter()

将一个单参数函数作用到一个序列上,返回该序列中使得该函数返回值为True的那些元素组成的filter对象,如果指定函数为None,则返回序列中等价与True的那些元素组成的filter对象,如果指定函数为None,则返回序列中等价于True的元素

>>> seq = ['foo', 'x41', '?!', '***']
>>> def func(x):
    return x.isalnum()                    #测试是否为字母或数字

>>> filter(func, seq)                     #返回filter对象
<filter object at 0x0000000002BB1390>
>>> list(filter(func, seq))               #把filter对象转换为列表
['foo', 'x41']
>>> seq                                   #不对原列表做任何修改
['foo', 'x41', '?!', '***']               
>>> [x for x in seq if x.isalnum()]       #使用列表推导式实现相同功能
['foo', 'x41']
>>> list(filter(lambda x:x.isalnum(), seq))         #使用lambda表达式实现相同功能
['foo', 'x41']
>>> list(filter(None, [1, 2, 3, 0, 0, 4, 0, 5]))    #指定函数为None
[1, 2, 3, 4, 5]
>>> 

Python列表支持与整数的乘法运算,表示列表元素进行重复并生成新列表

>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

列表之间的加法运算表示列表元素的合并,生成新列表

>>> [1, 2, 3] + [4, 5, 6]
[1, 2, 3, 4, 5, 6]

向量运算

生成10个[1, 100]区间内的随机数

>>> import random
>>> x = [random.randint(1, 100) for i in range(10)]
>>> x
[79, 86, 80, 51, 100, 37, 85, 94, 3, 23]

所有元素同时加5

>>> list(map(lambda i: i+5, x))
[84, 91, 85, 56, 105, 42, 90, 99, 8, 28]

 向量内积

>>> x = [random.randint(1, 10) for i in range(10)]
>>> x
[9, 10, 2, 6, 5, 9, 8, 6, 4, 7]
>>> y = [random.randint(1, 10) for i in range(10)]
>>> y
[3, 1, 3, 2, 10, 8, 1, 10, 3, 9]
>>> import operator
>>> sum(map(operator.mul, x, y))
320

使用内置函数计算向量内积

>>> sum((i * j for i, j in zip(x, y)))
320

两个等长的向量对应元素相加

>>> list(map(operator.add, x, y))
[12, 11, 5, 8, 15, 17, 9, 16, 7, 16]

使用lambda表达式实现同样效果

>>> list(map(lambda i, j:i+j, x, y))
[12, 11, 5, 8, 15, 17, 9, 16, 7, 16]

列表推导式

语法:

[表达是 for 变量 in 序列或迭代对象]

列表推导式在逻辑上相当于一个循环,只是形式更加简洁

>>> aList = [x * x for x in range(10)]

相当于

>>> aList = []
>>> for x in range(10):
    aList.append(x * x)

也等价于

>>> aList = list(map(lambda x:x*x, range(10)))

再例如:

>>> freshfruit = ['banana', 'loganberry', 'passion fruit']
>>> aList = [w.strip() for w in freshfruit]

等价于

>>> freshfruit = ['banana', 'loganberry', 'passion fruit']
>>> aList = []
>>> for item in freshfruit:
    aList.append(item.strip())

也等价于

>>> freshfruit = ['banana', 'loganberry', 'passion fruit']
>>> aList = list(map(lambda x:x.strip(), freshfruit))

>>> freshfruit = ['banana', 'loganberry', 'passion fruit']
>>> aList = list(map(str.strip, freshfruit))

 列表推导式强大功能

1、使用列表推导式实现嵌套列表的平铺

>>> vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

 等价于

>>> vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> result = []
>>> for elem in vec:
    for num in elem:
        result.append(num)

        
>>> result
[1, 2, 3, 4, 5, 6, 7, 8, 9]

2、过滤不符合条件的元素

列出当前文件夹下所有Python源文件

>>> import os
>>> [filename for filename in os.listdir('.') if filename.endswith('.py')]
[]

选择符合条件的元素组成新的列表

>>> aList = [-1, -4, 6, 7.5, -2.3, 9, -11]
>>> [i for i in aList if i > 0]      #所有大于0的数字
[6, 7.5, 9]

再例如,已知有一个包含一些同学成绩的字典,计算成绩的最高分、最低分、平均分,并查找所有最高分的同学

>>> scores = {"zhang san":45, "li si":78, "wang wu":40, "zhou liu":96, "zhao qi":65, "sun ba":90, "zheng jiu":78, "wu shi":99, "dong shiyi":60}
>>> highest = max(scores.values())       #最高分
>>> lowest = min(scores.values())        #最低分
>>> highest
99
>>> lowest
40
>>> average = sum(scores.values()) / len(scores)      #平均分
>>> average
72.33333333333333
>>> highestPerson = [name for name, score in scores.items() if score == highest]     #最高分所对应的名字
>>> highestPerson
['wu shi']

使用列表推导式查找列表中最大元素的位置

>>> from random import randint
>>> x = [randint(1, 10 ) for i in range(20)]
>>> m = max(x)
>>> m
10
>>> [index for index, value in enumerate(x) if value == m]         #输出最大值的下标位置 
[11, 15, 16]
>>> x
[4, 4, 1, 9, 3, 1, 8, 2, 8, 7, 6, 10, 1, 1, 2, 10, 10, 9, 6, 6]

3、在列表推导式中使用多个循环,实现多序列元素的任意组合,并且可以结合条件语句过滤特定元素

>>> [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

等价于

>>> result = []
>>> for x in [1, 2, 3]:
    for y in [3, 1, 4]:
        if x != y:
            result.append((x, y))

            
>>> result
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

4、使用列表推导式实现矩阵转置

>>> matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

或者,也可以使用内置函数zip()和list()来实现矩阵转置

>>> list(map(list, zip(*matrix)))                  #序列解包
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

或者

>>> matrix = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
>>> result = []
>>> for i in range(len(matrix)):
    temp = []
    for row in matrix:
        temp.append(row[i])
        result.append(temp)

        
>>> result
[[1, 5, 9], [1, 5, 9], [1, 5, 9], [2, 6, 10], [2, 6, 10], [2, 6, 10], [3, 7, 11], [3, 7, 11], [3, 7, 11]]

5、列表推导式中可以使用函数或复杂表达式

>>> def f(v):
    if v%2 == 0:
        v = v**2
    else:
        v = v+1
    return v

>>> print([f(v) for v in [2, 3, 4, -1] if v>0])
[4, 4, 16]
>>> print([v**2 if v%2 == 0 else v+1 for v in [2, 3, 4, -1] if v>0])
[4, 4, 16]

6、列表推导式支持文件对象迭代

7、使用列表推导式生成100以内的所有素数

>>> [p for p in range(2, 100) if 0 not in [p%d for d in range(2, int(p**0.5)+1)]]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

切片

切片使用2个冒号分隔的3个数字来完成,第一个数字表示切片的开始位置(默认为0),第二个数字表示切片的截止(但不包含)位置(默认为列表长度),第三个数字表示切片的步长(默认为1),当步长省略时可以同时省略最后一个冒号

1、使用切片获取列表中的部分元素

返回包含原列表中所有元素的新列表

>>> [p for p in range(2, 100) if 0 not in [p%d for d in range(2, int(p**0.5)+1)]]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

返回包含原列表中所有元素的逆序列表

>>> aList[::-1]
[17, 15, 13, 11, 9, 7, 6, 5, 4, 3]

隔一个元素取一个元素,获取偶数位置的元素

>>> aList[::2]
[3, 5, 7, 11, 15]

隔一个元素取一个元素,获取奇数位置的元素

>>> aList[1::2]
[4, 6, 9, 13, 17]

指定切片的开始位置和结束位置

>>> aList[3:6]
[6, 7, 9]

切片的结束位置大于列表长度时,从列表尾部截断

>>> aList[0:100]
[3, 4, 5, 6, 7, 9, 11, 13, 15, 17]

切片的开始位置大于列表长度时,返回空列表

>>> aList[100:]
[]

不允许越界访问

>>> aList[100]
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    aList[100]
IndexError: list index out of range

2、切片对列表元素进行增、删、改

在列表尾部增加元素

>>> aList = [3, 5, 7]
>>> aList[len(aList):]
[]
>>> aList[len(aList):] = [9]
>>> aList
[3, 5, 7, 9]

替换列表元素

>>> aList
[3, 5, 7, 9]
>>> 
>>> aList[:3] = [1, 2, 3]
>>> aList
[1, 2, 3, 9]

删除列表元素

>>> aList[:3] = []
>>> aList
[9]

替换列表元素

>>> aList = list(range(10))
>>> aList
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> aList[::2] = [0] * (len(aList) // 2)
>>> aList
[0, 1, 0, 3, 0, 5, 0, 7, 0, 9]

在列表指定位置插入元素

>>> aList
[0, 1, 0, 3, 0, 5, 0, 7, 0, 9]
>>> 
>>> aList[3:3] = [4, 5, 6]
>>> aList
[0, 1, 0, 4, 5, 6, 3, 0, 5, 0, 7, 0, 9]
>>> len(aList)
13

在尾部追加元素,注意切片的范围

>>> aList
[0, 1, 0, 4, 5, 6, 3, 0, 5, 0, 7, 0, 9]
>>> aList[20:30] = [3] * 2
>>> aList
[0, 1, 0, 4, 5, 6, 3, 0, 5, 0, 7, 0, 9, 3, 3]

删除列表中的部分元素

>>> aList = [3, 5, 7, 9, 11]
>>> del aList[:3]
>>> aList
[9, 11]

注意:切片返回的是浅复制,与列表对象的直接赋值并不一样

>>> aList = [3, 5, 7]
>>> bList = aList          #指向同一个内存
>>> bList
[3, 5, 7]
>>> bList[1] = 8
>>> aList
[3, 8, 7]
>>> aList == bList        #两个列表的值是相等的
True
>>> aList is bList        #两个列表是同一个对象
True
>>> id(aList) == id(bList)    #两个列表是同一个内存地址
True

切片浅复制

>>> aList = [3, 5, 7]
>>> aList[::]
[3, 5, 7]
>>> bList = aList[::]
>>> aList == aList
True
>>> 
>>> aList == bList
True
>>> aList is bList
False
>>> id(aList) is id(bList)
False
>>> id(aList[0]) == id(bList[0])
True
>>> bList[1] = 8
>>> bList
[3, 8, 7]
>>> aList
[3, 5, 7]
>>> aList == bList
False
>>> aList is bList
False

虽然直接把一个列表变量赋值给另一个变量时两个变量指向同一个内存地址,但是把一个列表分别赋值给2个变量时就不是这样的情况了

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> id(x) == id(y)
False
>>> y.append(4)      #修改y的值,不影响x
>>> x
[1, 2, 3]
>>> y
[1, 2, 3, 4]

当列表中包含其他可变序列时,情况变得更加复杂

Python采用的是基于值的内存管理模式

Python变量中并不直接存放值,而是存放值的引用

>>> x = [[1], [2], [3]]
>>> y = x[:]
>>> y
[[1], [2], [3]]
>>> y[0] = [4]            #直接修改y中下标为0的元素值,不影响x
>>> y
[[4], [2], [3]]
>>> y[1].append(5)        #增加元素,影响x
>>> y
[[4], [2, 5], [3]]
>>> x
[[1], [2, 5], [3]]

使用切片修改列表元素值时,如果左侧切片是连续的,那么等号两侧的列表长度可以不一样;如果左侧切片不连续,则右侧列表中元素个数必须与左侧相等

使用del命令和切片删除列表中部分元素时,切片可以不连续

等号两侧不相等,抛出异常

>>> x = list(range(10))
>>> x[::2] = [3, 5]
Traceback (most recent call last):
  File "<pyshell#47>", line 1, in <module>
    x[::2] = [3, 5]
ValueError: attempt to assign sequence of size 2 to extended slice of size 5

等号两侧等长,可以执行

>>> x[::2] = [1, 1, 1, 1, 1]
>>> x
[1, 1, 1, 3, 1, 5, 1, 7, 1, 9]

删除列表中不连续的元素

>>> del x[::2]
>>> x
[1, 3, 5, 7, 9]

元组与生成器推导式

元组

元组的所有元素放在一对圆括号中,元素之间使用逗号分隔

元组赋值给一个变量

>>> x = (1, 2, 3)
>>> x
(1, 2, 3)
>>> type(x)
<class 'tuple'>
>>> x = (3)                #这和x = 3 是一样的
>>> x
3

如果元组中只有一个元素,必须在后面多写一个逗号

>>> x = (3, )
>>> x
(3,)

空元组

>>> x = ()
>>> x
()

将其他迭代对象转换为元组

>>> tuple(range(5))
(0, 1, 2, 3, 4)

元组属于不可变序列,无法为元组增加或删除元素。可以认为元组是轻量级的列表,或者“常量列表”

包含列表的元组,并修改元组中的列表

>>> x = ([1, 2], [3])
>>> x[0][0] = 5
>>> x
([5, 2], [3])
>>> x[0].append(8)            #为元组中的列表增加元素
>>> x
([5, 2, 8], [3])

生成器推导式

创建生成器对象

>>> g = ((i + 2) ** 2 for i in range(10))
>>> g
<generator object <genexpr> at 0x0000000002B82B88>

将生成器对象转换为元组

>>> tuple(g)
(4, 9, 16, 25, 36, 49, 64, 81, 100, 121)

生成器对象已遍历结束,没有元素了

>>> list(g)
[]

获取生成器对象的元素

__next__()

>>> g = ((i + 2) ** 2 for i in range(10))
>>> g.__next__()
4
>>> g.__next__()
9

获取下一个元素

>>> next(g)
16
>>> next(g)
25

使用循环直接遍历生成器对象中的元素

>>> g = ((i + 2) ** 2 for i in range(10))
>>> for item in g:
    print(item, end=' ')

    
4 9 16 25 36 49 64 81 100 121 

使用生成器来生成斐波那契数列

>>> def f():                 #序列解包,同时为多个元素赋值
    a, b = 1, 1
    while True:
        yield a              #暂停执行,需要时再产生一个新元素
        a, b=b, a+b          #序列解包,继续生成新元素

        
>>> a = f()                  #创建生成器对象
>>> for i in range(10):      #斐波那契数列中前10个元素
    print(a.__next__(), end=' ')

    
1 1 2 3 5 8 13 21 34 55 
>>> for i in f():            #斐波那契数列中第一个大于100的元素
    if i > 100:
        print(i, end=' ')
        break

    
144 

获取生成器对象中的元素,每次索取新元素时,有yield语句生成

>>> a = f()
>>> next(a)
1
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
5
>>> next(a)
8
>>> next(a)
13
>>> next(a)
21
>>> next(a)
34
>>> next(a)
55
>>> next(a)
89
>>> next(a)
144

字典

字典是包含若干“键:值”元素的无序可变序列

创建一个字典变量

>>> a_dict = {'server':'db.diveintopython3.prg', 'database':'mysql'}
>>> a_dict
{'server': 'db.diveintopython3.prg', 'database': 'mysql'}

 使用内置函数快速创建字典

dict()

>>> keys = ['a', 'b', 'c', 'd']
>>> values = [1, 2, 3, 4]
>>> dictionary = dict(zip(keys, values))
>>> print(dictionary)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

创建空字典

>>> x = dict()
>>> x
{}
>>> type(x)
<class 'dict'>

给定键和值来创建字典

>>> d = dict(name='djl', age=23)
>>> d
{'name': 'djl', 'age': 23}

创建值为空的字典

>>> adict = dict.fromkeys(['name', 'age', 'sex'])
>>> adict
{'name': None, 'age': None, 'sex': None}

当以指定“键”为下标为字典元素赋值时,有两种含义:

1、若该“键”存在,则表示修改该“键”对应的值

2、若该“键”不存在,则表示添加一个新的“键:值”

例如:

修改元素值

>>> aDict = dict(name='djl', age='23', sex='male')
>>> aDict
{'name': 'djl', 'age': '23', 'sex': 'male'}
>>> aDict['age'] = 25
>>> aDict
{'name': 'djl', 'age': 25, 'sex': 'male'}

添加新元素

>>> aDict
{'name': 'djl', 'age': 25, 'sex': 'male'}
>>> aDict['address'] = 'shandong'
>>> aDict
{'name': 'djl', 'age': 25, 'sex': 'male', 'address': 'shandong'}

返回所有元素

>>> aDict = dict(name='djl', score='[98, 97]', age='23', sex='male')
>>> aDict
{'name': 'djl', 'score': '[98, 97]', 'age': '23', 'sex': 'male'}
>>> aDict.items()
dict_items([('name', 'djl'), ('score', '[98, 97]'), ('age', '23'), ('sex', 'male')])

修改“age”键的值,同时添加新元素'a':97

 update()方法

将另一个字典的“键:值”一次性全部添加到当前字典对象,如果两个字典中存在相同的“键,则以另一个字典中的“值”为准对当前字典进行更新

>>> aDict.update({'a':97, 'age':39})
>>> aDict
{'name': 'djl', 'score': '[98, 97]', 'age': 39, 'sex': 'male', 'a': 97}

删除字典元素

>>> aDict
{'name': 'djl', 'score': '[98, 97]', 'age': 39, 'sex': 'male', 'a': 97}
>>> del aDict['age']
>>> aDict
{'name': 'djl', 'score': '[98, 97]', 'sex': 'male', 'a': 97}

删除整个字典

>>> aDict
{'name': 'djl', 'score': '[98, 97]', 'sex': 'male', 'a': 97}
>>> 
>>> del aDict
>>> aDict           #字典对象被删除后不再存在
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    aDict
NameError: name 'aDict' is not defined

弹出一个元素(对空字典会抛出异常)

popitem()

>>> aDict = dict(age='23', score='[98, 97]', name='djl', sex='male')
>>> aDict
{'age': '23', 'score': '[98, 97]', 'name': 'djl', 'sex': 'male'}
>>> aDict.popitem()
('sex', 'male')
>>> aDict
{'age': '23', 'score': '[98, 97]', 'name': 'djl'}

弹出指定键对应的元素

>>> aDict
{'age': '23', 'score': '[98, 97]', 'name': 'djl'}
>>> aDict.pop('name')
'djl'
>>> aDict
{'age': '23', 'score': '[98, 97]'}

访问字典对象的数据

指定的“键”存在,返回对应的“值”

>>> aDict = {'age':23, 'score':[98, 97], 'name':'djl', 'sex':'male'}
>>> aDict
{'age': 23, 'score': [98, 97], 'name': 'djl', 'sex': 'male'}
>>> aDict['age']
23
>>> aDict
{'age': 23, 'score': [98, 97], 'name': 'djl', 'sex': 'male'}

指定的“键”不存在,抛出异常

>>> aDict['address']
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    aDict['address']
KeyError: 'address'

get()方法

用来返回指定“键”对应的“值”,允许指定该键不存在

>>> aDict.get('age')
23
>>> aDict.get('address')
>>> aDict
{'age': 23, 'score': [98, 97], 'name': 'djl', 'sex': 'male'}
>>> 
>>> aDict.get('address', 'Not Exists')
'Not Exists'

增加新元素

setdefault()方法

返回指定“键”对应的“值”,如果字典中不存在该“键”,就添加一个新元素并设置键值对

>>> aDict.setdefault('address', 'shandong')
'shandong'
>>> aDict
{'age': 23, 'score': [98, 97], 'name': 'djl', 'sex': 'male', 'address': 'shandong'}

遍历字典中所有的“键”

>>> aDict
{'age': 23, 'score': [98, 97], 'name': 'djl', 'sex': 'male', 'address': 'shandong'}
>>> for item in aDict:
    print(item)

    
age
score
name
sex
address

明确指定遍历字典的所有元素

>>> for item in aDict.items():
    print(item)

    
('age', 23)
('score', [98, 97])
('name', 'djl')
('sex', 'male')
('address', 'shandong')
>>> aDict.items()
dict_items([('age', 23), ('score', [98, 97]), ('name', 'djl'), ('sex', 'male'), ('address', 'shandong')])

遍历字典的所有键

>>> aDict.keys()
dict_keys(['age', 'score', 'name', 'sex', 'address'])

遍历字典的所有值

>>> aDict.values()
dict_values([23, [98, 97], 'djl', 'male', 'shandong'])

有序字典

Python内置字典是无序的

>>> import collections
>>> x = collections.OrderedDict()
>>> x['a'] = 3
>>> x['b'] = 5
>>> x['x'] = 8
>>> x
OrderedDict([('a', 3), ('b', 5), ('x', 8)])

对字典元素进行排序并返回新列表

sorted()

按字典的“值”进行排序

>>> phonebook = {'linda':'7750', 'bob':'9345', 'carol':'5834'}
>>> from operator import itemgetter
>>> sorted(phonebook.items(), key=itemgetter(1))
[('carol', '5834'), ('linda', '7750'), ('bob', '9345')]

按字典的“键”进行排序

>>> sorted(phonebook.items(), key=itemgetter(0))
[('bob', '9345'), ('carol', '5834'), ('linda', '7750')]
>>> sorted(phonebook.items(), key=lambda item:item[0])
[('bob', '9345'), ('carol', '5834'), ('linda', '7750')]

使用key来指定排序依据,先按姓名升序排序,姓名相同的按年龄降序排序

>>> persons = [{'name':'dong', 'age':37},
       {'name':'Li', 'age':40},
       {'name':'zhang', 'age':30},
       {'name':'du', 'age':23},
       {'name':'Li', 'age':25}]
>>> print(persons)
[{'name': 'dong', 'age': 37}, {'name': 'Li', 'age': 40}, {'name': 'zhang', 'age': 30}, {'name': 'du', 'age': 23}, {'name': 'Li', 'age': 25}]
>>> print(sorted(persons, key=lambda x:(x['name'], -x['age'])))
[{'name': 'Li', 'age': 40}, {'name': 'Li', 'age': 25}, {'name': 'dong', 'age': 37}, {'name': 'du', 'age': 23}, {'name': 'zhang', 'age': 30}]

字典推导式快速生成符合特定条件的字典

>>> {i:str(i) for i in range(1, 5)}
{1: '1', 2: '2', 3: '3', 4: '4'}
>>> x = ['A', 'B', 'C', 'D']
>>> y = ['a', 'b', 'c', 'd']
>>> {i:j for i, j in zip(x, y)}
{'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd'}

集合

集合是无序可变序列,使用一对大括号作为界定符,元素之间使用逗号分隔,同一个集合内的每个元素都是唯一的,元素之间不允许重复

创建集合对象

>>> a = {3, 5}
>>> a
{3, 5}
>>> type(a)
<class 'set'>

将列表、元组等其他可迭代对象转换为集合

set()函数

把range对象转换为集合

>>> a_set = set(range(8, 14))
>>> a_set
{8, 9, 10, 11, 12, 13}

把列表转换为集合,自动去掉重复元素

>>> b_set = set([0, 1, 2, 3, 4, 0, 1, 2, 3, 7, 8])
>>> b_set
{0, 1, 2, 3, 4, 7, 8}

空集合

>>> x = {}
>>> x
{}
>>> x = set()
>>> x
set()

集合中只能包含数字、字符串、元组等不可变类型(或者说可哈希)的数据,而不能包含列表、字典、集合等可变类型的数据

集合操作与运算

1、集合元素增加与删除

添加、更新元素,重复元素自动忽略

add()

update()

>>> s = {1, 2, 3}
>>> s.add(3)
>>> s
{1, 2, 3}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.update({3, 4, 5})
>>> s
{1, 2, 3, 4, 5}

从集合中删除一个特定元素,如果元素不存在则忽略该操作

discard()

>>> s
{1, 2, 3, 4, 5}
>>> 
>>> s.discard(5)
>>> s
{1, 2, 3, 4}
>>> s.discard(7)
>>> s
{1, 2, 3, 4}

删除集合中的元素,如果指定元素不存在则抛出异常

>>> s
{1, 2, 3, 4}
>>> 
>>> s.remove(3)
>>> s
{1, 2, 4}
>>> s.remove(5)
Traceback (most recent call last):
  File "<pyshell#155>", line 1, in <module>
    s.remove(5)
KeyError: 5

随机删除并返回集合中的一个元素,如果集合为空则抛出异常

>>> s
{1, 2, 4}
>>> s.pop()
1
>>> s
{2, 4}

2、集合运算

并集

union()

>>> a_set=set([8, 9, 10, 11, 12, 13])
>>> b_set = {0, 1, 2, 3, 7, 8}
>>> a_set | b_set
{0, 1, 2, 3, 7, 8, 9, 10, 11, 12, 13}
>>> a_set.union(b_set)
{0, 1, 2, 3, 7, 8, 9, 10, 11, 12, 13}

交集

intersection()

>>> a_set & b_set
{8}
>>> a_set.intersection(b_set)
{8}

差集

difference()

>>> a_set - b_set
{9, 10, 11, 12, 13}
>>> a_set.difference(b_set)
{9, 10, 11, 12, 13}

对称差集

symmetric_difference()

>>> a_set ^ b_set
{0, 1, 2, 3, 7, 9, 10, 11, 12, 13}
>>> a_set.symmetric_difference(b_set)
{0, 1, 2, 3, 7, 9, 10, 11, 12, 13}

比较集合大小

>>> x = {1, 2, 3}
>>> y = {1, 2, 5}
>>> z = {1, 2, 3, 4}
>>> x < y
False
>>> x < z
True
>>> y < z
False

测试是否为子集

issubset()

>>> x.issubset(y)
False
>>> x.issubset(z)
True

自定义枚举类型

>>> from enum import Enum      
>>> class Color(Enum):        #创建自定义枚举类
    red = 1
    blue = 2
    green = 3

    
>>> Color.red            #访问枚举的成员
<Color.red: 1>
>>> type(Color.green)    #差可能枚举成员的类型
<enum 'Color'>
>>> isinstance(Color.red, Color)
True
>>> x = dict()
>>> x[Color.red] = 'red'      #枚举成员可哈希,可作为字典的“键”
>>> x
{<Color.red: 1>: 'red'}
>>> Color(2)             #返回指定值对应的枚举类成员
<Color.blue: 2>
>>> Color['red']
<Color.red: 1>
>>> r = Color.red
>>> r.name
'red'
>>> r.value
1
>>> list(Color)             #枚举类是可以迭代的
[<Color.red: 1>, <Color.blue: 2>, <Color.green: 3>]

直接从指定序列中选取指定数量个不重复的元素

sample()

>>> import random
>>> random.sample(range(1000), 20)
[334, 827, 678, 299, 174, 296, 610, 886, 156, 5, 668, 657, 335, 83, 105, 602, 481, 384, 116, 764]

集合推导式

>>> {x.strip() for x in ('he', 'she', 'I')}
{'I', 'she', 'he'}
>>> import random
>>> x = {random.randint(1, 500) for i in range(100)}     #生成随机数,自动去除重复元素
>>> x
{4, 13, 26, 32, 39, 45, 66, 76, 80, 85, 86, 88, 91, 94, 102, 114, 115, 119, 120, 121, 129, 131, 156, 157, 162, 164, 173, 185, 192, 198, 211, 214, 220, 226, 236, 240, 249, 252, 254, 256, 259, 271, 286, 293, 294, 295, 296, 297, 301, 325, 330, 331, 332, 334, 336, 346, 347, 354, 358, 363, 372, 383, 390, 393, 394, 423, 428, 435, 436, 438, 444, 450, 458, 467, 468, 469, 471, 474, 477, 482, 489, 490, 493, 495}
>>> 
>>> len(x)
84
>>> 
>>> {str(x) for x in range(10)}
{'5', '1', '2', '9', '8', '0', '4', '7', '6', '3'}

序列解包

使用序列解包对多个变量同时进行赋值

>>> x, y, z = 1, 2, 3                 #多变量同时赋值
>>> v_tuple = (False, 3.5, 'exp')
>>> (x, y, z) = v_tuple
>>> x, y, z = v_tuple
>>> x, y, z = range(3)               #使用range对象进行序列解包
>>> x, y, z = map(str, range(3))     #使用迭代对象进行序列解包

列表与字典的序列解包

>>> a = [1, 2, 3]
>>> b, c, d=a             #列表也支持序列解包的用法
>>> b
1
>>> x, y, z=sorted([1, 3, 2])       #sorted()函数返回排序后的列表
>>> s = {'a':1, 'b':2, 'c':3}
>>> b, c, d=s.items()
>>> b                    #这里的结果如果和你的不一样是正常的
('a', 1)
>>> b, c, d=s            #使用字典时不用考虑元素的顺序
>>> b                    #多执行几次试试,或许结果会有变化
'a'
>>> b, c, d=s.values()
>>> print(b, c, d)
1 2 3

使用序列解包可以很方便地同时遍历多个序列

>>> keys = ['a', 'b', 'c', 'd']
>>> values = [1, 2, 3, 4]
>>> for k, v in zip(keys, values):
    print(k, v)

    
a 1
b 2
c 3
d 4

内置函数enumerate()返回的迭代对象进行遍历时序列解包的用法

>>> x = ['a', 'b', 'c']
>>> for i, v in enumerate(x):
    print('The value on position {0} is {1}'.format(i, v))

    
The value on position 0 is a
The value on position 1 is b
The value on position 2 is c

字典中的序列解包

>>> s = {'a':1, 'b':2, 'c':3}
>>> for k, v in s.items():
    print(k, v)

    
a 1
b 2
c 3

序列解包还支持下面的用法

>>> print(*[1, 2, 3], 4, *(5,6))
1 2 3 4 5 6
>>> *range(4), 4
(0, 1, 2, 3, 4)
>>> {*range(4), 4, *(5, 6, 7)}
{0, 1, 2, 3, 4, 5, 6, 7}
>>> {'x':1, **{'y':2}}
{'x': 1, 'y': 2}

在实参前面加上一个星号(*)也可以进行序列解包,从而实现将序列中的元素值依次传递给相同数量的形参

猜你喜欢

转载自www.cnblogs.com/djlsunshine/p/10857582.html