
先看整句代码到底在做什么
答案是:
import numpy
arr = list(map(int, input().split()))
my_array = numpy.array(arr)
print(numpy.reshape(my_array, (3, 3)))
这段代码其实是在做 3 件事:
- 读入一行数据
- 把这一行数据拆成 9 个整数
- 把这 9 个整数变成一个 3 行 3 列的 NumPy 数组
现在卡住的两个点很典型:
input().split()到底是什么意思reshape()里面几个参数到底分别表示什么
下面把这两个地方拆开讲清楚。
input().split() 到底是什么意思
input() 是什么
input() 的作用是:
从键盘读入一整行内容,并且结果默认是字符串 str 类型。
比如你输入:
1 2 3 4 5 6 7 8 9
那么:
x = input()
print(x)
print(type(x))
得到的会是:
1 2 3 4 5 6 7 8 9
<class 'str'>
也就是说,input() 读到的是一整行文本,不是数字列表。
split() 是什么
split() 的作用是:
把一个字符串按照分隔符切开,得到一个列表。
如果什么都不写,默认按“空白字符”来切分,也就是:
- 空格
- 多个空格
- Tab
- 换行前的空白
例如:
s = "1 2 3 4 5"
print(s.split())
结果是:
['1', '2', '3', '4', '5']
注意,这里得到的还是字符串列表,不是整数列表。
也就是说:
input().split()
整体意思就是:
读入一整行字符串,再按空格拆开,变成一个个小字符串组成的列表。
比如用户输入:
1 2 3 4 5 6 7 8 9
那么:
input().split()
得到的就是:
['1', '2', '3', '4', '5', '6', '7', '8', '9']
为什么还要 map(int, input().split())
因为 split() 拆出来的每一项都是字符串,比如 '1'、'2'、'3'。
但题目需要的是整数,所以要把这些字符串一个个转成 int。
map(int, ...) 是什么意思
map 的作用可以先用最直白的话理解成:
把某个操作,依次作用到一组数据的每一个元素上。
这里写的是:
map(int, input().split())
意思就是:
把 input().split() 得到的每个字符串,都拿去做一次 int(...) 转换。
比如:
['1', '2', '3']
经过:
map(int, ...)
就相当于变成:
1, 2, 3
不过在 Python 3 里,map(...) 返回的不是直接可见的列表,而是一个可迭代对象,所以通常再套一个 list(...):
arr = list(map(int, input().split()))
最后就得到真正的列表:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
这一整句如何一步一步理解
这句代码:
arr = list(map(int, input().split()))
可以拆成 3 小步来看。
第一步:先输入一整行
text = input()
如果输入:
1 2 3 4 5 6 7 8 9
那么:
text == "1 2 3 4 5 6 7 8 9"
第二步:按空格切开
parts = text.split()
这时:
parts == ['1', '2', '3', '4', '5', '6', '7', '8', '9']
第三步:把每个字符串转成整数
arr = list(map(int, parts))
这时:
arr == [1, 2, 3, 4, 5, 6, 7, 8, 9]
等价写法是什么
你可以把它写得更展开一点,这样更适合初学者理解:
text = input()
parts = text.split()
arr = []
for x in parts:
arr.append(int(x))
print(arr)
这个写法和下面这句本质上做的是同一件事:
arr = list(map(int, input().split()))
只是前者更慢、更清楚;后者更简洁。
reshape() 到底是什么意思
reshape 是干什么的
reshape 的作用是:
在不改变数据内容的前提下,重新安排数组的形状。
比如原来是一维:
[1 2 3 4 5 6 7 8 9]
可以重新排成二维:
[[1 2 3]
[4 5 6]
[7 8 9]]
注意,它不是改数字,而是改“摆放方式”。
numpy.reshape(my_array, (3, 3)) 里面的两个参数分别是什么
这句代码:
numpy.reshape(my_array, (3, 3))
可以这样理解:
第 1 个参数:my_array
表示:
你要对哪个数组进行重塑。
也就是原始数组。
比如:
my_array = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
第 2 个参数:(3, 3)
表示:
你想把它变成什么形状。
这里 (3, 3) 是一个元组,意思是:
- 3 行
- 3 列
所以:
numpy.reshape(my_array, (3, 3))
就是:
把 my_array 重新排成 3 行 3 列。
为什么这里要写成 (3, 3),而不是 3, 3
因为 reshape 需要一个“形状说明”,这个形状通常用元组来表示。
例如:
(3, 3)表示 3 行 3 列(1, 9)表示 1 行 9 列(9, 1)表示 9 行 1 列
这几个形状都用了 9 个元素,所以都可以。
例如:
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
print(numpy.reshape(a, (3, 3)))
print(numpy.reshape(a, (1, 9)))
print(numpy.reshape(a, (9, 1)))
reshape 为什么能成功
因为你的数据正好有 9 个元素,而目标形状 (3, 3) 也需要:
3 * 3 = 9
元素个数完全一致,所以可以重塑成功。
一个非常重要的规则
reshape 前后,元素总数必须相同。
比如:
- 9 个元素可以变成
(3, 3) - 9 个元素可以变成
(1, 9) - 9 个元素可以变成
(9, 1)
但是不能变成:
(2, 2),因为只需要 4 个元素(2, 5),因为需要 10 个元素
这都会报错。
这道题的完整执行过程
下面我们把整段代码完整模拟一遍。
原代码
import numpy
arr = list(map(int, input().split()))
my_array = numpy.array(arr)
print(numpy.reshape(my_array, (3, 3)))
假设输入
1 2 3 4 5 6 7 8 9
第一步
input().split()
得到:
['1', '2', '3', '4', '5', '6', '7', '8', '9']
第二步
map(int, ...)
把每个字符串转成整数。
第三步
list(...)
得到列表:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
所以:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
第四步
my_array = numpy.array(arr)
把 Python 列表变成 NumPy 数组。
第五步
numpy.reshape(my_array, (3, 3))
把一维数组重新排成 3 行 3 列,结果就是:
[[1 2 3]
[4 5 6]
[7 8 9]]
从思路到代码,应该怎么想
做这种题时,不要一上来就盯着函数名,而是先想“数据怎么变化”。
这题的思路其实是这样的:
第一步:题目给我什么
题目给的是:
一行里有 9 个整数,中间用空格隔开。
所以你要立刻想到:
- 先读一整行
- 再按空格切开
对应代码:
input().split()
第二步:切开后是什么
切开后得到的是:
字符串列表
不是整数,所以还不能直接当数字用。
因此还要:
- 把每个字符串转成整数
对应代码:
map(int, ...)
第三步:最终想要什么
题目要的是:
一个 3×3 的 NumPy array
所以先变成 NumPy 数组:
numpy.array(arr)
再改成 3 行 3 列:
numpy.reshape(my_array, (3, 3))
最小可运行例子
你可以先单独跑这个小例子,专门观察 split() 和 reshape()。
import numpy
text = "1 2 3 4 5 6 7 8 9"
parts = text.split()
print(parts)
arr = list(map(int, parts))
print(arr)
my_array = numpy.array(arr)
print(my_array)
new_array = numpy.reshape(my_array, (3, 3))
print(new_array)
你运行后,会一步步看到数据怎么变。
初学者最容易混淆的几个点
1. input() 读到的默认是字符串
这是最常见错误。
比如输入:
1 2 3
不是直接得到数字列表,而是得到一个字符串:
"1 2 3"
2. split() 得到的还是字符串列表
比如:
['1', '2', '3']
注意有引号,说明还是字符串。
如果不转成 int,后面很多数值操作都会不对。
3. reshape() 不是随便改形状
它必须满足:
新形状需要的元素总数 = 原来数组的元素总数
这是硬规则。
4. reshape() 改的是形状,不是内容
它不会把 1 变成别的数,也不会排序。
它只是重新排列显示方式。
再补一个你很容易遇到的写法
除了:
numpy.reshape(my_array, (3, 3))
你以后还会看到这种写法:
my_array.reshape(3, 3)
这两个意思很接近。
对于初学阶段,你可以先这样记:
numpy.reshape(my_array, (3, 3)):把数组传进去再重塑my_array.reshape(3, 3):直接让这个数组自己重塑
在这道题里,用哪种都可以。
本节小结
这道题最核心的两部分可以这样记:
input().split()
表示:
读入一整行字符串,再按空格拆开,得到字符串列表。
例如:
"1 2 3".split()
得到:
['1', '2', '3']
list(map(int, input().split()))
表示:
把拆出来的每个字符串都转成整数,最后得到整数列表。
例如输入:
1 2 3
得到:
[1, 2, 3]
numpy.reshape(my_array, (3, 3))
表示:
把数组 my_array 改成 3 行 3 列的形状。
其中:
my_array是要被改形状的数组(3, 3)是目标形状,意思是 3 行 3 列
而且必须满足:
原元素总数 = 新形状所需元素总数
练习
请你自己试着写一个小程序:
把输入的一行 6 个整数,转换成一个 2 x 3 的 NumPy 数组并打印出来。
提示:
- 先用
input().split()把一行拆开 - 再把每个字符串转成整数
- 用
numpy.array()变成数组 - 用
reshape改成(2, 3)
补充:为什么 split() 后得到的是字符串,而不是整数
这个问题非常关键。很多初学者第一次看到:
input().split()
都会下意识觉得,既然我输入的是 1 2 3,那分开以后应该就是数字 1, 2, 3。但 Python 并不会这样做。
原因很简单:
input() 读进来的,本质上就是一整行文本。
也就是说,当你在键盘输入:
1 2 3
程序眼里看到的不是三个数字,而是一串字符:
"1 2 3"
既然 split() 是对字符串做操作,那么它做的事情只是:
把这串文本按空格切成几段文本。
所以:
"1 2 3".split()
得到的是:
['1', '2', '3']
这里每一项仍然是字符串,不是整数。
为什么 Python 不自动把它变成整数
因为 Python 不会替你“猜”。
比如下面这些输入:
"1 2 3"
"001 002 003"
"1.5 2.8 3.1"
"hello world"
如果 split() 自动转数字,就会出现很多问题:
- 到底该转成
int还是float - 如果里面有单词怎么办
- 如果既有数字又有字母怎么办
所以 Python 采取的规则很统一:
split() 只负责“切开字符串”,不负责“理解内容类型”。
类型转换这一步,要你自己明确写出来。
这也是为什么我们后面要写:
list(map(int, input().split()))
意思就是:
- 先拆开
- 再明确告诉 Python:这些内容我要按整数来处理
map 到底是怎么逐个处理数据的
先用一句最直白的话理解
map 的作用可以理解成:
把同一个操作,依次应用到一组数据的每一个元素上。
比如:
parts = ['1', '2', '3']
如果你写:
map(int, parts)
意思就是:
- 对
'1'做int('1') - 对
'2'做int('2') - 对
'3'做int('3')
最后就变成整数:
1, 2, 3
不过在 Python 3 里,map(...) 返回的不是现成列表,而是一个“可迭代对象”,所以通常再用 list(...) 把结果真正拿出来:
arr = list(map(int, parts))
最后得到:
[1, 2, 3]
把 map 翻译成最朴素的 for 循环
下面这两种写法,本质是一样的。
写法 1:用 map
parts = ['1', '2', '3']
arr = list(map(int, parts))
print(arr)
写法 2:用 for 循环展开
parts = ['1', '2', '3']
arr = []
for x in parts:
arr.append(int(x))
print(arr)
所以你可以把:
list(map(int, input().split()))
脑子里翻译成:
- 先得到一个字符串列表
- 再把列表里的每个元素都做一次
int() - 最后收集成列表
map 是“马上全部处理完”吗
从初学角度,你可以先把它理解成“逐个处理”。
更准确地说,在 Python 3 里,map 是一种“按需要一个一个产出结果”的对象。它不是一开始就把所有结果都摆在你面前。
但在你写:
list(map(int, input().split()))
的时候,list(...) 会把这些结果全部取出来,所以你最后还是得到一个完整列表。
对于入门阶段,你可以先这样记:
map(int, ...):让每个元素做一次intlist(...):把处理后的结果真正装进列表里
这就足够了。
如果我修改 split() 里面的参数,会怎么样
情况 1:什么都不写
text = "1 2 3 4"
print(text.split())
结果:
['1', '2', '3', '4']
这表示按空白字符分开,是最常见用法。
情况 2:指定分隔符
比如字符串里不是空格,而是逗号:
text = "1,2,3,4"
print(text.split(','))
结果:
['1', '2', '3', '4']
这说明:
你传给 split() 什么分隔符,它就按什么切。
如果你分隔符写错了,就切不开。
例如:
text = "1,2,3,4"
print(text.split())
结果会是:
['1,2,3,4']
因为这个字符串里没有空格,所以默认按空格切时,整个字符串就还是一整块。
情况 3:限制切几次
split() 还可以控制最多切几次,例如:
text = "a b c d"
print(text.split(maxsplit=1))
结果:
['a', 'b c d']
意思是:
- 只切一次
- 前面切出
'a' - 后面剩下的全部作为一个整体
这个在初学阶段不是最常用,但你以后会见到。
如果我修改 map() 里的参数,会怎么样
map 的基本结构是:
map(函数, 可迭代对象)
也就是说,map 最核心的两个部分是:
- 你想对每个元素做什么操作
- 你想处理哪一组数据
例 1:把字符串转成整数
parts = ['1', '2', '3']
print(list(map(int, parts)))
结果:
[1, 2, 3]
例 2:把字符串转成浮点数
parts = ['1.5', '2.8', '3.2']
print(list(map(float, parts)))
结果:
[1.5, 2.8, 3.2]
例 3:把每个字符串变成大写
parts = ['apple', 'banana']
print(list(map(str.upper, parts)))
结果:
['APPLE', 'BANANA']
所以你可以看到:
map 本身不决定做什么,真正决定行为的是你传进去的那个函数。
- 传
int,就转整数 - 传
float,就转浮点数 - 传别的函数,就做别的处理
如果输入里有不能转换的内容,会怎么样
比如:
parts = ['1', '2', 'hello']
print(list(map(int, parts)))
这会报错,因为:
int('hello')
是做不到的。
所以 map(int, ...) 有一个前提:
列表里的每一项都必须能成功转成整数。
再看 reshape:它的参数改了以后会怎么样
你原题中写的是:
numpy.reshape(my_array, (3, 3))
这里第二个参数 (3, 3) 表示目标形状,也就是:
- 3 行
- 3 列
如果你换成别的形状,只要总元素数对得上,就都可以。
假设原数组有 6 个元素:
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
那么下面这些都可以:
print(a.reshape(2, 3))
print(a.reshape(3, 2))
print(a.reshape(1, 6))
print(a.reshape(6, 1))
因为它们需要的元素总数分别是:
2 * 3 = 63 * 2 = 61 * 6 = 66 * 1 = 6
都刚好等于原来的 6 个元素。
什么叫“平分”或者“均分”
这里说的“平分”“均分”,放到 reshape 里,实际可以这样理解:
你想把一串元素,平均安排到若干行或若干列中。
比如有 6 个元素:
[1, 2, 3, 4, 5, 6]
如果你想排成 2 行,那么每行就要放 3 个:
[[1 2 3]
[4 5 6]]
如果你想排成 3 行,那么每行就要放 2 个:
[[1 2]
[3 4]
[5 6]]
这就是一种“整齐均分”。
如果不能均分,会怎么样
这是 reshape 里最重要的规则之一:
总元素个数必须正好等于目标形状所需的格子数。
例如你有 7 个元素:
[1, 2, 3, 4, 5, 6, 7]
你想把它变成 3 x 3:
a.reshape(3, 3)
这是不行的,因为:
3 * 3 = 9
但你只有 7 个元素,不够填满 9 个位置。
NumPy 不会帮你自动补空,也不会偷偷丢掉元素,它会直接报错。
通常会看到类似这样的错误:
ValueError: cannot reshape array of size 7 into shape (3,3)
意思就是:
- 原数组大小是 7
- 你想变成
(3,3),需要 9 个位置 - 对不上,所以失败
不能形成完整数组时,NumPy 会怎么做
标准二维数组要求每一行长度一致,也就是必须是规则矩阵。
所以如果你想把一维数据重排成二维,NumPy 要求必须“排得整整齐齐”。
它不会这样做:
- 不会自动补
0 - 不会自动补空值
- 不会自动舍弃多出来的元素
而是直接报错,让你自己决定该怎么处理。
这其实是很好的设计,因为它避免程序悄悄做错事。
如果长度不合适,通常怎么处理
方法 1:改目标形状
比如你有 8 个元素:
[1, 2, 3, 4, 5, 6, 7, 8]
不能变成 (3, 3),但可以变成:
(2, 4)(4, 2)(1, 8)(8, 1)
只要乘起来等于 8 就行。
方法 2:补齐数据
如果你就是想要 3 x 3,那你得自己补到 9 个元素。
例如:
import numpy
arr = [1, 2, 3, 4, 5, 6, 7, 8]
arr.append(0)
a = numpy.array(arr)
print(a.reshape(3, 3))
这样才行。
方法 3:截断数据
如果元素太多,也可以手动截掉一部分,再重塑。
例如有 10 个元素,但你只想做 3 x 3,那就先只取前 9 个。
用具体例子看“能不能形成完整数组”
可以成功的例子
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
print(a.reshape(2, 3))
结果:
[[1 2 3]
[4 5 6]]
因为 2 * 3 = 6,刚好。
失败的例子
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6, 7])
print(a.reshape(2, 3))
会报错,因为 2 * 3 = 6,但你有 7 个元素,多了一个,也不行。
很多初学者只注意“不够不行”,其实“多了也不行”。
规则不是“差不多就行”,而是:
必须完全相等。
这几部分合在一起,再完整看一遍
看下面这段代码:
import numpy
arr = list(map(int, input().split()))
my_array = numpy.array(arr)
print(my_array.reshape(3, 3))
假设输入是:
1 2 3 4 5 6 7 8 9
程序会这样走:
第一步:input()
得到整行字符串:
"1 2 3 4 5 6 7 8 9"
第二步:split()
拆成字符串列表:
['1', '2', '3', '4', '5', '6', '7', '8', '9']
第三步:map(int, ...)
对每个元素做 int(...):
1, 2, 3, 4, 5, 6, 7, 8, 9
第四步:list(...)
收集成列表:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
第五步:numpy.array(...)
变成 NumPy 数组。
第六步:reshape(3, 3)
重排成 3 行 3 列,因为总元素正好是 9 个,所以成功。
最容易错的几个点
第一,split() 不会自动转数字
它只负责切开,不负责类型转换。
第二,map(int, ...) 里的每一项都必须能转成整数
只要有一个不能转,整个过程就会报错。
第三,reshape 必须严格匹配元素总数
不是“大概差不多”,而是必须完全相等。
第四,不能整齐排开时,NumPy 不会替你补齐
你必须自己决定:
- 改形状
- 补数据
- 删数据
本节小结
这几个地方可以这样记:
split() 为什么得到字符串
因为 input() 本来读进来的就是文本,split() 只是把文本切开,所以结果还是文本,也就是字符串。
map 是怎么逐个处理的
map(int, data) 就是把 data 里的每个元素都依次做一次 int(...)。
你可以把它想成一个自动化的 for 循环。
改参数会怎样
- 改
split()的参数,就是改“按什么切” - 改
map()的函数,就是改“对每个元素做什么处理” - 改
reshape()的形状,就是改“想排成几行几列”
不能形成完整数组怎么办
reshape 时,元素总数必须和目标形状完全一致。
如果不一致,NumPy 会直接报错,不会自动补齐,也不会自动删除。
练习
请你自己试着判断下面每一行代码的结果,先不要运行,先靠脑子想:
text = "10 20 30"
print(text.split())
print(list(map(int, text.split())))
再判断下面这两句,哪一句会成功,哪一句会报错:
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
print(a.reshape(2, 3))
print(a.reshape(4, 2))
提示:
- 先看
split()后每个元素是什么类型 - 再看
reshape时,目标形状需要几个位置
shape 和 reshape 的区别到底是什么
这是 NumPy 里一个非常容易混淆的点,因为这两个单词长得很像,而且都和“形状”有关。
但它们的作用其实完全不同:
shape:看形状reshape:改形状
你可以先把它们记成一句最直白的话:
shape 是“现在长什么样”,reshape 是“把它改成长什么样”。
下面把这个区别彻底讲清楚。
shape 是干什么的
shape 的作用是:
查看一个数组当前的形状。
它返回的是一个元组 tuple,里面记录了每个维度的长度。
一维数组的 shape
import numpy
a = numpy.array([1, 2, 3, 4, 5])
print(a.shape)
输出:
(5,)
这里的 (5,) 表示:
- 这是一个一维数组
- 里面有 5 个元素
注意这个逗号不能忽略。(5,) 不是普通括号包个数字,它表示“一维元组”。
二维数组的 shape
import numpy
a = numpy.array([[1, 2, 3],
[4, 5, 6]])
print(a.shape)
输出:
(2, 3)
意思是:
- 2 行
- 3 列
所以 shape 的本质就是:
告诉你这个数组现在是几行几列,或者更一般地说,各个维度分别有多长。
reshape 是干什么的
reshape 的作用是:
把数组重新变成另一种形状。
例如:
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
b = a.reshape(2, 3)
print(b)
输出:
[[1 2 3]
[4 5 6]]
原来 a 是一维的,现在通过 reshape(2, 3) 变成了二维数组。
所以:
shape是“描述”reshape是“操作”
用一句类比来理解
你可以把数组想成一堆积木。
shape
是在问:
这些积木现在是怎么摆的?
比如是:
- 1 排摆 6 个
- 2 排,每排 3 个
- 3 排,每排 2 个
这就是 shape 在做的事:看当前摆法。
reshape
是在做:
把这些积木重新摆一摆。
但前提是积木总数不能变。
最核心的区别
下面是最重要的区别,你要真正记住。
| 名称 | 作用 | 本质 |
|---|---|---|
shape | 查看当前形状 | 属性 |
reshape() | 改变形状 | 方法 / 函数 |
也就是说:
shape 不负责修改
它只是告诉你:
a.shape
相当于在问:
“你现在是什么形状?”
reshape 不负责查看当前形状
它是在说:
a.reshape(2, 3)
相当于在命令:
“请你变成 2 行 3 列。”
先看一个完整例子
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
print(a)
print(a.shape)
b = a.reshape(2, 3)
print(b)
print(b.shape)
输出逻辑是:
一开始的 a
[1 2 3 4 5 6]
它是一维数组,所以:
a.shape
结果是:
(6,)
经过 reshape(2, 3) 之后
[[1 2 3]
[4 5 6]]
这时:
b.shape
结果是:
(2, 3)
所以你能看到:
shape告诉你原来是(6,)reshape把它改成(2, 3)- 再用
shape看,就变成(2, 3)
shape 为什么不加括号,reshape 为什么要加括号
这也是初学者特别容易混淆的地方。
shape 是属性
写法是:
a.shape
它像是在读取“这个对象的某个信息”。
就像:
student.name
student.age
shape 是数组自带的一个属性,表示它当前的形状,所以不用加括号。
reshape 是方法
写法是:
a.reshape(2, 3)
因为它是一个动作,要告诉它“改成什么形状”,所以要传参数。
所以它需要括号。
你可以这样记:
shape:像“信息”reshape:像“动作”
从执行过程来看,二者有什么不同
shape 的执行过程
比如:
a = numpy.array([[1, 2, 3],
[4, 5, 6]])
print(a.shape)
程序并没有改动数组,只是在读取:
- 有几行
- 有几列
最后返回:
(2, 3)
reshape 的执行过程
比如:
a = numpy.array([1, 2, 3, 4, 5, 6])
b = a.reshape(2, 3)
程序会做的事是:
- 先看原数组有多少个元素
- 再看目标形状
(2, 3)需要多少个位置 - 如果数量一致,就重新排列
- 如果数量不一致,就报错
所以 reshape 是真正会参与“变形”的。
一个特别容易混淆的地方:a.shape = (2, 3) 是什么
你有时可能会看到这种写法:
a.shape = (2, 3)
这个在某些情况下也能改形状。
但对初学者来说,不建议把这个当主要写法。
你现在先把标准、最好理解的口径记牢:
a.shape:查看形状a.reshape(2, 3):修改形状
这样最稳定,也最不容易混。
shape 和 reshape 放在一起看
下面这段代码最能看出区别:
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
print("原来的数组:", a)
print("原来的形状:", a.shape)
b = a.reshape(2, 3)
print("变形后的数组:")
print(b)
print("变形后的形状:", b.shape)
你会发现:
shape只是打印信息reshape才是把一维改成二维
如果 reshape 失败了,shape 还能看吗
当然可以。
例如:
import numpy
a = numpy.array([1, 2, 3, 4, 5])
print(a.shape)
print(a.reshape(2, 3))
这里:
a.shape会先正常输出(5,)- 但
reshape(2, 3)会报错
因为:
2 * 3 = 6
而数组只有 5 个元素。
这也说明:
shape只是读取当前状态reshape要满足严格条件才能成功
reshape 的前提条件是什么
这个一定要再强调一次:
reshape 前后,元素总数必须一致。
例如:
可以
a = numpy.array([1, 2, 3, 4, 5, 6])
a.reshape(2, 3)
因为 2 * 3 = 6
不可以
a = numpy.array([1, 2, 3, 4, 5, 6])
a.reshape(4, 2)
因为 4 * 2 = 8,和原来的 6 不一致。
你可以怎样实际判断该用哪个
遇到题目时,可以这样判断。
如果题目在问“这个数组现在是什么形状”
你就应该想到:
a.shape
比如:
- 它是几行几列
- 它是一维还是二维
- 它当前尺寸是多少
这些都属于“看形状”。
如果题目在要求“把数组变成某种形状”
你就应该想到:
a.reshape(...)
比如:
- 变成
3 x 3 - 变成
2 x 4 - 变成一列
- 变成一行
这些都属于“改形状”。
最小可运行对比例子
下面这个例子非常适合你自己跑一遍。
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6])
print("a =", a)
print("a.shape =", a.shape)
b = a.reshape(3, 2)
print("b =")
print(b)
print("b.shape =", b.shape)
你运行后会很直观地看到:
a.shape是(6,)b.shape是(3, 2)
也就是说:
shape是结果信息reshape是变形过程
常见错误与易混点
1. 把 shape 和 reshape 当成同一种东西
不是。
shape是“形状信息”reshape是“改变形状的方法”
2. 写成 a.shape()
这是错的。
因为 shape 不是函数,不需要括号。
正确写法是:
a.shape
3. 写成 a.reshape 却不给参数
这也不行。
因为 reshape 要知道你想改成什么形状。
正确写法应该像:
a.reshape(2, 3)
4. 忘记检查元素个数是否匹配
这是 reshape 最常见错误。
只要总数对不上,就一定会报错。
本节小结
可以把今天这一节压缩成下面 4 句话。
第一句
shape 是看当前形状的。
例如:
a.shape
第二句
reshape 是改目标形状的。
例如:
a.reshape(2, 3)
第三句
shape 是属性,不加括号。reshape 是方法,要加括号并传参数。
第四句
reshape 只有在元素总数完全匹配时才能成功。
练习
请你自己判断下面每一步的结果,不要先运行,先自己想。
import numpy
a = numpy.array([1, 2, 3, 4, 5, 6, 7, 8])
print(a.shape)
b = a.reshape(2, 4)
print(b)
print(b.shape)
再想一想,下面这句为什么会报错:
a.reshape(3, 3)
提示:
- 先看
a一共有几个元素 - 再看
(2, 4)和(3, 3)分别需要多少个位置
NumPy 一维数组、二维数组,到底该怎么从 shape 上判断出来
这是一个非常重要、也非常容易混淆的问题。
很多初学者看到:
a.shape
返回一个结果后,往往只会机械地读数字,但不知道这个结果到底说明了什么。
其实判断方法可以先记一句最核心的话:
看 shape 这个元组里有几个数字,就大致能判断它是几维数组。
也就是说:
shape里有 1 个数字,通常就是一维数组shape里有 2 个数字,通常就是二维数组shape里有 3 个数字,通常就是三维数组
下面我们专门把“一维”和“二维”讲透。
先回顾:shape 到底表示什么
shape 表示的是:
数组在每一个维度上分别有多长。
它返回的是一个元组 tuple。
例如:
import numpy
a = numpy.array([10, 20, 30, 40])
print(a.shape)
输出:
(4,)
这个 (4,) 的意思不是“4 行 0 列”,也不是“4×1”。
它真正表示的是:
这个数组只有 1 个维度,这个维度长度是 4。
所以这是一个一维数组。
怎么从 shape 判断是不是一维数组
一维数组的特征
如果 shape 长这样:
(5,)
(10,)
(3,)
也就是:
- 只有一个数字
- 后面通常带一个逗号
那么它就是一维数组。
例子
import numpy
a = numpy.array([1, 2, 3, 4, 5])
print(a)
print(a.shape)
输出:
[1 2 3 4 5]
(5,)
说明:
- 数组里有 5 个元素
- 它只有一个方向上的长度
- 所以它是一维数组
为什么 (5,) 是一维,而不是二维
这是初学者非常容易误解的地方。
很多人看到 (5,),会下意识觉得:
“是不是 5 行 1 列?”
不是。
因为如果是二维数组,shape 必须有两个数字,比如:
(5, 1)
这才表示:
- 5 行
- 1 列
而 (5,) 只有一个数字,所以它只是“一维长度为 5”。
也就是说:
(5,)
表示:
一维数组,长度是 5
(5, 1)
表示:
二维数组,5 行 1 列
这两个完全不是一回事。
怎么从 shape 判断是不是二维数组
二维数组的特征
如果 shape 长这样:
(2, 3)
(4, 5)
(3, 1)
(1, 6)
也就是:
- 有两个数字
- 第一个数字表示行数
- 第二个数字表示列数
那么它就是二维数组。
例子
import numpy
a = numpy.array([[1, 2, 3],
[4, 5, 6]])
print(a)
print(a.shape)
输出:
[[1 2 3]
[4 5 6]]
(2, 3)
这个 (2, 3) 表示:
- 2 行
- 3 列
所以这是一个二维数组。
用最直白的判断规则来记
你可以先这样记。
shape 是 (n,)
那就是一维数组。
例如:
(3,)(8,)(100,)
shape 是 (行数, 列数)
那就是二维数组。
例如:
(2, 3)(3, 2)(1, 5)(5, 1)
为什么“一维数组”和“只有一行的二维数组”不是同一个东西
这个地方特别关键。
看下面两个数组。
第一种:一维数组
a = numpy.array([1, 2, 3])
print(a.shape)
输出:
(3,)
这是一维数组。
第二种:二维数组,1 行 3 列
b = numpy.array([[1, 2, 3]])
print(b.shape)
输出:
(1, 3)
这是二维数组。
虽然它看起来也像“横着排了 3 个数”,但本质不同。
为什么不同?
因为:
a只有一个维度b有两个维度:第一个维度是行,第二个维度是列
所以它们不是一回事。
再看一个更容易混的例子:列向量
import numpy
c = numpy.array([[1],
[2],
[3]])
print(c.shape)
输出:
(3, 1)
这表示:
- 3 行
- 1 列
这也是二维数组,不是一维数组。
所以你现在要能清楚地区分这三种情况:
一维数组
numpy.array([1, 2, 3])
shape 是:
(3,)
二维数组,1 行 3 列
numpy.array([[1, 2, 3]])
shape 是:
(1, 3)
二维数组,3 行 1 列
numpy.array([[1], [2], [3]])
shape 是:
(3, 1)
从 shape 看“有几个维度”,本质看什么
本质上,看的是:
shape 这个元组里有几个数字。
一个数字
例如:
(4,)
说明只有一个维度,所以是一维数组。
两个数字
例如:
(2, 3)
说明有两个维度,所以是二维数组。
三个数字
例如:
(2, 3, 4)
说明有三个维度,所以是三维数组。
你现在主要学一维和二维,所以先把前两个分清楚最重要。
把“一维”和“二维”放在一起对比
下面这组对比非常重要。
| 数组写法 | shape | 几维 | 说明 |
|---|---|---|---|
numpy.array([1, 2, 3]) | (3,) | 一维 | 只有一个方向,长度为 3 |
numpy.array([[1, 2, 3]]) | (1, 3) | 二维 | 1 行 3 列 |
numpy.array([[1], [2], [3]]) | (3, 1) | 二维 | 3 行 1 列 |
numpy.array([[1, 2], [3, 4]]) | (2, 2) | 二维 | 2 行 2 列 |
这个表你最好多看几遍,因为它能解决很多初学阶段的混乱。
从“列表写法”也能辅助判断
虽然你这次问的是“怎么从 shape 判断”,但我还是顺手补一句,因为这两者经常一起看更容易懂。
一维数组常见写法
numpy.array([1, 2, 3, 4])
里面只有一层方括号。
二维数组常见写法
numpy.array([[1, 2, 3],
[4, 5, 6]])
里面是“列表套列表”。
也就是说:
- 外层表示整体
- 里面每个小列表通常表示一行
这通常就会变成二维数组。
不过真正最稳的判断方式,还是看 shape。
最小可运行例子
你可以直接运行下面这段代码,看它们的 shape 有什么不同。
import numpy
a = numpy.array([1, 2, 3])
b = numpy.array([[1, 2, 3]])
c = numpy.array([[1], [2], [3]])
d = numpy.array([[1, 2], [3, 4]])
print("a.shape =", a.shape)
print("b.shape =", b.shape)
print("c.shape =", c.shape)
print("d.shape =", d.shape)
你会看到:
a.shape = (3,)
b.shape = (1, 3)
c.shape = (3, 1)
d.shape = (2, 2)
这组例子非常有代表性。
从思路到判断,实际该怎么做
以后你拿到一个 shape,可以按下面的顺序判断。
第一步:先看有几个数字
例如:
(5,)里面有 1 个数字(2, 3)里面有 2 个数字
这一步就是在判断有几个维度。
第二步:如果是一个数字,就是一维
例如:
(8,)
表示一维数组,长度是 8。
第三步:如果是两个数字,就是二维
例如:
(3, 4)
表示二维数组,3 行 4 列。
第四步:不要把 (n,) 看成 (n, 1)
这是非常常见的误判。
(3,)是一维(3, 1)是二维
这两个差别很大。
常见错误与易混点
1. 看到 (3,) 就以为是 3 行 1 列
错。
(3,) 只有一个维度,所以是一维数组,不是二维数组。
2. 觉得 [1, 2, 3] 和 [[1, 2, 3]] 差不多
表面看很像,实际不一样。
[1, 2, 3]对应一维数组[[1, 2, 3]]对应二维数组
3. 认为“只有一行”就不算二维
错。
只要 shape 里有两个数字,它就是二维。
所以:
(1, 3)
虽然只有一行,但仍然是二维数组。
4. 认为“只有一列”就不算二维
也错。
(3, 1)
虽然只有一列,但仍然是二维数组。
本节小结
这节内容可以压缩成下面几句最核心的话。
第一条
看 shape 里有几个数字,就能大致判断是几维数组。
第二条
shape 是 (n,),说明它是一维数组。
例如:
(5,)
表示一维,长度是 5。
第三条
shape 是 (行数, 列数),说明它是二维数组。
例如:
(2, 3)
表示二维,2 行 3 列。
第四条
一定要分清:
(3,)是一维(1, 3)是二维(3, 1)也是二维
这三个非常容易混。
练习
请你自己判断下面每个数组是一维还是二维,并说出它的形状含义。
import numpy
a = numpy.array([10, 20, 30, 40])
b = numpy.array([[10, 20, 30, 40]])
c = numpy.array([[10], [20], [30], [40]])
d = numpy.array([[1, 2], [3, 4], [5, 6]])
提示:
- 先分别看它们的
shape - 数一数
shape里有几个数字 - 一个数字就是一维,两个数字就是二维
- 如果是两个数字,就再解释成“几行几列”



