第三次Python作业,说实话我拖了挺久。倒不是题目有多难,而是前两次作业我还停留在“照着教程敲一遍能跑就万事大吉”的状态,到第三次才真正开始琢磨环境怎么搭、代码怎么写才能更干净、报错了怎么快速定位。如果你是刚学Python、准备交第三次作业的初学者,或者已经在学但总在安装、报错、打包这些环节上卡壳,这篇内容应该正好适合你。我会把这次作业从环境准备到代码实现,再到最后打包交作业的完整过程拆开讲,把那些教程里一笔带过的坑都填上。
1. 环境准备:从零搭建Python开发环境
很多同学第三次作业最大的感受是“代码看着都会,一跑就报错”,十有八九问题出在环境上。我第一次装Python的时候也踩过坑,下载完双击安装,然后打开命令行输入python,告诉我不是内部或外部命令。后来才知道,安装时有个“Add Python to PATH”复选框必须勾上。这个选项默认不勾选,很多人就一路Next,装上等于没装。
1.1 Python安装:版本选择和PATH配置是第一个坑
建议直接去Python官网下载最新稳定版,当前阶段装3.10或3.11都行,不必追新。安装时务必勾选“Add Python to PATH”,然后选“Customize installation”进入下一步,把Optional Features里的所有项都勾上,尤其是pip和py launcher。
提示:如果你第一次安装的时候没勾PATH,不用急着卸载重装。去系统设置里找到“编辑环境变量”,把Python的安装目录(类似C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\)和它的Scripts子目录手动加到Path里就行。
Linux系统下情况稍微简单点,大部分发行版自带Python 3,但版本可能偏老,而且自带的pip通常需要sudo权限。我建议用apt安装python3-pip或者用官方脚本安装,但一定要注意系统环境不要乱动,避免影响系统其他工具。
环境变量为什么重要?因为Python.exe虽然装好了,但系统不知道去哪里找它。PATH就是系统查找可执行文件的路径清单。配置好以后,在命令行输入python才会进入交互模式,输入python --version才能看到版本号。很多人卡在后续的pip install、vscode配置上,根源都是这里。
1.2 开发工具选型:VSCode还是PyCharm
选编辑器是个容易纠结的点。我的建议是:如果你的电脑配置一般,或者你以后想写脚本、爬虫、数据分析这类偏轻量的东西,首选VSCode。如果你后续准备专门做Python开发,比如后端、GUI应用,想开箱即用,PyCharm Community版更省心。
VSCode配置Python其实不复杂,核心就三步:
- 安装Python扩展。
- 按Ctrl+Shift+P打开命令面板,输入“Python: Select Interpreter”,选刚才装的那个解释器。
- 新建一个.py文件,写一行print("hello"),点右上角的运行按钮。
PyCharm则简单粗暴,新建项目时它会自动识别系统里的Python解释器,自己装好requirements里的依赖,不需要手动折腾太多。但PyCharm启动慢、占内存,前期上手建议VSCode,轻快、贴近真实开发场景。
有人会问:我能不能用Notepad++或者记事本写?当然能,但代码提示和调试会让你怀疑人生。写Python超过20行代码就开始需要语法高亮和自动补全了。不要在这个阶段省事。
1.3 虚拟环境:提前避免了“库地狱”
第3次作业之前,我一直是全局pip install,装了一堆包。直到有一次发现numpy版本冲突,旧项目跑不了新代码,新项目又要求新版本,两边打架。后来才知道有虚拟环境这回事。
虚拟环境本质上就是一个独立的Python解释器和第三方库目录,你在这个环境里装的东西不影响其他项目。操作很简单:
bash复制# 在项目目录下创建虚拟环境
python -m venv venv
# Windows下激活
venv\Scripts\activate
# Linux/Mac下激活
source venv/bin/activate
激活后命令行前面会多一个(venv)前缀,这时候pip install的包都会装到当前虚拟环境里。换项目就换个虚拟环境,再也不怕版本冲突了。
作业阶段不一定非要建虚拟环境,但我建议从第三次作业开始养成这个习惯。原因很简单:后面你做爬虫、数据分析、打包exe时,依赖关系会越来越复杂,虚拟环境越早用越省心。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 作业题目解析与核心代码实现
2.1 作业要求:做一个会“咬人”的小程序
我们这次作业的要求是写一个控制台小游戏,题目叫“人狗大作战”。核心逻辑是玩家和一只狗轮流行动,狗可以咬人,人可以打狗,还会出现随机事件,比如狗突然闪避、玩家暴击。听起来很简单,但这里面其实藏了不少知识点。
我一开始想直接抄网上的游戏源码,转念一想,作业的意义在于把基础语法用起来,于是在网上找了几个参考版本,最终自己写了一个简化的回合制玩法。关键设计如下:
- 玩家和狗都有生命值、攻击力属性。
- 每回合玩家可以选择“攻击”或“逃跑”。
- 狗每回合有概率触发“闪避”或“暴击”。
- 任意一方生命值归零则游戏结束。
为什么选这个题目?因为它在一次代码里覆盖了Python最重要的几个基础点:类与对象、while循环、random随机数、if条件分支、f-string字符串格式化,还有input输入处理。这基本就是Python第三次作业应该掌握的全部核心。
2.2 核心代码:人狗大作战的完整实现
我把代码稍微整理了一下,去掉不必要的花哨功能,控制在100行以内,方便理解和调试。
python复制import random
class Character:
"""角色基类,包含名字、生命值、攻击力"""
def __init__(self, name, hp, attack):
self.name = name
self.hp = hp
self.attack = attack
def is_dead(self):
return self.hp <= 0
def take_damage(self, damage):
self.hp -= damage
if self.hp < 0:
self.hp = 0
print(f"{self.name} 受到 {damage} 点伤害,剩余生命值 {self.hp}")
def attack_target(self, target):
print(f"{self.name} 攻击了 {target.name}")
target.take_damage(self.attack)
class Player(Character):
def __init__(self, name):
super().__init__(name, hp=100, attack=15)
self.potion_count = 3
def use_potion(self):
if self.potion_count <= 0:
print("没有药水了,别乱按")
return False
self.hp += 30
if self.hp > 100:
self.hp = 100
self.potion_count -= 1
print(f"{self.name} 使用了药水,恢复30点生命值,当前生命值 {self.hp}")
return True
class Dog(Character):
def __init__(self):
super().__init__(name="恶犬", hp=80, attack=12)
def special_action(self):
# 返回'dodge'或'crit',分别表示闪避或暴击
roll = random.random()
if roll < 0.2:
return 'dodge'
elif roll < 0.35:
return 'crit'
else:
return None
def attack_target(self, target):
action = self.special_action()
if action == 'dodge':
print("恶犬灵巧地闪开了,没有受到任何伤害")
elif action == 'crit':
print("恶犬突然暴起,造成双倍伤害!")
target.take_damage(self.attack * 2)
else:
super().attack_target(target)
def main():
player = Player("你")
dog = Dog()
turn_count = 0
print("===== 人狗大作战 =====")
print("输入1攻击,输入2逃跑,输入3使用药水")
print("-" * 30)
while not player.is_dead() and not dog.is_dead():
turn_count += 1
print(f"回合 {turn_count},请选择行动:")
choice = input("1. 攻击 2. 逃跑 3. 药水 > ").strip()
if choice == "1":
dog.attack_target(player) if dog.hp <= 0 else None
player.attack_target(dog)
elif choice == "2":
if random.random() < 0.5:
print("你成功逃跑了,游戏结束")
break
else:
print("逃跑失败!狗扑了上来")
elif choice == "3":
if not player.use_potion():
continue
else:
print("无效输入,请输入1、2或3")
turn_count -= 1
continue
if dog.hp > 0:
dog.attack_target(player)
print("-" * 30)
if player.is_dead():
print("你被狗打败了,游戏结束")
elif dog.is_dead():
print("恶犬被打败了!你赢了")
print(f"共进行了 {turn_count} 回合")
if __name__ == "__main__":
main()
这段代码里有个小细节:玩家攻击前先判断狗是否已死,避免打出“鞭尸”效果,同时还能避免回合数混乱。逃跑成功那一步用break跳出循环,后面再判断胜负状态,整体逻辑比较清晰。
2.3 代码里的考点:类、随机数与循环退出条件
写这个作业最大的收获不是游戏本身,而是把几个平时零散的知识点串起来了。首先是类的继承:Player和Dog都是Character的子类,Dog重写了attack_target方法,实现了多态。这里的关键是理解print函数里的调用时机——攻击顺序、伤害计算、状态打印,每一步的顺序都会影响输出效果。
随机数的使用也是个考点。Dog的special_action函数里用了random.random()生成一个0到1之间的浮点数,然后按概率区间划分:小于0.2触发闪避,0.2到0.35之间触发暴击,其他情况普通攻击。很多初学者会直接random.randint去判断,效果也能实现,但浮点数区间的方式更直观,也方便以后调概率。
循环退出条件是这个游戏最容易写错的地方。主循环的退出条件是“玩家死亡或狗死亡”,但这个判断要在每一次攻击后重新检查。我在代码里用while not player.is_dead() and not dog.is_dead()作为外层判断,然后在狗攻击后再检查一次player状态,否则可能出现狗已经死了还在打印“狗攻击了你”的尴尬情况。
有个经典变体题叫“李白打酒”,用递推的方式模拟李白出门时有酒、遇到店就加酒、遇到花就喝酒,最后求回酒店前剩余酒量。这类题也是考查循环和状态更新的思路,原理和人狗大作战一模一样:把每个回合的状态变化理清楚,写起来就顺了。
3. 作业之外的加分项:数据可视化与exe打包
3.1 用Pandas顺手做个小分析
交作业之前,我决定给游戏加一个“战绩统计”功能,把每局战斗数据存成CSV文件,用Pandas读出来做个小分析。这不仅是为了给老师看,也是想练一练数据分析的基本流程,毕竟网上热词里“python数据分析与可视化”“python量化交易策略代码”热度一直很高,说明大家对这个方向是真感兴趣。
我写了一个简单的统计脚本,用来读取游戏记录文件,聚合玩家胜率、平均回合数等指标:
python复制import pandas as pd
df = pd.read_csv("battle_records.csv")
# 按角色分组聚合,计算平均回合数和胜率
result = df.groupby("result")["rounds"].agg(["mean", "count", "max"])
print(result)
这里就用到了热搜词里提到的groupby。它是pandas库提供的分组聚合方法,用法上相当于SQL里的GROUP BY。很多初学者会问“groupby()属于哪个库”,其实是属于pandas库的DataFrame对象方法,用来按指定列分组后做统计。把groupby和agg这两招学会,大部分日常表格统计都能搞定。
既然已经读取了数据,顺手画个图也不难。用matplotlib画一个柱状图,展示胜、负、逃跑的次数分布:
python复制import matplotlib.pyplot as plt
df["result"].value_counts().plot(kind="bar")
plt.title("人狗大作战战绩统计")
plt.savefig("result_chart.png")
整个流程本质上就是“数据采集(游戏输出CSV)—数据清洗(读取并处理)—数据分析(groupby聚合)—数据可视化(画图)”。这是当前Python学习最热的方向之一,也是上班后最实用的技能。
3.2 用PyInstaller把作业打包成exe
作业交上去之后,老师可能需要在没有Python环境的电脑上运行演示。这时候最好的办法就是把py文件打包成exe。用PyInstaller是最常见的方式:
bash复制pip install pyinstaller
pyinstaller -F -w game.py
解释一下参数:-F是生成单文件,-w是不显示黑色控制台窗口。如果游戏本身要打印输出,就不要加-w,否则窗口被隐藏了看不到信息。
打包过程中容易踩的坑有三个。第一是PyInstaller版本和Python版本不兼容,建议用最新的,如果报错就pip install --upgrade pyinstaller更新一下。第二是路径问题,脚本里如果用了相对路径读取CSV文件,打包成exe后再运行,当前工作目录可能和.py所在目录不一致,导致找不到文件。解决办法是代码里用os.path.dirname(file)拼接绝对路径,或者干脆把数据文件放在固定目录下。第三是杀毒软件误报,PyInstaller打包出来的exe偶尔会被Windows Defender拦截,这个属于正常现象,添加信任即可,但别轻易关掉杀毒软件。
打包后生成dist目录下的exe,双击就能运行。第一次打包出来的体积往往比较大,几十MB起步,这正常,因为Python运行时被一起打进去了。如果实在嫌大,可以试试UPX压缩,但收益有限。
4. 常见报错与排查实录
4.1 让人头疼的“missing nodes”和pip安装失败
这次做数据分析部分时,我想用ComfyUI跑图像工作流,结果在导入环节报了个错:“要安装缺失的节点,请先在你的Python环境中运行pip install -u --pre comfyui-m”。这个报错英文很直白:缺节点。处理办法就是按提示在Python环境里安装对应包,但要注意必须是在当前使用的虚拟环境里执行,不是全局环境。如果你装了多个Python版本,pip install很可能装到了另一个解释器里,导致执行程序时仍然找不到包。
更常见的同类报错是ModuleNotFoundError: No module named 'xxx'。解决办法很简单,pip install那个缺失的模块名就行。但有时候你明明已经pip install了,运行还是报这个错。这时候优先检查两件事:第一,当前激活的虚拟环境是哪个;第二,你有没有用python -m pip install而不是直接pip install。我习惯用python -m pip install,因为这样能确保包安装到当前解释器对应的环境里。
4.2 Excel只能写到65536行
还有一次我想把游戏数据导出到Excel,结果程序写了几万行之后突然提示文件会超过65536行,还问我要不要放弃。这个报错其实是个经典陷阱:pandas或openpyxl在写入.xls格式时,老规范对行数有硬性限制65536行,也就是2的16次方。解决办法很简单,把文件后缀改成.xlsx即可。xlsx格式的合理上限是1048576行,日常使用基本够用。
如果你只是用pandas的to_excel方法,记得确保已安装openpyxl,否则会提示需要指定engine参数。完整写法是:
python复制df.to_excel("output.xlsx", index=False, engine="openpyxl")
4.3 input()返回的竟然不是数字?
写人狗大作战时,我用input()接收玩家选择的数字,然后进行分支判断。一开始直接比较,发现怎么都不对。后来print(type(choice))一看,才知道input()返回的类型永远是字符串,不是整数。这个坑几乎是所有初学Python的人都会踩的。
解决办法是在比较前做类型转换:
python复制choice = input("请选择行动:")
if choice == "1":
# 处理攻击
或者用int()转换后比较:
python复制choice = int(input("请选择行动:"))
但用int()转换有个问题:如果用户输入了非数字,程序会直接抛ValueError异常。我后来改用字符串比较,简单而且不容易崩,这也是很多命令行小游戏的标准处理方式。
4.4 高频问题速查表
下面这张表是我从热搜词和自己踩坑经历里整理出来的高频问题,建议收藏备查。
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
| pip不是内部或外部命令 | Python安装时未勾选Add to PATH | 手动配置环境变量,或重装并勾选 |
| ModuleNotFoundError: No module named 'numpy' | 当前解释器没有安装该库 | python -m pip install numpy |
| SyntaxError: invalid syntax | 中英文符号混用、括号不匹配 | 检查代码编辑器右下角引号/括号状态 |
| UnicodeDecodeError | 读取文件编码与文件实际编码不一致 | 打开文件时指定encoding="utf-8" |
| FileNotFoundError | 当前工作目录和脚本所在目录不一致 | 使用绝对路径或者基于__file__拼接路径 |
| ValueError: invalid literal for int() | input()输入了不可转数字的内容 | 改用字符串比较或加try-except |
| ImportError: missing nodes | 依赖包缺失 | 按提示pip install对应包,注意虚拟环境 |
最后再分享一点实用经验
第三次作业真正给我带来的不是语法熟练度,而是解决问题的思路。之前遇到报错只会复制粘贴到搜索引擎,现在会先看完整的Traceback,定位是哪一行、什么类型、哪个函数抛的错,再对症下药。
如果你做完了作业还有余力,可以往两个方向扩展一下。一个是把命令行游戏改成带图形界面的版本,试试tkinter或者pygame;另一个是调用在线API做一些小工具,比如网上很多人用Python调用讯飞星火API写智能问答脚本,原理不难,关键在于学会发送HTTP请求和解析JSON响应。
说到底,“python第3次作业”只是路标,只要你把环境搭建、基础语法、类与对象、报错排查这些基本功练扎实了,后面学爬虫、数据分析、策略回测都会越来越顺。别急着追求炫技,先把这些小代码写明白,比什么都强。
