Python 的二维数组,你写对了吗?
这是「刷题躲坑」系列的第一篇文章,这个系列帮助大家躲掉刷题/代码中常见的坑。
怪事
在 Python 中,定义长度为 3
,数值全为 0
的一维列表(也就是数组)的方式有:
a = [0, 0, 0]
a = [0 for _ in range(3)]
a = [0] * 3
在刷算法题是,我们常常遇到的一个场景,就是需要定义一个和输入等长的一维列表。所以,我基本都是用上述的第 3 种方式。
如:
a = [0] * len(nums)
假设 nums
的长度是 5,那么运行完上述代码以后,a
的值为 [0, 0, 0, 0, 0]
。
我们修改一下 a
列表:
In [1]: a[0] = 666In [2]: a
Out[2]: [666, 0, 0, 0, 0]
可以看到,修改 a
列表的第 0
个元素并不会影响到其他位置的元素。
这是理所当然的事情。
可是,当数组变成二维的时候,怪事就发生了。
按照上述定义一维数组的思路,定义一个 3
行 2
列的二维数组 b
:
In [1]: b = [[0] * 2] * 3In [2]: b
Out[2]: [[0, 0], [0, 0], [0, 0]]
看起来 b
是符合要求的,没问题吧。
但是,当我们修改 b
中的元素时:
In [1]: b[0][0] = 2333In [2]: b
Out[2]: [[2333, 0], [2333, 0], [2333, 0]]
看到了吗?我们只修改了 b[0][0]
,但是 b
列表中的第 0
列的所有元素,全部都被修改了!!
是不是很奇怪??
分析
遇到这种奇怪的问题时,可以用我之前分享的【代码执行可视化工具】进行分析。
这个工具的地址是:https://pythontutor.com/
先看 Python 一维列表,在内存中的可视化运行情况。
从上面的动图可以看到,修改一维数组中的某个元素,并不会影响到其他元素。
再看按照之前方式定义的 Python 二维列表,在内存中的运行情况。
我们本以为的正确的二维列表应该是下面这样。即数组有 3
行,每行都是一个独立的长度为 2
的列表。
可实际上呢?
当我们定义 b = [[0] * 2] * 3
时,虽然看起来结果是一个 3 x 2
的二维列表,但是在内存中,数组中每行都是指向同一个长度为 2
的列表。
因此,当我们修改 b[0][0]
时,虽然只是修改了内存中的一个元素,但是由于 3
行指向的是同一个地址,因此看起来是把 3
行中的元素都修改了。
这就是怪事发生的原因。
我们在 Python 终端中看一下 b
的 3
行的内存地址(可以使用id()
函数获取内存地址),进行验证。
In [1]: b = [[0] * 2] * 3
In [2]: for i in range(3):...: print(id(b[i]))...:
140178338622720
140178338622720
140178338622720
看到 b
列表的 3
行内存地址确实一样的,和我们上面的可视化结果一致。
正确写法
上面是 Python 中常见的坑,负雪在刷题的时候,也被坑过。。
我们可以这么理解:
[0] * 2
返回的是一个内存中的地址。- 定义
[[0] * 2] * 3
时 ,[0] * 2
只运行了一次,返回了一个地址x
;二维列表中存放了3
个x
,即[x, x, x]
。
那 Python 二维数组的正确写法是什么呢?
第一种写法,你可以把所有的元素都显式的写出来,这样肯定没问题:
a = [[0, 0], [0, 0], [0, 0]]
第二种写法,我们使用 for
来定义第二个维度。是推荐的写法。
In [1]: a = [[0] * 2 for _ in range(3)]In [2]: a
Out[2]: [[0, 0], [0, 0], [0, 0]]In [3]: a[0][0] = 666In [4]: a
Out[4]: [[666, 0], [0, 0], [0, 0]]
为什么使用 for
的写法可以呢?
因为这种情况下 [0] * 2
运行了 3
次,所以返回的是 3
个不同的地址x,y,z
。二维列表中的存放的是 [x, y, z]
。
可视化结果如下:
可以看到 3
行指向不同的地址,这样的结果就是符合预期的了。
总结
今天分享了 Python 刷题中常见的一个坑:二维列表的定义。
我们通过代码运行可视化工具,分析了为什么使用 *
定义二维数组会出问题。
最后也给出了使用 for
来定义二维列表的正确写法。
了解内存知识,在编程中非常有用。
推荐新手在遇到这种问题时,使用可视化工具进行排查,非常有助于理解。
以上就是「刷题躲坑」系列的第一篇文章啦!
欢迎关注我的公众号「负雪明烛」,在编程学习路上,我们一起踩坑、躲坑。
Python 的二维数组,你写对了吗?相关推荐
- python 对二维数组赋值
最近做力扣遇到一个问题, obstacleGrid=[[0],[1]]m = len(obstacleGrid) n = len(obstacleGrid[0]) # 需要考虑m=1 n=1dp = ...
- php 写二维数组,php二维数组怎么写
php二维数组怎么写? 一个数组中的值可以是另一个数组,另一个数组的值也可以是一个数组.依照这种方式,我们可以创建二维或者三维数组: 实例<?php // 二维数组: $cars = array ...
- python输入二维数组_Python输入二维数组方法
Python输入二维数组方法 前不久对于Python输入二维数组有些不解,今日成功尝试,记以备忘.这里以输入1-9,3*3矩阵为例 n=int(input()) line=[[0]*n]*n for ...
- python读取二维数组的行列数_Python获取二维数组的行列数的2种方法
Python获取二维数组的行列数的2种方法 这篇文章主要介绍了Python获取二维数组的行列数的2种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考 ...
- python 构件二维数组_通过这四个构件块来升级您的javascript数组
python 构件二维数组 Arrays in JavaScript are something special, as they leverage the prototype feature of ...
- Python练习——二维数组中每行最大值和每行和
Python练习--二维数组中每行最大值和每行和 求一个3*3二维数组中每行的最大值和每行的和. 输入格式: 在一行中输入9个小于100的整数,其间各以一个空格间隔 输出格式: 输出3行3列的二维数组 ...
- 【python】二维数组按照某行或某列排序(numpy lexsort)
这里介绍的排序方法主要是针对最后一行和最后一列,如果要指定某一行目前没有很好的方法,有个笨办法可以先把排序的该列(或行)换到最后,排序后再换回来 曾经以为排序只能使用list的sort函数,后来发现a ...
- 定义一个二维数组,写函数来实现对该二维数组求最大值。(要求,用行指针为函数形参)
// 121219 上机任务3.cpp : 定义控制台应用程序的入口点. // /* * Copyright (c) 2012, 烟台大学计算机学院 * All rights reserved. * ...
- python二维数组怎么写_python的二维数组操作
需要在程序中使用二维数组,网上找到一种这样的用法: #创建一个宽度为3,高度为4的数组 #[[0,0,0], # [0,0,0], # [0,0,0], # [0,0,0]] myList = [[0 ...
最新文章
- dataGridView右键菜单并选中该行 http://blog.csdn.net/lanmao100/archive/2009/06/25/4298529.aspx...
- eWebEditor不支持IE8的解决方法
- ZZULIOJ 1085: 求奇数的乘积(多实例测试)
- 【转载】socket select模型
- java面试下_Java面试宝典(下)
- 戴机械手表有哪些事情就不能做了?
- zabbix 代理报错
- Matplotlib常用绘图示例
- mac input 不支持xls_如何将PDF转换成xls格式的表格
- PatchELF 修改linux下elf文件library搜索路径
- 在线画图工具ProcessOn
- 阿里电话面试经过与总结
- win10任务栏透明_桌面美化|任务栏美化
- Matlab基本操作与矩阵输入
- JBOD(Just a Bunch Of Disks,磁盘簇)简介
- ER图和EER图的区别
- 防止 Access 数据库被下载的手段。
- Facebook Move 语言 IR 编译器简介
- Delphi下的MPS
- 全国高速公路一览表_拔剑-浆糊的传说_新浪博客