1. 赋值与拷贝的区别
- 变量即是一个名字一个标签,通过变量即可找到对应的数据。变量不是一个盒子,赋值语句不是将数据放在盒子当中,而是将变量与数据进行挂钩(变量指向地址的数据)这个行为称之为引用。
具体可使用下面这个图演示:x = [1,2,3]
将一个变量赋值给另一个变量就是将一个变量的引用传递给另一个变量:y = x,演示如下:
既然它们都指向同一个地址的数据,当其中一个改变时另一个也会随之变化:
y = [0] * 3 '''定义变量y'''
x = [1,2,3]
y = x
y[0] = 5
print(x)
'''输出 [5,2,3] '''
即使是将x赋值给y,一旦通过任一变量改变被指向的数据,所有变量的指向数据都会发生改变。这是赋值带来的结果,如果想要获得两个独立的列表必须要采用拷贝来完成。
2. 深拷贝与浅拷贝
- 通过拷贝才能获得两个独立的列表,拷贝的是整个列表对象,而非简单的变量引用;列表拷贝分为浅拷贝和深拷贝;浅拷贝可通过copy函数与切片来实现。
x = [1,2,3]
y = x.copy()
print(y)
'''输出 [1, 2, 3] '''
x = [1,2,3]
y = x[:]
print(y)
'''输出 [1, 2, 3] '''
通过与赋值的对比会发现一个不同,赋值的情况下y是需要定义的,因为它是一个变量的引用必须规定变量类型,而拷贝则不需要定义变量类型;但其实将y定义成int型也可赋值成功。
- 但是浅拷贝存在局限性,它只能拷贝一维列表;对于嵌套列表就存在很强的局限性,因此引入拷贝模块(copy()属于该模块里的其中一个函数);另一个函数则为deepcopy()。
import copy
x = [[1,2,3],[4,5,6],[7,8,9]]
y = copy.copy(x) '''第一个copy是指copy模块,第二个是指模块中的copy函数 '''
x[1][1] = 0
print(y)
''' 输出 [[1, 2, 3], [4, 0, 6], [7, 8, 9]] '''
import copy
x = [[1,2,3],[4,5,6],[7,8,9]]
y = copy.deepcopy(x)
x[1][1] = 0
print(y)
''' 输出 [[1, 2, 3], [4, 5, 6], [7, 8, 9]] '''
上面两张图第一个浅拷贝第二个深拷贝,浅拷贝只是拷贝了外层的对象如果包含嵌套对象拷贝的只是其引用;而深拷贝会将原对象拷贝的同时也将对象中所有引用的子对象一并进行拷贝。且无论几层嵌套都会拷贝下来;通常为了效率会默认使用浅拷贝。
3. 列表推导式
- 简单(一维)形式 list = [循环体结果 for循环体 if筛选语句] if筛选语句可以省略
- 将列表list = [1,2,3,4,5] 中的每个元素扩大两倍
list = [1,2,3,4,5]
for i in range(len(list)):
list[i] = list[i] * 2
print(list)
list = [1,2,3,4,5]
list = [i * 2 for i in list]
print(list)
第一个方法是正常解法,使用for循环实现;第二个即是采用列表推导式来实现;两种方法的实现结果相同那么有什么不同点呢,for循环是通过迭代逐个修改原列表中元素,推导式是建立一个新的列表,然后再赋值回原先的变量名。
不仅数字可翻倍,字符串同样可以
list = ["python"]
list = [i * 2 for i in list]
print(list)
''' 输出['pythonpython'] '''
list = [i * 2 for i in "python"]
print(list)
''' 输出 ['pp', 'yy', 'tt', 'hh', 'oo', 'nn'] '''
- 若想将字符转换成对应的Unicode编码并保存为列表,可以采用ord()函数
list = [ord(i) for i in "python"]
print(list)
''' 输出 [112, 121, 116, 104, 111, 110] '''
- 二维列表同样可以操作
matrix = [[1,2,3],[4,5,6],[7,8,9]]
list = [row[1] for row in matrix ]
print(list)
''' 输出 [2, 5, 8] '''
matrix = [[1,2,3],[4,5,6],[7,8,9]]
list = [matrix[i][i] for i in range(len(matrix))]
print(list)
''' 输出 [1, 5, 9] '''
第一个程序输出每行元素的第二列元素,其中for循环对于二维列表的输出是行列表,即row是三个行列表;第二个程序输出的结果是对角线元素。这两个程序有一个区别,第一个是直接输出for循环的值,而第二个for是输出索引的值,然后通过索引值再输出结果。
- 输出副对角线元素
matrix = [[1,2,3],
[4,5,6],
[7,8,9]]
list = [matrix[i][len(matrix)-1-i] for i in range(len(matrix))]
print(list)
- 列表推导式创建的二维列表和for循环相同属于浅拷贝。
s = [[0] * 4 for i in range(3)]
print(s)
''' 输出 [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] '''
这里的 i 变量并没有在输出值中有任何的体现,这里只当做表示循环三次的作用。
- 带有if筛选语句的应用,输出0-10之间的奇数赋值给一个列表
s = [i+1 for i in range(10) if i % 2 == 0]
print(s)
''' 输出 [1,3,5,7,9] '''
- 找出开头是f的单词
words = ["Great","Fishc","Ba","Excellent","Fantastic"]
s = [row for row in words if row[0] == "F"]
print(s)
''' 输出 ['Fishc', 'Fantastic'] '''
这里要说一点,字符串也可以使用下表索引的方式。
- 嵌套列表推导式: matrix=[expression for target1 in iterable1 if condition1 for target2 in iterable2 if condition2 for target3 in iterable3 if condition3.......]
- 将一个二维列表降为一维列表,包含两种方法
matrix = [[1,2,3],
[4,5,6],
[7,8,9]]
s = [matrix[i][j] for i in range(len(matrix)) for j in range(len(matrix))]
print(s)
matrix = [[1,2,3],
[4,5,6],
[7,8,9]]
s = [col for row in matrix for col in row]
print(s)
- 带有 if 条件的嵌套推导式
s = [[x,y] for x in range(3) if x % 2 == 0 for y in range(4) if y % 3 == 0]
print(s)
s = []
for x in range(3):
if x % 2 == 0:
for y in range(4):
if y % 3 == 0:
s.append([x,y])
print(s)
''' 输出 [[0, 0], [0, 3], [2, 0], [2, 3]] '''
两个程序表示同一个意思 keep it simple & stupid