拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python作业复盘:函数、切片、NumPy与Matplotlib避坑指南

Python作业复盘:函数、切片、NumPy与Matplotlib避坑指南

上周刚把python作业二交上去,成绩不算顶好,但这次从拿到题目到调试通过,踩的坑和总结的经验,我觉得比分数更有价值。如果你也是刚开始学Python、正在被课堂作业折磨的同学,这篇复盘应该能帮你省下不少时间。这次的作业说是基础题,其实从环境配置到库安装,从函数定义到数据可视化,几乎把入门阶段最常遇到的所有问题都过了一遍,做完之后再去写爬虫、做数据分析,心里会踏实很多。

作业总共四道题:一道函数计算、一道列表切片、一道NumPy数组处理、一道Matplotlib绘图导出。看着都不难,但实际操作里面全是细节。下面按我的完成顺序一点点拆开讲。

1. 先别写代码:把作业需求拆成能执行的小点

1.1 拿到题目我先做了什么

第一次看到题目的时候,我的第一反应是打开编辑器直接写。结果第一题就翻车了:题目要求函数返回多个值,我只写了一个 return,后面对照预期输出怎么都对不上。后来我学乖了,拿到任何作业先做两件事。

第一步是把每道题的要求用一句话复述清楚,拆成“输入是什么、输出是什么、中间要做什么处理”。比如第一题是“输入身高体重,输出BMI值和一个健康等级”,第二题是“给定一个列表,得到指定位置的切片并反转”,第三题是“用数组计算一堆数据的平均值和标准差”,第四题是“把折线图画出来并且横坐标刻度不重叠”。这样拆完,脑子里基本就有轮廓了。

第二步是把需要用到的知识点提前过一遍。我当时把函数定义、列表切片、NumPy基本操作、Matplotlib的常用函数在教程里迅速翻了一遍,心里有个数。别小看这一步,它能帮你提前发现哪些地方容易卡住,比如切片步长为负数时到底怎么取,画图时间隔太密怎么处理,这些后来都成了我debug的重点。

1.2 这几次作业到底在考什么

把四道题看完,其实能发现一个共同点:老师不是在考你背语法,而是在练“输入-处理-输出”这条完整链路。函数题练的是怎么封装一段逻辑,列表题练的是怎么操作批量数据,NumPy题练的是怎么处理数值型数据,画图题练的是怎么把结果可视化。这些恰恰是以后做数据分析、爬虫、甚至量化交易策略代码的时候最常用的能力。

我把考察点和对应的知识点整理成了一张表,后面复习也用得上。

题号表面任务核心知识点常见翻车点
第一题计算BMI并输出等级def定义函数、参数传递、返回值、字符串格式化忘了转换input为float,函数返回None
第二题列表切片反转列表索引、切片、负步长边界混淆、切片后返回新列表
第三题数组统计计算NumPy的array、mean、std、广播维度不一致、数组和列表混用
第四题绘图导出Matplotlib、中文显示、xticks旋转横坐标标签挤成一团、坐标轴标题乱码

看清楚考察点之后,后面每一步都围绕这些点补漏洞,效率会高很多。

2. 环境准备与工具选择:别让安装问题浪费一晚上

2.1 装好Python和VSCode就能开工吗

答案是能,但要注意几个坑。我刚开始装的是官网下载的Python,装完直接在VSCode里写代码。VSCode配置很简单,装一个Python扩展,然后把解释器路径指到Python安装目录就行。但这里有个非常隐蔽的问题:VSCode左下角选择的解释器,跟你安装Python的版本一定要对得上,否则后装库的时候会出现“代码里能import,但运行报ModuleNotFoundError”。

我自己就遇到过这种情况:系统里有一个Anaconda自带的Python,VSCode自动选了那个,然后我用终端pip install的库装到了另一个Python里,结果两边对不上。后来检查了很久才发现是解释器选错了。新手建议在VSCode里用命令面板选解释器,确认指向你常用的那个Python路径,并且在同一个终端里执行pip安装和运行脚本,能避免大量奇怪问题。

2.2 装第三方库直接用镜像源

作业里需要NumPy、Matplotlib,这两步按理说很简单,但第一次直接执行pip install numpy的时候,网络慢到怀疑人生,后来换成了国内镜像源才顺畅。我的做法是打开终端,执行:

pip install numpy matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple

这里稍微解释一下为什么用镜像源。pip默认去官方PyPI下载,虽然稳定,但有时候连接很慢。清华、阿里、豆瓣这些镜像源把PyPI的包同步了一份,下载速度快很多。以后装pandas、scikit-learn(也就是sklearn)也是一样的思路,只要加一个-i参数就能解决。需要注意的是,如果用了conda或venv虚拟环境,要在对应环境里执行pip install,别装到别的环境去。

2.3 关于环境管理的一点建议

很多教程会让你学conda或者venv,但对普通作业来说,不是必须的。我个人的体会是:第一周作业阶段,你只需要一套能跑的Python环境就够了,别引入太多概念。等你真正开始做项目,或者同时需要多个Python版本的时候,再去了解conda和venv也不迟。作业阶段遇到环境问题,优先考虑这个顺序:确认解释器路径,确认库装在了哪个环境,用镜像源重装,再检查代码里import的名字有没有写错。

3. 四道题的实操拆解与关键代码

3.1 第一题:函数定义与常见的def误区

题目大概是要求写一个计算BMI的函数,然后根据数值输出“偏瘦、正常、偏胖”这样的等级。我最初的版本长这样:

def calc_bmi(weight, height): bmi = weight / (height ** 2) if bmi < 18.5: print('偏瘦') elif bmi < 24: print('正常') else: print('偏胖') return bmi w = input('请输入体重(kg): ') h = input('请输入身高(m): ') result = calc_bmi(w, h) print(result)

跑起来发现结果很奇怪,因为input返回的一直是字符串,字符串和数字做除法会直接报错。解决办法就是在传给函数前做类型转换:

w = float(input('请输入体重(kg): ')) h = float(input('请输入身高(m): '))

这题虽然简单,但把入门阶段最容易踩的三个坑都集中踩了一遍:input需要类型转换、函数里要明确return还是print、函数名避免和内置函数冲突。我把函数名从bmi改成calc_bmi,就是为了避免和任何变量名混淆。另外函数参数和全局变量的关系也要注意,函数内部用到的变量如果没有return,外面是拿不到的。

3.2 第二题:列表切片与负步长

第二题是给定一个列表,比如numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求取索引2到索引7之间、步长为2的元素,然后反转输出。直接写:

numbers = list(range(10)) slice_part = numbers[2:8:2] print(slice_part) print(slice_part[::-1])

这里第一个print得到[2, 4, 6],第二个print得到[6, 4, 2]。切片的核心规则是左闭右开:numbers[2:8]包含索引2,但不包含索引8。负步长[::-1]是完整的反转操作,这个细节很多新手第一次会踩。我当时把切片写成了numbers[8:2:-2],顺序一下乱掉,得出来的结果和预期完全不一致。

有个生活化的类比:切片就像在一排柜子里按“起始柜到结束柜之前、每隔几个柜子取一次”的规则拿东西。正步长是从左往右拿,负步长是从右往左拿,非常容易搞混。建议每次写完切片先print一下,用肉眼确认结果再继续往下写。另外还要注意,切片不会修改原列表,它返回的是一个新的列表,如果后面还要用原列表,不用担心被破坏。

3.3 第三题:用NumPy做数组计算

第三题要求计算一组数值的平均值、标准差和中位数。这里如果用纯Python的列表写循环也能算,但代码又长又慢。正确姿势是用NumPy:

import numpy as np data = [172, 168, 175, 180, 165, 170, 169, 176, 183, 171] arr = np.array(data) print(np.mean(arr)) print(np.std(arr)) print(np.median(arr))

这里要理解一个关键差异:普通列表和NumPy数组的区别。列表里的元素是一堆独立的引用,数组则是一块连续内存,所以NumPy能高效做批量运算。比如计算每个身高和平均值的差,用数组一行就搞定:

diff = arr - np.mean(arr)

这种写法叫广播,意思是数组自动把标量和每个元素做运算。如果用Python列表写,得写for循环。我第一次用列表尝试运行这段代码,直接报“unsupported operand type(s)”,就是因为列表不支持减法广播。换成数组之后清爽很多。

这题的另一个隐藏知识点是np.mean和arr.mean()两种写法都行,结果一样。作业里如果要求保留小数,可以用np.round(result, 2)。以后做量化交易策略代码的时候,这种批量数组运算几乎无处不在,所以刚开始一定要把数组和列表的关系搞清楚。

3.4 第四题:Matplotlib画图与横坐标太密的解决方案

第四题是给一批数据画折线图,数据是逐月温度变化,大概有几十个点。我第一版写完直接plt.show(),屏幕上出现一团黑:横坐标标签全部叠在一起,根本看不清。这就是热搜里常见的“python画图横坐标太密集”问题。

原因很简单:当横坐标数量超过十几个图,Matplotlib默认把每个点都画上标签,标签之间空间不够就互相遮挡。解决办法有几种,我给一个最常用的:

import matplotlib.pyplot as plt months = ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06', '2024-07', '2024-08', '2024-09', '2024-10', '2024-11', '2024-12', '2025-01', '2025-02'] temps = [-2, 1, 8, 15, 22, 28, 30, 29, 24, 17, 9, 1, -1, 3] plt.figure(figsize=(10, 5)) plt.plot(months, temps, marker='o', color='b') plt.xticks(rotation=45) plt.xlabel('月份') plt.ylabel('温度(°C)') plt.title('月度温度变化') plt.tight_layout() plt.show()

关键就是这一行plt.xticks(rotation=45),把标签旋转45度,再加上tight_layout()自动调整间距,黑乎乎的叠字问题基本解决了。如果数据更多,比如有100个点,旋转也救不了,那就要每隔若干个点才显示一个标签:

step = 10 plt.xticks(ticks=range(0, len(months), step), labels=[months[i] for i in range(0, len(months), step)], rotation=45)

这样每隔10个点显示一个,页面立刻干净。我当时为了让图好看,还顺手设置了figure的宽度,数据少的时候用figsize=(10,5),数据多用更宽的画布,也是很实用的技巧。

4. 作业里的隐藏关卡:文件读取与Excel导出

4.1 读取文本文件时被编码坑惨了

作业的第四题还需要从本地文件读数据,文件是一行一个数值的记事本格式。我直接用open('data.txt')去读,结果运行时报UnicodeDecodeError,原因是Windows记事本保存的文件默认是GBK编码,而Python默认用UTF-8解码。解决办法是读取时显式指定编码:

with open('data.txt', 'r', encoding='utf-8') as f: lines = f.readlines()

如果文件是GBK编码,就把encoding改成'gbk'。这里有一个更稳妥的判断思路:先用记事本打开文件看看右下角显示的编码,或者用Python的chardet库自动识别,但作业阶段直接试utf-8和gbk基本能解决。

用with open的好处是文件用完后会自动关闭,不会留下文件句柄。我见过有些同学用f = open('data.txt'),用完忘记f.close(),结果在后续操作里出现各种莫名其妙的问题。所以无论读取还是写入,推荐都用with语句。

4.2 用pandas把结果写入Excel

作业最后一步要求把统计结果保存成Excel表格。我一开始还想着用csv模块手写表格,后来同学提醒才想起有pandas这个东西。pandas处理结构化数据非常方便,三行代码就能导出:

import pandas as pd result_dict = { '平均值': [np.mean(arr)], '标准差': [np.std(arr)], '中位数': [np.median(arr)] } df = pd.DataFrame(result_dict) df.to_excel('result.xlsx', index=False)

注意to_excel依赖openpyxl库,第一次运行会报ModuleNotFoundError: No module named 'openpyxl',装一下就行:

pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple

我在这个环节还踩过一个坑:pandas写出的Excel如果数组维度不对,会出现“If using all scalar values, you must pass an index”的报错。原因是用字典创建DataFrame时,如果值为标量而不是列表,pandas分不清是单行还是多行。解决办法就是用列表包一下,比如写成{'平均值': [np.mean(arr)]}而不是{'平均值': np.mean(arr)}。

对作业来说,能把结果落到Excel里,整个链路就完整了。以后在公司里自动拉表、写报表,基本就是这套东西的升级版:pandas读数据,处理完再to_excel输出。

5. 调试实录:我踩过的坑和排查方法

5.1 ModuleNotFoundError到底怎么查

这个错误我连续遇到了两次。一次是上面说的openpyxl,一次是sklearn。遇到这种报错,先不要急着重复pip install,先跑一下pip list看看包里有没有。如果确实没有,再安装。如果pip list里有,代码还是报错,重点检查两件事:当前终端里处在哪个Python环境;VSCode里选中的解释器是不是同一个。很多新手被这个问题折磨一晚上,其实就是解释器指错了。

5.2 代码运行完什么输出都没有

这种情况最让初学者抓狂。原因一般是三种:函数定义了但没调用;print拼错了;代码块缩进不对导致print在函数外面,而函数压根没执行。我有个很笨但很有效的办法:在关键位置插入print('checkpoint'),看程序到底走没走到那里。等确认逻辑没问题再把临时的print删掉,比空想快得多。

5.3 函数返回了None

第一题我一开始就犯了这个错:只print了结果,没有return,然后调用函数后用变量接收,打印出来就是None。这个问题的本质是函数默认返回None,只有写return才会返回实际值。想清楚函数是“只执行动作”还是“执行动作并给结果”,这个问题就解决了。

5.4 一张方便粘贴的常见问题速查表

报错或现象原因快速解决
ModuleNotFoundError库没装或解释器不对pip install后重跑;检查VSCode解释器
UnicodeDecodeError文件编码和指定编码不一致读取时指定encoding='utf-8'或'gbk'
UnsupportedOperandType列表直接做数学运算先把数据转成np.array
函数返回None没有return或return写得不完整检查函数末尾是否有return语句
横坐标标签重叠标签太多、间距不足用rotation=45和tight_layout,或隔几个点显示
画图中文乱码默认字体没有中文字符设置plt.rcParams['font.sans-serif'] = ['SimHei'],并解除unicode负号

中文乱码这个坑,当时也花了我十分钟。高版本Matplotlib在Windows上默认字体不含中文字符串,显示出来是一堆方框。解决方法是开头加两行:

plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False

第二行是为了让坐标轴上的负号正常显示。如果用的是Mac,字体名改成'Arial Unicode MS'或者'PingFang SC'之类的,因为系统自带字体不同。

6. 一次作业能带来的额外收获

做完这四道题,我最大的感受是:作业只是外壳,真正要学的是“遇到问题怎么拆解、怎么调试、怎么查资料”。比如这次我用到的NumPy数组、Matplotlib绘图、pandas导出Excel,看起来是几道独立题目,但它们组合起来,就是一套小型数据处理的工作流。这种工作流以后做爬虫数据分析、甚至量化交易策略代码的时候都能直接复用。比如你爬了一堆股票数据,先用pandas清洗,再用NumPy算指标,最后Matplotlib画K线和趋势图,节奏跟这次作业一模一样。

还有一个体会是:遇到报错别慌,先读报错信息。Python的报错信息里通常带着行号和错误类型,比如NameError、TypeError、IndexError,把这些关键词复制到搜索引擎,基本都有现成答案。很多同学一看到红色报错就迷茫,其实大多数报错已经在告诉你该怎么改了。

最后说一句:python作业二这种阶段性的小任务,价值不在分数,而在让你把每个“看似简单但做起来全是坑”的知识点真正过一遍。多花点时间把函数、切片、数组这些基本功打牢,后面写复杂代码的时候会轻松很多。

返回列表