python列表嵌套引发的问题总结

 更新时间:2022年05月20日 09:10:16   作者:Python热爱者  
这篇文章主要介绍了python列表嵌套引发的问题总结,下面问文章引发问题来自日常工作总结,具有一定的参考价值需要的小伙伴可以参考一下

1.嵌套列表

Python中有一种内置的数据类型叫列表(list),它是一种容器,可以用来承载其他的对象(准确的说是其他对象的引用),列表中的对象可以称为列表的元素,很明显我们可以把列表作为列表中的元素,这就是所谓的嵌套列表。

嵌套列表可以模拟出现实中的表格、矩阵、2D游戏的地图(如植物大战僵尸的花园)、棋盘(如国际象棋、黑白棋)等。

2.识别坑点

在使用嵌套的列表时要小心,否则很可能遭遇非常尴尬的情况,下面是一个小例子:

def main():
names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[0] * 3] * 5
for row, name in enumerate(names):
print('请输入%s的成绩' % name)
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()

我们希望录入5个学生3门课程的成绩,于是定义了一个有5个元素的列表,而列表中的每个元素又是一个由3个元素构成的列表,这样一个列表的列表刚好跟一个表格是一致的,相当于有5行3列。

接下来我们通过嵌套的for-in循环输入每个学生3门课程的成绩。程序执行完成后我们发现,每个学生3门课程的成绩是一模一样的(尴尬),而且就是最后录入的那个学生的成绩。

3.区分两个概念

要想把这个坑填平,我们首先要区分对象和对象的引用这两个概念,而要区分这两个概念,还得先说说内存中的栈和堆。

我们经常会听人说起“堆栈”这个词,但实际上“堆”和“栈”是两个不同的概念。众所周知,一个程序运行时需要占用一些内存空间来存储数据和代码,那么这些内存从逻辑上又可以做进一步的划分。

对底层语言(如C语言)有所了解的程序员大都知道,程序中可以使用的内存从逻辑上可以为五个部分,按照地址从高到低依次是:栈(stack)、堆(heap)、数据段(data segment)、只读数据段(static area)和代码段(code segment)。

栈用来存储局部、临时变量,以及函数调用时保存现场和恢复现场需要用到的数据,这部分内存在代码块开始执行时自动分配,代码块执行结束时自动释放,通常由编译器自动管理。

堆的大小不固定,可以动态的分配和回收,因此如果程序中有大量的数据需要处理,这些数据通常都放在堆上,如果堆空间没有正确的被释放会引发内存泄露的问题,而像Python、Java等编程语言都使用了垃圾回收机制来实现自动化的内存管理(自动回收不再使用的堆空间)。

4.小例子

所以,下面的代码中,变量a并不是真正的对象,它是对象的引用,相当于记录了对象在堆空间的地址,通过这个地址我们可以访问到对应的对象。

a = object()
b = ['apple', 'pitaya', 'grape']

同理,变量b是列表容器的引用,它引用了堆空间上的列表容器,而列表容器中并没有保存真正的对象,它保存的也仅仅是对象的引用。

知道了这一点,我们可以回过头看看刚才的程序,我们对列表进行[[0]* 3] * 5操作时,仅仅是将[0, 0, 0] 这个列表的地址进行了复制,并没有创建新的列表对象。

所以,容器中虽然有5个元素,但是这5个元素引用了同一个列表对象。这一点可以通过id函数检查scores[0]和scores[1]的地址得到证实。在此我们举一个小例子,读者朋友们可以敲一敲加深印象。

a = [[0]*3]*5id(a[0])
id(a[1])
# id相等

5.正确代码

所以,正确的代码应该按照如下的方式进行修改:

def main():
names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[]] * 5
for row, name in enumerate(names):
print('请输入%s的成绩' % name)
scores[row] = [0] * 3 #变为不再嵌套
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()

或者:

def main():
names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[0] * 3 for _ in range(5)]
for row, name in enumerate(names):
print('请输入%s的成绩' % name)
scores[row] = [0] * 3
for col, subj in enumerate(subjs):
scores[row][col] = float(input(subj + ': '))
print(scores)
if __name__ == '__main__':
main()

总结

本文介绍使用嵌套列表需要注意的问题及解决措施,以此避免在使用嵌套列表或者复制对象时可能遇到的坑。

到此这篇关于python列表嵌套引发的问题总结的文章就介绍到这了,更多相关python列表嵌套内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用qt quick-ListView仿微信好友列表和聊天列表的示例代码

    使用qt quick-ListView仿微信好友列表和聊天列表的示例代码

    本文以微信好友列表为例给大家学习listview的相关知识,通过实例demo给大家详解qt quick-ListView仿微信好友列表和聊天列表的实现方法,需要的朋友参考下吧
    2021-06-06
  • python如何处理matlab的mat数据

    python如何处理matlab的mat数据

    这篇文章主要介绍了python如何处理matlab的mat数据,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • Python手写回归树的实现

    Python手写回归树的实现

    本文主要介绍了Python手写回归树的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Python开启Http Server的实现步骤

    Python开启Http Server的实现步骤

    本文主要介绍了Python开启Http Server的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • python对接ihuyi实现短信验证码发送

    python对接ihuyi实现短信验证码发送

    在本篇文章里小编给大家分享的是关于python对接ihuyi实现短信验证码发送功能,需要的朋友们可以参考下。
    2020-05-05
  • python从gbff文件中直接提取cds序列

    python从gbff文件中直接提取cds序列

    这篇文章主要为大家介绍了python从gbff文件中直接提取cds序列示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Python 除法小技巧

    Python 除法小技巧

    Python中将两个整数相除,默认结果是为整数的。但我们可以通过下面的方法,使得两个整数相除的结果为小数。
    2008-09-09
  • python3中bytes和string之间的互相转换

    python3中bytes和string之间的互相转换

    这篇文章主要介绍了python3中bytes和string之间的互相转换,文中给出了详细的介绍和示例代码,相信对大家具有一定的参考价值,有需要的朋友们下面来一起学习学习吧。
    2017-02-02
  • Python网络编程之ZeroMQ知识总结

    Python网络编程之ZeroMQ知识总结

    这篇文章主要介绍了Python网络编程之ZeroMQ知识总结,文中有非常详细的代码示例,对正在学习python的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Python实现给qq邮箱发送邮件的方法

    Python实现给qq邮箱发送邮件的方法

    这篇文章主要介绍了Python实现给qq邮箱发送邮件的方法,涉及Python邮件发送的相关技巧,需要的朋友可以参考下
    2015-05-05

最新评论