当前位置: 代码网 > it编程>前端脚本>Python > Python中列表乘法和列表推导式的区别举例详解

Python中列表乘法和列表推导式的区别举例详解

2025年04月07日 Python 我要评论
可变对象与不可变对象python中对象有两种类型:可变对象类型:list、dict、set不可变对象类型:tuple、string、int、float、bool我们可以简单理解为:可变对象类型的变量中

可变对象与不可变对象

python中对象有两种类型:

  • 可变对象类型:list、dict、set
  • 不可变对象类型:tuple、string、int、float、bool

我们可以简单理解为:

  • 可变对象类型的变量中记录是:对象的地址值
  • 不可变对象类型的变量中记录时:对象的值

可变对象类型变量 list1 和 list2 可以通过相同地址值,指向同一个对象

list1 = [1, 2, 3, 4, 5]
list2 = list1  # 将list1的地址值赋给list2,使得list1,list2指向同一个对象

list1[0] = 2  # list1 修改对象内容

print(list1)
print(list2)  # list2 和 list1 指向的是同一个对象,因此list2打印结果和list1相同

但是不可变对象类型的变量,不具备上面特点

num1 = 10
num2 = num1

num1 -= 1

print(num1)  # 9
print(num2)  # 10

生成含 x 个 不可变对象 的列表

列表乘法

list1 = [0] * 2

列表推导式

list2 = [0 for _ in range(2)]

 由于 0 是不可变对象,因此这两种方式生成的列表没有区别。

生成含 x 个 可变对象 的列表

 列表乘法

list1 = [[]] * 2

列表推导式

list2 = [[] for _ in range(2)]

[]列表,属于可变对象,此时上面两种方式生成的列表是有区别的

list1 = [[]] * 2
list2 = [[] for _ in range(2)]

print(list1)  # [[], []]
print(list2)  # [[], []]

list1[0].append(0)
list2[0].append(0)

print(list1)  # [[0], [0]]
print(list2)  # [[0], []]

通过运行上面代码,我们可以发现,list1的打印结果似乎不太对劲。我们只是向 list1[0] 中追加了一个数值0,但是list1[1] 也被追加了一个数值0。

而 list2 没有发生这样的问题。

列表类型属于可变对象类型,列表类型的变量本质记录的是对象的地址值,我们可以使用id函数来获取对象的地址值,因此我们可以将 list1 和 list2 内部元素的地址值打印出来看看

list1 = [[]] * 2
list2 = [[] for _ in range(2)]

print(list(map(id, list1)))  # [2779372310784, 2779372310784]
print(list(map(id, list2)))  # [2779372317376, 2779372633152]

可以发现,list1 中两个元素的对象地址值是相同的,而 list2 中两个元素的对象地址值是不相同的。

也就是说,list1中虽然有两个元素,但是这两个元素的对象地址值相同,即指向同一个对象,就好比两条绳子(变量)a,b牵着一头牛(对象),你通过绳子 a 把牛拽过来给它挂了个铃铛后,你再通过绳子 b 再把牛拽过来,发现它就是刚刚被挂铃铛的牛。

牛是同一头牛,但是有两条绳子牵着它。你无论通过哪个绳子拽牛,拽来的都是同一头牛。

也就说,列表乘法不会生成新的牛,只是生成了牵着同一头牛的多条绳子。

那么列表推导式,是会生成新的牛吗?我们不妨再看下面代码:

ele = []
list2 = [ele for _ in range(2)]

print(list2)  # [[], []]

list2[0].append(0)

print(list2)  # [[0], [0]]

此时,我们发现 list2 发生之前相同的问题。我们打印此时 list2 内部元素的地址值,发现内部两个元素也指向了同一个对象。

ele = []
list2 = [ele for _ in range(2)]

print(list(map(id, list2)))  # [1849845272832, 1849845272832]

造成问题出现的原因是,list2 的生成代码做了如下改变:

list2 = [[] for _ in range(2)]

变为了

ele = []
list2 = [ele for _ in range(2)]

list2 = [[] for _ in range(2)] 给了我们一种错觉,似乎这种方式可以产生新的对象,但是实际上,列表推导式只是一种语法糖,它只是对 for 循环的写法上的简化,你可以认为列表推导式:

list2 = [[] for _ in range(2)]

等价于 

list2 = []
for _ in range(2):
    list2.append([])

其中 [] 其实是一种动作,表示:创建一个空列表,比如:

  • list2 = [],表示创建一个空列表后,赋值给 list2
  • list2.append([]),表示创建一个空列表后,追加到 list2 尾部

那么:

ele = []
list2 = [ele for _ in range(2)]

其实可以认为等价于

ele = []

list2 = []
for _ in range(2):
    list2.append(ele)

上面代码中

  • ele = [],表示创建了一个空列表赋值给 ele
  • list2.append(ele),表示将 ele的地址值 追加到 list2 尾部

这种方式本质和列表乘法并无区别。

总结

列表乘法 [x] * n,本质是将要元素 x 复制 n 次。

若要重复的元素 x 是不可变对象类型,则使用列表乘法后,会将元素 x 的值复制多次,最终生成的列表中的每个元素:值相同,但是不是同一个对象。

若要重复的元素 x 是可变对象类型,则使用列表乘法后,会将元素 x 的对象地址值复制多次,最终生成的列表中元素:地址值相同,都指向同一个对象。

列表推导式,本质是一种语法糖,它只是简化了 for 循环写法。在代码理解上,我们还是应该将列表推导式当成普通 for 循环来解读。

到此这篇关于python中列表乘法和列表推导式区别的文章就介绍到这了,更多相关python列表乘法和列表推导式内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com