前言
写作背景
2020年,突如其来的疫情让整个世界按下了暂停键。居家隔离的日子里,我想给家里10岁的孩子找点有意义的事情做。考虑到编程既能帮孩子巩固和应用数学知识、培养逻辑思维,又充满创造乐趣,于是我决定教他学编程。
为什么选择Python?因为它简单易学,相比别的编程语言更有乐趣,又能下探到计算机的基础知识。对于孩子来说,Python就像一把入门的钥匙,能快速打开编程世界的大门。
为什么选择Python而不是Scratch?
很多家长会问:现在不是流行用Scratch教孩子编程吗?为什么选择Python?
这是一个很好的问题!Scratch确实有其优点,但对于小学高年级(3年级以上)及以上的孩子来说,Python是更好的选择。
真实的编程体验
- Scratch使用积木块拼接,更像是玩游戏,虽然有趣但距离真实的编程环境较远
- Python让孩子直接接触真实的代码和编程工具,了解什么是计算机程序、命令行、开发工具以及基本的计算机体系结构
经过实践验证,小学高年级的孩子完全有能力接受这些概念,而且他们会对能深入的控制计算机感到自豪!
更深入的概念理解
- Scratch隐藏了太多细节,孩子可能只学会了拖拽积木,但不理解背后的软件和计算机体系结构原理
- Python虽然需要写代码,但每一步都是透明的,孩子能真正理解程序是如何一行行执行的、变量是如何存储和传递数据的、语法错误是什么以及如何调试
更好的知识迁移
- Scratch的积木编程方式相对独特,学完后如果要转其他语言需要重新适应
- Python学到的编程思维和语法知识,可以轻松迁移到其他编程语言(如JavaScript、C++等)
更大的成长空间
- Scratch更适合编程启蒙(幼儿园到小学低年级)
- Python可以陪伴孩子从小学到高中,甚至大学和工作都能用到;孩子可以用Python做真正有用的项目(数据分析、网站开发、自动化工具等)
💡 给家长的建议
如果您的孩子:
- 年龄在8岁以下,Scratch可能是更好的起点
- 年龄在10-12岁(小学高年级),完全可以直接学Python
- 已经学过Scratch,现在可以挑战Python,进入真正的编程世界
这本书适合谁?
这本书是同时为家长和孩子设计的,它既可以是家长的备课教案,也可以是孩子的自学课本。
对于孩子
- 年龄:小学高年级(10-12岁)
- 数学基础:
- ✅ 掌握基本的数学运算(加减乘除)
- ✅ 了解未知数和方程的概念
- ✅ 会解简单的应用题
- 编程基础:零起点,不需要学过编程
- 学习方式:
- 在家长指导下学习
- 独立阅读和复习
- 参考书中的例题和练习
对于家长
- 数学基础:
- ✅ 具备高中数学知识
- ✅ 学习过函数的概念
- ✅ 如果家长本身会编程就更好,但不是必需的
- 电脑操作能力:具备基本的电脑操作能力即可
- 学习方式:
- 作为教学参考和备课手册
- 陪伴孩子学习,解决环境、安装和出错调试等问题
- 如果不会编程,可以先自学、操作和练习,然后再给孩子讲解教学
💡 这本书的核心目的
这本书希望通过编程教学,共建亲子关系——家长陪伴和引导孩子的成长,通过编程的创造力一起体验学习乐趣。
如果家长不会编程,也没关系!这可以变成一项共学活动:家长先自学掌握,然后教孩子。这反而会让孩子看到“爸爸妈妈也在学习“,更有激励作用!
编写原则
📝 符合儿童认知规律
考虑到小学高年级阶段孩子的知识结构特点,在内容编排上:
- ✅ 生活化引入:每个概念都用生活化的例子来引入
- ✅ 循序渐进:从简单到复杂,做好足够的逻辑台阶搭建
- ✅ 自然衔接:避免突然跳跃,让知识点自然衔接
- ✅ 类比教学:大量使用类比和比喻(比如把变量比作盒子)
- ✅ 详细说明:提供详细的步骤说明和注释
- ✅ 梯度练习:设计逐步增加的练习难度
- ✅ 适度扩展:在合适的上下文下适度扩展一些软件设计和计算机体系结构知识
👨👩👧👦 双重视角设计
这本书既可以作为家长的教学手册,也可以作为孩子的参考书:
- 对孩子:用生动有趣的语言讲解,配上大量练习
- 对家长:提供教学建议(Tips 标注的板块),指出易错点和教学技巧
📐 数学与几何知识的复习和应用
- 复习和巩固小学数学的各种知识,如数学运算和应用题、几何应用、统计概念等…
- 通过编程为数学知识找到一个应用的场合,让学校的知识能够和解决具体的问题关联起来
🎮 趣味性与实用性结合
- 练习题目贴近孩子的生活(计算图形、课表管理、小游戏)
- 从基础的命令行程序,到图形界面,再到数据报表
- 让孩子看到编程的实际用途,保持学习动力
使用指南
学习路径
整个教程分为18章,按照以下逻辑递进展开:
第一阶段:入门基础(第1-5章)
- 准备工作:安装Python和编程工具
- 输入输出:了解程序如何与人交互
- 变量类型:学习字符串、数字、布尔值
第二阶段:程序控制(第6-9章)
- 顺序执行:理解程序的执行流程
- 条件判断:学会让程序做决定
- 循环语句:掌握重复执行的技巧
- 流程图:用图形化方式理解程序逻辑
第三阶段:数据与行为组织(第10-12章)
- 列表:管理多个相关的数据
- 字典:用键值对组织信息
- 函数:学习代码中的抽象和复用
第四阶段:综合应用(第13-16章)
- 库的使用:学会使用现成的工具
- 命令行程序:制作实用的脚本工具
- 报表程序:用图表展示数据
- 图形界面:创建可视化的应用程序
第五阶段:知识扩展(第17-18章)
- 程序设计方法:了解所谓的软件设计和软件工程
- 计算机体系结构:理解程序运行的物理硬件基础
如何使用这本书?
这本书建议的使用方式是:
第一步:家长先阅读
- 家长完整阅读一遍教程,了解整体内容和结构
- 理解各章节的知识点和难易程度
- 提前熟悉要教授的知识,有针对性地备课
第二步:家长教孩子
- 按照章节顺序,循序渐进地给孩子讲解
- 演示代码的编写和运行过程
- 引导孩子理解概念,而不是死记硬背
第三步:陪伴和解决问题
- 帮助孩子解决环境配置、安装和出错调试等技术问题
- 在孩子遇到困难时提供提示和引导
- 鼓励孩子独立思考和解决问题
第四步:共建亲子关系
- 通过编程教学,培养孩子的逻辑思维和创造力
- 陪伴孩子在编程世界探索和成长
- 一起体验编程创造的乐趣
💡 如果家长不会编程
这完全不是问题!您可以:
- 先自学:自己先跟着教程学一遍,完成练习
- 先操作:安装环境,编写代码,运行程序
- 先练习:自己动手做每个例题和练习
- 再教学:掌握后再给孩子讲解和教学
把它变成一项共学活动,孩子会看到“爸爸妈妈也在努力学习“,这反而会更好地激励孩子!学习过程本身就是最好的亲子陪伴。
给家长的教学建议
⏰ 合理安排时间
- 每次学习1-2个知识点,不要贪多
- 理论讲解与练习时间比例约为1:2
- 鼓励孩子动手修改代码,观察变化
🎭 注重过程而非结果
- 编程出错是正常现象,教会孩子调试
- 让孩子解释自己的思路,培养表达能力
- 即使有AI工具,亲自编程仍然是思维训练的好方法
🎯 因材施教
- 根据孩子的接受速度调整进度
- 兴趣是最好的老师,选择孩子感兴趣的练习
- 鼓励创造性的改进和扩展
给孩子的学习建议
- 多动手:编程是动手的技能,只看不练学不会
- 多思考:理解为什么这样做,不要死记硬背
- 多提问:不懂就问家长,或者记录下来一起查资料
- 多创造:学完基础后,尝试做自己的小项目
关于AI时代的学习
有人可能会问:AI这么强大,还需要学编程吗?
这个问题我想了很久,目前给出的答案是需要的!
具两个例子:
-
计算器很早就比人类在数学计算上强了,但是孩子依旧要学习数学,具备一定的计算能力。因为这是一种基本的能力培养,也是学习其它理科的基础;
-
AI 虽然很早就在象棋(后来是围棋)上战胜了人类,但是我们依旧会陪孩子下棋,通过下棋锻炼孩子的策略性思维,并享受下棋时候的亲子乐趣!
因此,我强烈建议,家长和孩子一起学习,然后亲自给孩子教编程,除了培养孩子逻辑思考、问题分解、抽象建模的能力,更是一个和孩子一起体验创造的乐趣的亲子时光!
在这个 AI 大行其道的时代,人类的学习重在过程,不在目的!学习编程的目的是了解数字世界运行的原理,培养思维能力和创造能力,而不是一定要成为程序员。
反馈与改进
如果你在使用过程中发现任何问题,或有改进建议,欢迎一起完善这份教程,帮助更多孩子走进编程的世界,理解这个世界。
第1章 安装环境
本章导读
在开始编程之旅前,我们需要先准备好“工具箱“。就像画画需要画笔和颜料,做手工需要剪刀和胶水一样,编程也需要专门的工具。
这一章我们将会:
- 了解什么是编程语言和程序
- 安装Python编程语言
- 安装代码编辑器VS Code
- 写出并运行我们的第一个程序!
什么是编程语言?
编程语言是什么?
想象一下,你想和一个不会说中文的外国朋友交流。你们需要一种共同的语言才能互相理解。同样的道理,我们想要让计算机帮我们做事,也需要用一种计算机能理解的语言——这就是编程语言。
常见的编程语言有:
- Python:简单易学,我们用它来入门
- C语言:运行速度快,但较复杂
- Java:功能强大,常用于开发大型软件
- JavaScript:主要用于网页开发
什么是程序?
用编程语言写出来的一系列指令,就叫做程序。程序就像给计算机的一份详细说明书,告诉它要做什么、怎么做。
举个例子,如果你想让计算机计算两个数的和,程序就会告诉计算机:
- 接收第一个数字
- 接收第二个数字
- 把这两个数字相加
- 把结果显示出来
👨🏫 给家长的Tips
用“给机器人下指令“的类比来讲解,可以让孩子更容易理解程序的概念。可以和孩子一起讨论:如果我们要指挥一个机器人从教室走到操场,需要给它哪些指令?
计算机是如何工作的?
在学习编程前,让我们先了解一下计算机的基本组成。计算机就像一个人的身体,有五个主要部分在工作:
1. 输入设备(Input Device) - 就像人的眼睛和耳朵
- 键盘:用来输入命令和文字
- 鼠标:用来点击和选择
- 麦克风:用来输入声音
2. 输出设备(Output Device) - 就像人的嘴巴和动作
- 显示器:用来显示文字和图像
- 打印机:用来打印纸张
- 扬声器:用来播放声音
3. 内存(Memory) - 就像人的短期记忆
- 临时存储程序运行时的数据
- 关机后数据会丢失
- 比如:你在做数学题时草稿纸上的数字
4. 硬盘(Hard Drive) - 就像人的笔记本
- 长期保存文件和程序
- 关机后数据不会丢失
- 比如:你记在笔记本上的笔记
5. CPU(中央处理器) - 就像人的大脑
- 执行程序中的指令
- 进行计算和判断
- 控制其他所有部件
flowchart LR
A[输入设备<br/>键盘/鼠标] --> B[CPU<br/>中央处理器]
C[内存<br/>Memory] <--> B
D[硬盘<br/>存储] <--> B
B --> E[输出设备<br/>显示器/打印机]
💡 给孩子的小知识
计算机的这五个部分就像一个团队在工作:
- 输入设备把信息告诉CPU
- CPU从内存中读取指令和数据
- CPU处理数据,进行计算
- CPU把结果发送到输出设备显示
我们编写的Python程序,就是存储在硬盘上,运行时被调入内存,然后由CPU一条条执行!
👨🏫 给家长的Tips
为什么需要安装Python?
你可能会问:计算机不是已经很聪明了吗?为什么还要安装Python?
答案是:计算机的CPU只能理解“机器语言“(由0和1组成的指令)。Python是一种“高级语言“,人类容易理解,但CPU不能直接执行。
Python解释器就像一个“翻译官“,它把我们写的Python代码翻译成CPU能理解的机器语言。这就是为什么我们需要先安装Python编程语言!
类比:就像你想和一个只会说英语的外国朋友交流,如果你们都说中文,就需要一个翻译官。Python解释器就是这个“翻译官“。
安装Python
Python是我们要学习的编程语言。现在让我们在电脑上安装它。
第一步:下载Python
-
打开浏览器,访问Python官网:https://www.python.org/
-
点击网站上的 “Downloads”(下载)按钮
-
网站会自动识别你的操作系统。我们以Windows 10为例:
- 点击 “Downloads” 下拉菜单
- 选择 “Windows”
- 在下载页面找到 “Python 3.8.x”(稳定版本)
- 点击下载
⚠️ 重要提示
教程中使用Python 3.8版本。如果你下载的版本号略有不同(比如3.9或3.10),也不用担心,它们的基本用法是一样的。
第二步:安装Python
-
找到下载好的安装文件(比如
python-3.8.10-amd64.exe),双击打开 -
**非常重要!**在安装界面底部,有两个选项:
- ☑️ Add Python 3.8 to PATH(把Python添加到系统路径)
务必勾选这个选项!如果不勾选,以后使用会很不方便。
-
点击 “Install Now”(现在安装)
-
等待安装完成,可能需要几分钟
-
看到 “Setup was successful”(安装成功)后,点击 “Close”(关闭)
第三步:验证安装
让我们检查一下Python是否安装成功:
-
按
Win + R键,打开运行窗口 -
输入
cmd,按回车键,打开命令提示符 -
在黑色窗口中输入以下命令(按回车):
python --version -
如果看到类似这样的输出:
Python 3.8.10恭喜你!Python安装成功了!
👨🏫 给家长的Tips
- 什么是PATH? PATH是Windows的一个设置,告诉系统在哪里可以找到程序。勾选“Add to PATH“后,我们就能在电脑的任何位置使用Python,不需要每次都进入安装目录。
- 如果忘记勾选PATH怎么办?可以卸载Python重新安装,或者手动添加到环境变量。建议重新安装,更简单。
- 测试技巧: 可以让孩子在cmd中输入
python然后按回车,如果出现>>>符号,说明Python交互环境已启动。输入exit()退出。
安装代码编辑器
虽然Python自带一个简单的编辑器(IDLE),但我们推荐使用更专业的工具:Visual Studio Code(简称VS Code)。它免费、强大,而且用起来很舒服。
第一步:下载VS Code
-
访问VS Code官网:https://code.visualstudio.com/
-
点击大大的蓝色 “Download”(下载)按钮
-
等待下载完成
第二步:安装VS Code
-
找到下载好的安装文件(比如
VSCodeUserSetup-x64.exe),双击运行 -
一路点击 “Next”(下一步)
-
建议勾选以下选项:
- ☑️ Add “Open with Code” action to Windows Explorer(在右键菜单中添加“用Code打开“)
- ☑️ Add “Open with Code” action to Windows Explorer file context menu(在文件右键菜单中添加“用Code打开“)
这样以后我们想用VS Code打开文件或文件夹,只需要右键点击即可!
-
点击 “Install”(安装),等待完成
-
点击 “Finish”(完成)
第三步:安装Python扩展
VS Code安装好后,我们还需要告诉它“我们要用Python编程“:
-
打开VS Code
-
点击左侧的方块图标(扩展),或者按快捷键
Ctrl + Shift + X -
在搜索框中输入:
Python -
找到 “Python” 扩展(作者是 Microsoft),点击 “Install”(安装)按钮
-
等待安装完成
👨🏫 给家长的Tips
VS Code的扩展(Extension)就像给手机安装APP,可以为软件添加新功能。Python扩展让VS Code能够识别Python代码,提供语法高亮、自动补全、运行按钮等方便功能。
对孩子说: 安装扩展就像给工具箱添加新工具,让我们的编程工作更轻松!
运行第一个程序
环境都准备好了!现在让我们写并运行第一个Python程序。
创建第一个程序文件
-
在电脑上创建一个文件夹,比如命名为
python-learn(Python学习) -
进入这个文件夹,在空白处右键点击
-
选择 “Open with Code”(用Code打开)
-
VS Code打开了!在左侧资源管理器中,点击新建文件的图标(或者按
Ctrl + N) -
按
Ctrl + S保存文件,命名为hello.py
🤔 为什么是 .py?
就像Word文档用
.docx结尾,照片用.jpg结尾一样,Python程序文件使用.py作为扩展名。这样电脑就知道这个文件是Python程序。
编写第一个程序
在 hello.py 文件中输入以下代码:
print("Hello, Python!")
代码说明:
print()是Python的输出命令,可以把内容显示在屏幕上"Hello, Python!"是字符串,就是一串字符- 注意要用英文的双引号
",不要用中文的引号"
运行第一个程序
在VS Code中运行程序有好几种方法:
方法一:使用运行按钮(最简单)
- 找到代码右上角的 ▶️ 三角形按钮
- 点击它,程序就会运行
- 在下方的终端窗口中,你应该能看到:
Hello, Python!
方法二:使用快捷键
- 按
Ctrl + F5 - 选择 “Run Python File in Terminal”
- 程序运行,输出结果显示在下方
方法三:在命令行中运行
- 在VS Code中,按
Ctrl +`(反引号键)打开终端 - 在终端中输入:
python hello.py - 按回车,程序运行
恭喜你!你已经运行了第一个Python程序!🎉
练习环节
练习1:输出不同的内容
修改程序,让它输出你的名字。比如你的名字叫“小明“,程序应该是:
print("小明")
运行看看!
练习2:输出多行内容
一个程序可以有多条输出语句。试试这个:
print("我学习编程")
print("这很有趣")
print("我喜欢Python")
运行程序,看看输出了什么?
练习3:做数学题
Python还能做数学计算!试试:
print(5 + 3)
print(10 - 2)
print(4 * 5)
print(20 / 4)
👨🏫 给家长的Tips
这是观察孩子的好机会:
- 问孩子:“为什么
5 + 3不用引号,而小明要用引号?”- 答案:
5 + 3是数学运算,Python会计算结果;而带引号的是字符串,Python会原样输出。- 如果孩子不理解,没关系,下一章我们会详细讲解。
熟悉VS Code的基本操作
在进行正式编程前,让我们再熟悉一下VS Code:
新建文件
- 按
Ctrl + N新建文件 - 按
Ctrl + S保存文件,记得输入.py后缀
打开已有文件
- 在资源管理器中双击文件
- 或者在文件夹中右键文件,选择“Open with Code“
切换文件
- 如果打开了多个文件,在顶部的标签栏中点击切换
常用快捷键
Ctrl + S:保存(记得经常保存!)Ctrl + Z:撤销(撤销上一步操作)Ctrl + Y:重做(撤销后后悔了,可以重做)Ctrl + F:查找(在文件中搜索内容)
文件管理练习
让我们练习一下文件的基本操作:
- 创建一个新文件
practice1.py - 输入一些代码
- 保存文件
- 运行程序
- 关闭文件(点击文件标签的 × 号)
- 重新打开
practice1.py - 修改代码
- 保存并运行
👨🏫 给家长的Tips
培养孩子良好的文件管理习惯:
- 为不同主题的练习创建不同的文件夹
- 给文件起有意义的名字(如
rectangle.py而不是1.py)- 经常保存(可以用“每写一行代码就按一次Ctrl+S“来养成习惯)
就像整理书包一样,井井有条的文件管理会让编程更愉快!
本章小结
我们学到了什么?
-
编程语言与程序
- 编程语言是用来和计算机交流的工具
- 程序是用编程语言写的一系列指令
-
Python环境安装
- Python 3.8编程语言
- VS Code代码编辑器及Python扩展
- 验证安装是否成功
-
编写和运行程序
- 创建
.py文件 - 编写Python代码
- 在VS Code中运行程序
- 创建
-
VS Code基本操作
- 新建、保存、打开文件
- 运行程序的几种方法
- 常用快捷键
下一步预告
你成功运行了第一个程序!下一章,我们将深入学习:
- 如何在屏幕上显示各种内容
- 如何让程序接收用户输入
- 编写更有趣的程序,比如计算长方形面积
家长辅导提示
教学目标
- 孩子能说出编程语言和程序的区别
- 孩子能独立运行Python程序
- 孩子掌握VS Code的基本操作
- 孩子养成经常保存的习惯
- 孩子理解计算机的基本组成(五个主要部分)
常见问题解答
Q: 孩子觉得安装步骤太复杂怎么办? A: 可以家长负责主要安装过程,让孩子参与部分步骤,重在体验过程。
Q: VS Code界面是英文的,孩子不认识怎么办? A: 可以下载安装中文版,但是使用英文版本是一个接触和使用英语术语的好机会。常用的几个操作多用几次就记住了(File、Edit、Save等)。也可以打印一份常用操作的中文对照表。
Q: 家长不会编程,能教孩子吗? A: 完全可以!
- 共学模式:家长先自学,然后教孩子。孩子看到“爸爸妈妈也在学习“会更有激励
- 陪伴学习:不需要成为编程专家,只需陪伴和引导
- 解决问题:和孩子一起解决环境配置、安装等技术问题,出问题可以求助 AI
- 鼓励探索:鼓励孩子自己尝试,犯错也是学习的一部分
Q: 运行程序时出现错误怎么办? A:
- 检查是否用了中文标点(如中文引号““、中文括号())
- 检查代码拼写是否正确
- 查看错误提示,尝试理解
教学方式建议
1. 分阶段进行
- 第一阶段:环境安装(可以分2-3次完成)
- 第二阶段:运行第一个程序
- 第三阶段:熟悉VS Code操作
- 不要急于求成,每个阶段都充分练习
2. 多用类比和比喻
- 编程语言 = 人和计算机交流的语言
- 程序 = 给计算机的详细说明书
- Python解释器 = 翻译官
- CPU = 大脑, 内存 = 草稿纸, 硬盘 = 笔记本
3. 鼓励动手尝试
- 让孩子多修改代码,观察变化
- “如果不这样写会怎样?”——鼓励实验
- 即使出错也是宝贵的学习经验
4. 联系生活实际
- 计算机的输入输出 = 人的眼睛耳朵和嘴巴
- 程序执行 = 按菜谱做菜的步骤
- 变量 = 盒子,函数 = 快捷指令
5. 保持兴趣第一
- 不要纠结语法细节
- 多鼓励和表扬
- 让孩子看到立即可见的成果(程序运行成功)
评估与反馈
完成本章学习后,观察孩子:
- 对编程是否有兴趣?
- 遇到错误时的反应(沮丧还是好奇)?
- 是否愿意尝试修改代码?
- 能否理解计算机的基本组成?
根据孩子的反应调整后续教学节奏。记住:兴趣第一,进度第二!
知识补充:关于计算机的一些常识
Q: CPU的主频是什么意思? A: CPU的主频(比如3.0GHz)表示CPU每秒可以执行的周期数。简单理解:
- 1GHz = 每秒10亿次周期
- 3.0GHz = 每秒30亿次周期
- 这不是直接等于每秒执行30亿条指令(因为一条指令可能需要多个周期)
- 但主频越高,CPU通常越快
Q: 内存和硬盘有什么区别? A:
- 内存:
- 速度快,但容量小(如8GB、16GB)
- 断电后数据丢失
- 存储正在运行的程序和数据
- 硬盘:
- 速度相对慢,但容量大(如512GB、1TB)
- 断电后数据仍保存
- 长期存储文件和程序
Q: 为什么程序需要调入内存才能运行? A:
- 硬盘的读取速度太慢,如果直接从硬盘运行程序会非常卡
- 内存的速度快,适合CPU快速读取指令
- 类比:你要做作业时,会把书从书架(硬盘)拿到桌上(内存),因为桌面上拿取更方便
准备好继续探索了吗?让我们进入第2章,开始真正的编程吧! 🎯
输入与输出
引言
计算机程序就像一个神奇的魔法盒子,它可以接收你的输入(Input),经过处理后,再给你输出(Output)。这一章,我们要学习如何让计算机程序和你“对话“——接收你的指令和信息,然后把结果显示给你。
计算机的输入输出设备 🖥️
在我们学习编程之前,先来认识一下计算机的“五官“——输入输出设备:
输入设备:计算机用来接收信息的工具
- 🎹 键盘:像计算机的“耳朵“,接收你按下的按键
- 🖱️ 鼠标:像计算机的“手“,接收你的点击和移动
- 🎤 麦克风:像计算机的“听觉器官“,接收你的声音
输出设备:计算机用来展示信息的工具
- 📺 显示器:像计算机的“嘴巴“,把结果展示给你看
- 🔊 扬声器:像计算机的“声音“,播放音乐和音效
- 🖨️ 打印机:把计算机里的内容打印在纸上
想象一下,你在玩一个电子游戏:
- 输入:你按下键盘上的按钮、点击鼠标 → 输入设备在工作
- 处理:计算机的CPU(中央处理器)计算游戏画面
- 输出:屏幕上显示游戏画面、播放音乐、显示分数 → 输出设备在工作
我们写程序时,最常用的输入输出方式就是:
- 输入:通过键盘输入文字或数字
- 输出:在屏幕上显示文字或数字
🎯 本章目标
通过这一章,你将学会:
- 让计算机“说话“(输出)
- 让计算机“倾听“(输入)
- 用变量存储数据
- 做一个能做数学题的计算器!
输出
认识 print 函数
在Python中,让程序“说话“的方法叫做 print(打印)。print 可以把内容显示在屏幕上。
让我们试试看:
print(5)
print("Jerry") # 双引号中的是字符串,基本按照原样输出
print("Jerry, ", 10, " years old") # 多个输出,用逗号隔开
print() # 输出空行
print(5 + 3) # 输出计算结果
运行结果:
5
Jerry
Jerry, 10 years old
8
👨🏫 给家长的小贴士:
- 这里的
print是一个“函数“(function),现在孩子不用理解什么是函数,只需要知道它是一个工具,可以帮我们输出内容 - 双引号
""中的内容叫做“字符串“(string),会原样输出 - 如果没有双引号,Python会把它当作数字或变量来处理
#后面的是注释,计算机不会执行,只是给人看的说明- 教学建议:可以让孩子先运行这段代码,然后修改数值再次运行,观察输出结果的变化,这样可以让孩子理解“输出“的概念
实践:打印长方形信息
现在我们用 print 来展示一个长方形的信息:
print("rectangle")
print("---------------")
print("length : ", 5)
print("width : ", 4)
print("area : ", 5 * 4)
print("perimeter : ", (5 + 4) * 2)
运行结果:
rectangle
---------------
length : 5
width : 4
area : 20
perimeter : 18
📐 数学小知识:
- 面积 = 长 × 宽
- 周长 = (长 + 宽) × 2
- 这个例子中:面积 = 5 × 4 = 20,周长 = (5 + 4) × 2 = 18
想一想:如果要计算宽为3的长方形,如何修改程序?
答案:你需要把所有 4 改成 3:
print("rectangle")
print("---------------")
print("length : ", 5)
print("width : ", 3) # 改这里
print("area : ", 5 * 3) # 改这里
print("perimeter : ", (5 + 3) * 2) # 改这里
但是这样改来改去很麻烦,有没有更好的办法呢?
使用变量
什么是变量?
变量就像是贴了标签的盒子。
想象你的书桌上有很多盒子:
- 每个盒子上都贴着一个标签(名字)
- 你可以在盒子里放东西(值)
- 你可以随时打开盒子,看看里面是什么
- 你也可以随时换掉盒子里的东西
在Python中,我们用 = 来给变量“赋值“(给盒子装东西):
=的左边是盒子的标签(变量名)=的右边是要放进去的东西(值)
l = 5 # 把数字5放进标签为"l"的盒子
w = 4 # 把数字4放进标签为"w"的盒子
用变量改进长方形程序
现在我们用变量来重写长方形程序:
l = 5 # length(长度)的缩写
w = 4 # width(宽度)的缩写
print("rectangle")
print("---------------")
print("length : ", l)
print("width : ", w)
print("area : ", l * w)
print("perimeter : ", (l + w) * 2)
现在,如果你想计算宽为3的长方形,只需要改一个地方:
l = 5
w = 3 # 只需要改这里!
print("rectangle")
print("---------------")
print("length : ", l)
print("width : ", w)
print("area : ", l * w)
print("perimeter : ", (l + w) * 2)
变量的命名规则
给变量起名字时,要遵守一些规则:
✅ 可以用:
- 英文字母(大小写都可以)
- 数字(但不能作为开头)
- 下划线
_
❌ 不能用:
- 数字开头(如
1name) - 空格或特殊符号(如
my-name、name@) - Python的关键字(如
print、input等)
好的变量名例子:
length = 5 # 用完整的英文单词
width = 4
l = 5 # 用有意义的缩写
w = 4
my_name = "Tom" # 多个单词用下划线连接
不好的变量名例子:
a = 5 # 看不出是什么意思
x1 = 5 # 没有意义
更改变量的值
变量盒子里面的东西可以随时更换:
w = 4
print(w) # 输出:4
w = 6
print(w) # 输出:6
w = w + 1
print(w) # 输出:7(解释:把w的值加1后重新放回w里)
👨🏫 给家长的小贴士:
- 孩子可能会对
w = w + 1感到困惑,因为在数学中这是不成立的 - 在编程中,
=是“赋值“而不是“相等“ - 可以这样解释:把盒子w里的东西拿出来,加1后再放回去
- 教学方式:用实物演示,比如准备一些小积木放在盒子里,让孩子亲手操作,理解“取出、加1、放回“的过程
练习1:正方形计算器
任务:参照上面的长方形程序,写一个计算正方形周长和面积的程序。
对于一个边长为3的正方形,要能输出如下:
square
----------------
side : 3
area : 9
perimeter : 12
提示:
- 正方形只需要一个变量
side(边长) - 📐 数学知识:
- 正方形的四条边都相等
- 面积 = 边长 × 边长
- 周长 = 边长 × 4
- 这个例子中:面积 = 3 × 3 = 9,周长 = 3 × 4 = 12
点击查看答案
side = 3
print("square")
print("---------------")
print("side : ", side)
print("area : ", side * side)
print("perimeter : ", side * 4)
输入
什么是输入?
之前我们学习了“输出“,程序可以把结果显示在屏幕上。但只有输出还不够,我们希望程序能和用户“对话“。
这就需要用到输入功能!
🔄 输入输出的循环:
- 输出:程序在屏幕上显示问题(通过显示器这个输出设备)
- 用户思考:你看到问题,在脑子里想答案
- 输入:你通过键盘输入答案(通过键盘这个输入设备)
- 处理:程序接收你的答案,进行处理
- 输出:程序再次显示结果(通过显示器)
这个循环就像两个人在对话:
- 程序“说话“(输出)
- 你“说话“(输入)
- 程序理解并“回答“(处理和输出)
认识 input 函数
Python中的 input() 函数可以让程序接收你通过键盘输入的信息。
让我们一步步学习:
最简单的输入
name = input()
print("Hi, ", name)
运行这段程序时:
- 程序会停下来等待(你看不到任何提示)
- 你输入名字(比如“Tom“)并按回车
- 程序继续执行,输出
Hi, Tom
添加提示信息
print("What is your name?")
name = input()
print("Hi, ", name)
这样用户就知道该做什么了!
更简洁的写法
我们可以把提示信息直接放在 input() 的括号里:
name = input("What is your name?")
print("Hi, ", name)
👨🏫 给家长的小贴士:
- 括号里的文字叫做“参数“(parameter),现在孩子不需要理解这个词
- 可以这样解释:把提示信息“交给“ input 函数,让它在等待输入时显示出来
- 教学建议:可以用角色扮演的方式,家长扮演“程序“,孩子扮演“用户“,模拟输入输出的对话过程,帮助孩子理解程序与人的交互
让输出更美观
我们可以在问候语前加一个空行:
name = input("What is your name?")
print() # 输出一个空行
print("Hi, ", name)
或者在提示语后加换行符 \n:
name = input("What is your name?\n") # \n 表示换行
print()
print("Hi, ", name)
关于 \n:
\n是一个特殊符号,表示“换行“(new line)\叫做“转义符“,它让后面的n不再是字母n,而是代表换行
输入多个信息
现在我们让程序更聪明一点,询问用户的更多信息:
name = input("What is your name?")
age = input("How old are you?")
print("Haha, you are ", name)
运行示例:
What is your name? Tom
How old are you? 10
Haha, you are Tom
练习2:个人信息汇总
任务:写一个程序,询问用户的名字和年龄,然后输出一句话介绍他/她。
期望输出:
What is your name? Tom
How old are you? 10
Haha, you are Tom, you are 10 years old
点击查看答案
name = input("What is your name?")
age = input("How old are you?")
print()
print("Haha, you are ", name, ", you are ", age, " years old")
更漂亮的输出方式
上面的输出会有很多空格,因为 print() 默认会在逗号 , 的位置加空格。Python 3.6+ 提供了一种更漂亮的输出方式,叫做 f-string(格式化字符串):
name = input("What is your name?")
age = input("How old are you?")
print(f"Haha, you are {name}, you are {age} years old")
注意:
print()前面的字母f不能忘记!{name}和{age}会自动替换成变量的值- 这种方式更灵活,你可以自由决定在哪里加空格
给家长的小贴士:
- f-string 是 Python 3.6 引入的新特性,现代Python代码推荐使用
- 可以这样解释:字母 f 告诉Python“这里有变量要替换“
{}就像是一个小窗口,透过它可以看到变量盒子里的内容
综合练习:交互式计算器
现在让我们把输入和输出结合起来,做一个真正的交互式程序!
练习3:长方形计算器(最终版)
任务:写一个程序,询问用户长方形的长和宽,然后输出面积和周长。
期望输出示例:
rectangle
---------------
length ? 5
width ? 4
area : 20
perimeter : 18
点击查看答案
print("rectangle")
print("---------------")
l = int(input("length ? "))
w = int(input("width ? "))
print("area : ", l * w)
print("perimeter : ", (l + w) * 2)
说明:
int(input(...))先获取输入,再立即转换成数字- 这样
l和w就是数字类型,可以直接进行数学运算 - 关于
int()的详细讲解在下一章
👨🏫 给家长的小贴士:
- 这里出现了一个新问题:
input()返回的是“字符串“,不能直接做数学运算 int()函数可以把字符串转换成数字(integer,整数)- 这个知识点在第三章会详细讲解
- 如果孩子提出疑问,可以先简单解释:计算机把输入当作文字,需要告诉它“这是数字“
- 教学建议:可以演示一下不加
int()会发生什么错误,让孩子理解数据类型的重要性
综合练习:数学应用题 📝
现在让我们用输入输出功能来解决一些数学应用题!
练习4:年龄计算器
任务:写一个程序,询问用户今年的年龄,然后计算5年后的年龄。
期望输出示例:
How old are you? 10
Five years later, you will be 15 years old
点击查看答案
age = int(input("How old are you? "))
print()
print(f"Five years later, you will be {age + 5} years old")
📐 数学知识:
- 这是简单的加法运算:未来年龄 = 现在年龄 + 年数
- 本题中:15 = 10 + 5
练习5:价格计算器
任务:写一个程序,询问用户购买苹果的数量和单价,计算总价。
期望输出示例:
How many apples? 6
Price per apple? 2
Total price: 12 yuan
点击查看答案
count = int(input("How many apples? "))
price = int(input("Price per apple? "))
print()
print(f"Total price: {count * price} yuan")
📐 数学知识:
- 总价 = 单价 × 数量
- 本题中:12 = 2 × 6
练习6:速度计算器
任务:写一个程序,询问用户汽车的速度和行驶时间,计算行驶距离。
期望输出示例:
Speed (km/h)? 60
Time (hours)? 2
Distance: 120 km
点击查看答案
speed = int(input("Speed (km/h)? "))
time = int(input("Time (hours)? "))
print()
print(f"Distance: {speed * time} km")
📐 数学知识:
- 距离 = 速度 × 时间
- 本题中:120 = 60 × 2
👨🏫 给家长的小贴士:
- 这些练习都是小学数学常见的应用题类型
- 通过编程练习,可以加深孩子对数学公式的理解
- 教学建议:
- 先让孩子用纸笔算出答案,再编程验证
- 鼓励孩子自己出题,交换做题
- 可以讨论生活中还有哪些类似的计算问题
本章小结
恭喜你完成了这一章!你已经学会了:
- 输出:使用
print()在屏幕上显示内容 - 变量:用标签盒子存储和改变数据
- 输入:使用
input()获取用户输入 - f-string:用
{}和字母f美化输出 - 数学应用:用编程解决年龄、价格、距离等数学问题
重要概念:
- ✅ 变量就像贴了标签的盒子
- ✅
=是“赋值“,不是“相等“ - ✅
input()得到的是字符串 - ✅
print()可以输出多个内容,用逗号隔开 - ✅ 输入输出设备(键盘、显示器)是计算机与用户交互的“五官“
🖥️ 计算机知识回顾:
- 输入设备:键盘、鼠标、麦克风等,让计算机接收信息
- 输出设备:显示器、扬声器、打印机等,让计算机展示信息
- 程序交互:通过输入输出,程序可以和人“对话“
- 数据处理:输入 → 处理 → 输出,这是计算机工作的基本流程
📐 数学知识回顾:
- 长方形:面积 = 长 × 宽,周长 = (长 + 宽) × 2
- 正方形:面积 = 边长 × 边长,周长 = 边长 × 4
- 加法:未来年龄 = 现在年龄 + 年数
- 乘法:总价 = 单价 × 数量,距离 = 速度 × 时间
🎉 下节预告:下一章我们会详细学习“字符串“——文字在计算机中是如何存储和处理的。你会发现,文字也可以做很多有趣的操作!
💡 给家长的建议:
- 这一章是编程基础,建议让孩子多练习,熟练掌握输入输出
- 可以让孩子设计自己的“小问题“,用编程来解答
- 鼓励孩子用数学知识来解决实际问题,增强学习兴趣
- 如果孩子对某个概念不理解,可以结合生活中的例子来解释
字符串变量与操作
引言
在上一章中,我们学习了如何让程序“说话“(输出)和“倾听“(输入)。你可能已经注意到,input() 函数接收到的内容,以及 print() 函数输出的那些文字,都叫做“字符串“(string)。
字符串就是计算机处理文字信息的方式。它就像一串珍珠项链,每个字符(字母、数字、符号、汉字)都是一颗珍珠,按顺序串在一起。
💾 计算机如何存储文字?
你可能好奇,计算机怎么“记住“这些文字呢?
🖥️ 计算机的小知识:
- 计算机的内存(RAM)就像一个巨大的柜子,里面有很多小格子
- 每个格子里可以存放一个字符
- 字符串就是一连串的格子,每个格子里放一个字符
- 比如
"Hello"就需要5个格子,分别存放 H、e、l、l、o
内存中的样子:
┌───┬───┬───┬───┬───┐
│ H │ e │ l │ l │ o │
└───┴───┴───┴───┴───┘
📏 内存占用:
- 每个字符在内存中占用一定的空间
- 在Python中,一个英文字符通常占用1-2个字节
- 一个中文字符通常占用2-4个字节
- 所以,字符串越长,占用的内存空间越大
这一章,我们要深入了解:
- 什么是字符串变量
- 如何创建和使用字符串变量
- 字符串的基本操作:拼接、重复
- 如何让字符串和数字一起工作
- 📐 字符串位置与数轴的关系
回顾:变量是什么
在上一章中,我们已经学过变量的概念。还记得我们用的“盒子“类比吗?
变量就像一个盒子:
- 盒子有一个名字(变量名)
- 盒子里可以装一个东西(变量的值)
- 我们可以随时把盒子里的东西拿出来或换成别的东西
name = "小明" # 创建一个叫name的盒子,里面装了"小明"
age = "10" # 创建一个叫age的盒子,里面装了"10"
👨🏫 给家长的小贴士:
- 变量名要使用有意义的英文名字,比如用
name而不是n - 变量名区分大小写,
name和Name是两个不同的变量 - 变量名不能用数字开头,也不能包含空格
- 变量名最好用小写字母,多个单词用下划线连接,如
first_name - 教学建议:
- 变量名就像盒子的标签,要清晰说明盒子里装的是什么
- 可以用实物(盒子、标签)演示变量的概念
- 数据存储的抽象性:孩子可能对“看不见的存储“感到困惑,可以解释为:
- 变量就像在纸上写下的名字,我们可以随时查看这个名字代表什么
- 计算机内存就是计算机的“草稿纸“,用来暂时存放信息
字符串变量的创建
在Python中,创建字符串变量非常简单,只需要用引号把文字括起来。
引号的用法
Python支持三种引号:
- 双引号
"":最常用 - 单引号
'':和双引号一样,看个人喜好 - 三引号
"""或''':用于多行文字
# 使用双引号
s1 = "hello"
print(s1) # 输出:hello
# 使用单引号
s2 = 'world'
print(s2) # 输出:world
# 如果文字中本身就包含引号,可以使用另一种引号
s3 = "He said: 'Hello!'"
print(s3) # 输出:He said: 'Hello!'
s4 = 'It\'s a nice day' # 使用反斜杠转义
print(s4) # 输出:It's a nice day
👨🏫 给家长的小贴士:
- 建议让孩子主要使用双引号,这样更统一
- 如果字符串中包含双引号,就用单引号包裹
\是“转义字符“,告诉Python后面的引号是文字的一部分,不是字符串的结束- 暂时不用深入讲解转义字符的概念,孩子遇到时再解释即可
- 计算机编码知识(补充):
- 计算机不认识“字母“或“汉字“,只认识数字
- 所以需要把每个字符对应到一个数字,这就是“编码“
- ASCII码:英文字符的编码,比如A=65,B=66,a=97
- Unicode:统一的编码标准,可以表示所有语言的字符
- 现在Python默认使用Unicode,可以处理中文、日文、韩文等各种语言
- 这些知识不用深入讲,只是让孩子知道:计算机用数字来存储文字
多行字符串
有时候我们需要写很长、很多行的文字,比如一首诗或一段对话,这时可以用三引号:
poem = """静夜思
床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。"""
print(poem)
运行结果:
静夜思
床前明月光,
疑是地上霜。
举头望明月,
低头思故乡。
字符串的基本操作
1. 字符串拼接(+)
就像把两段绳子接在一起,我们可以用 + 号把两个字符串连接成一个新的字符串。
first_name = "张"
last_name = "三"
full_name = first_name + last_name
print(full_name) # 输出:张三
# 也可以直接拼接文字
greeting = "Hello, " + "World!"
print(greeting) # 输出:Hello, World!
注意:拼接时不会自动添加空格,需要自己加上:
s1 = "Hello"
s2 = "World"
# 错误:没有空格
print(s1 + s2) # 输出:HelloWorld
# 正确:手动添加空格
print(s1 + " " + s2) # 输出:Hello World
2. 字符串重复(*)
如果你想打印一条分隔线,比如 10 个 -,不需要一个一个敲出来,可以用 * 号让字符串“复制“多次:
line = "-" * 10
print(line) # 输出:----------
# 也可以用于其他文字
laugh = "哈" * 5
print(laugh) # 输出:哈哈哈哈哈
# 组合使用
border = "=" * 20
print(border)
print(" 我的通知 ")
print(border)
运行结果:
====================
我的通知
====================
3. 获取字符串长度
有时候我们需要知道一个字符串有多少个字符,可以使用 len() 函数:
name = "张三"
print(len(name)) # 输出:2
sentence = "Hello World"
print(len(sentence)) # 输出:11(包含空格)
empty = ""
print(len(empty)) # 输出:0
给家长的小贴士:
len()是 length(长度)的缩写- 空格也是字符,会被计入长度
- 每个汉字算 1 个字符(在 Python 中)
- 空字符串
""的长度是 0
实践 1:制作名片
让我们用字符串拼接来制作一张简单的名片:
# 名片程序
print("=" * 30)
name = "张小明"
age = "10岁"
school = "阳光小学"
hobby = "画画、读书"
print("姓名:" + name)
print("年龄:" + age)
print("学校:" + school)
print("爱好:" + hobby)
print("=" * 30)
运行结果:
==============================
姓名:张小明
年龄:10岁
学校:阳光小学
爱好:画画、读书
==============================
练习 1:自我介绍
请编写一个程序,输出你自己的自我介绍。要求:
- 使用变量存储你的姓名、年龄、喜欢的颜色、喜欢的食物
- 使用字符串拼接把信息组合起来
- 使用
*号制作上下边框 - 使用
len()函数显示你名字的字数
📝 点击查看参考答案
# 自我介绍程序
print("=" * 25)
# 存储个人信息
my_name = "李小花"
my_age = "9岁"
my_color = "粉色"
my_food = "冰淇淋"
# 输出信息
print("我是:" + my_name)
print("今年:" + my_age)
print("喜欢的颜色:" + my_color)
print("喜欢的食物:" + my_food)
print("我的名字有" + str(len(my_name)) + "个字")
print("=" * 25)
运行结果:
=========================
我是:李小花
今年:9岁
喜欢的颜色:粉色
喜欢的食物:冰淇淋
我的名字有3个字
=========================
给家长的小贴士:
- 如果孩子在
len()的输出拼接时遇到困难,可以提示他们用str()把数字转换成字符串 - 鼓励孩子尝试改变边框的样式和长度
字符串的索引和切片
字符串中的每个字符都有一个位置编号,这个编号叫做“索引“(index)。我们可以通过索引来获取字符串中的某个字符或某一部分。
📐 索引与数轴
在数学课上,你学过数轴吗?数轴是一条直线,上面有很多刻度,每个刻度对应一个数字:
数轴:
0 1 2 3 4 5
│ │ │ │ │ │
────┼────┼────┼────┼────┼────
│ │ │ │ │ │
字符串的索引就像数轴:
字符串: H e l l o ,
索引: 0 1 2 3 4 5
↓ ↓ ↓ ↓ ↓ ↓
- 索引 0 对应第一个字符 H (就像数轴上的 0)
- 索引 1 对应第二个字符 e (就像数轴上的 1)
- 以此类推…
📐 数学联系:
- 数轴上的每个点对应一个数字
- 字符串中的每个位置对应一个索引
- 它们都是用数字来标识“位置“的方法
索引从 0 开始
在Python中,索引从 0 开始计数,而不是 1。这对初学者来说需要适应一下:
字符串: H e l l o , W o r l d !
索引: 0 1 2 3 4 5 6 7 8 9 10 11
为什么要从0开始?
- 这与计算机的底层工作方式有关
- 可以理解为“偏移量“:要找第1个字符,需要偏移0个位置;要找第2个字符,需要偏移1个位置
- 就像在数轴上,0是起始点,不是第1个点
s = "Hello, World!"
# 获取单个字符
print(s[0]) # 输出:H(第1个字符)
print(s[4]) # 输出:o(第5个字符)
print(s[7]) # 输出:W(第8个字符)
负数索引
Python还支持从右边数,使用负数索引:
字符串: H e l l o , W o r l d !
负索引: -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
s = "Hello, World!"
print(s[-1]) # 输出:!(倒数第1个)
print(s[-6]) # 输出:W(倒数第6个)
👨🏫 给家长的小贴士:
- 可以用“从0开始“和“从-1开始倒着数“来记忆
- 索引
0是第一个字符,索引-1是最后一个字符 - 可以用手指着每个字符数给孩子看,帮助他们理解
- 数学类比:
- 可以用数轴来帮助孩子理解索引的概念
- 强调索引就像数轴上的刻度,从0开始标记位置
- 负数索引就像从数轴的右边往左数
字符串切片
切片(slice)可以获取字符串的一部分。语法是:字符串[开始位置:结束位置]
s = "Hello, World!"
# 获取子串(注意:不包含结束位置)
print(s[0:5]) # 输出:Hello(从位置0到4)
print(s[7:12]) # 输出:World(从位置7到11)
# 省略开始或结束位置
print(s[:5]) # 输出:Hello(从开头到位置4)
print(s[7:]) # 输出:World!(从位置7到结尾)
print(s[:]) # 输出:Hello, World!(复制整个字符串)
# 使用负数索引
print(s[-6:]) # 输出:World!(倒数第6个到结尾)
print(s[:-7]) # 输出:Hello(开头到倒数第7个)
重要提示:切片的“结束位置“是不包含的!s[0:5] 只包含索引 0,1,2,3,4,不包含 5。
给家长的小贴士:
- 切片的概念对孩子来说可能比较抽象,可以用“切蛋糕“来类比
- 强调“结束位置不包含“这个规则
- 建议先掌握基本用法
s[开始:结束],负数索引可以以后慢慢理解 - 如果孩子感到困惑,不要强求,以后用到时再巩固
练习 2:名字的秘密
编写一个程序,分析一个名字:
- 获取名字的第一个字
- 获取名字的最后一个字
- 如果名字是两个字,分别输出两个字
- 如果名字是三个字,输出中间的字
- 使用
len()判断名字有几个字
📝 点击查看参考答案
# 名字分析程序
name = "张小明"
# 输出名字长度
length = len(name)
print("名字有" + str(length) + "个字")
# 获取第一个字
first = name[0]
print("第一个字:" + first)
# 获取最后一个字
last = name[-1]
print("最后一个字:" + last)
# 根据长度做不同处理
if length == 2:
print("姓:" + name[0])
print("名:" + name[1])
elif length == 3:
print("姓:" + name[0])
print("名:" + name[1:3])
给家长的小贴士:
- 这个练习需要用到第5章的条件语句,如果孩子还没学,可以先让他们处理固定长度的名字
- 可以让孩子先试试处理自己的名字,然后试试同学的不同长度的名字
- 这个练习展示了字符串操作的实际应用
字符串和数字的转换
还记得我们在上一章遇到过一个问题吗?当我们用 input() 获取数字时,程序计算长方形面积出错了:
l = input("length ?\n") # 输入:5
w = input("weight ?\n") # 输入:3
print(l * w) # 错误!输出:333(而不是15)
为什么会这样?因为 input() 得到的是字符串,不是数字!字符串的 * 操作是重复,不是乘法:
s = "3"
print(s * 5) # 输出:33333(重复5次)
字符串转数字:int()
要让字符串“变成“数字,我们需要使用 int() 函数:
s = "5"
n = int(s) # 把字符串"5"转换成数字5
print(n * 3) # 输出:15(这是数学乘法)
# 在输入时直接转换
l = input("length ?\n")
w = input("weight ?\n")
# 转换成数字
l = int(l)
w = int(w)
# 现在可以正常计算了
print("面积:", l * w) # 输出:面积:15
数字转字符串:str()
有时候我们也需要把数字转换成字符串,比如拼接文字:
age = 10 # 这是一个数字
message = "我今年" + age + "岁" # 错误!不能直接拼接
# 需要转换
age = 10
message = "我今年" + str(age) + "岁" # 正确
print(message) # 输出:我今年10岁
给家长的小贴士:
int是 integer(整数)的缩写str是 string(字符串)的缩写- 强调:字符串的
*是重复,数字的*是乘法 - 这个转换过程叫做“类型转换“(type conversion)
- 可以用“翻译“来类比:就像把中文翻译成英文,我们把“字符串“翻译成“数字“
实践 2:改进的长方形计算器
现在我们可以修复上一章的计算器程序了:
# 长方形计算器(改进版)
print("=" * 30)
print(" 长方形计算器 ")
print("=" * 30)
# 获取输入
l = input("请输入长度(数字):")
w = input("请输入宽度(数字):")
# 转换成数字
l = int(l)
w = int(w)
# 计算
area = l * w
perimeter = (l + w) * 2
# 输出结果
print()
print("计算结果:")
print("-" * 20)
print("长度:" + str(l))
print("宽度:" + str(w))
print("面积:" + str(area))
print("周长:" + str(perimeter))
print("-" * 20)
运行示例:
==============================
长方形计算器
==============================
请输入长度(数字):5
请输入宽度(数字):3
计算结果:
--------------------
长度:5
宽度:3
面积:15
周长:16
--------------------
练习 3:正方形计算器
编写一个完整的正方形计算器程序:
- 询问用户正方形的边长
- 计算正方形的面积和周长
- 输出格式化结果(使用拼接和重复)
- 添加分隔线和标题
📝 点击查看参考答案
# 正方形计算器
print("=" * 25)
print(" 正方形计算器 ")
print("=" * 25)
print()
# 获取边长并转换
side = input("请输入正方形的边长:")
side = int(side)
# 计算
area = side * side
perimeter = side * 4
# 输出
print()
print("✿ 计算结果 ✿")
print("-" * 20)
print("边长:" + str(side))
print("面积:" + str(area))
print("周长:" + str(perimeter))
print("-" * 20)
print()
print("小提示:")
print(" 面积 = 边长 × 边长")
print(" 周长 = 边长 × 4")
字符串的常用方法
在Python中,字符串有很多内置的“工具“,叫做“方法“(method)。这些方法可以让字符串做各种有趣的事情。
大小写转换
s = "Hello World"
# 全部大写
print(s.upper()) # 输出:HELLO WORLD
# 全部小写
print(s.lower()) # 输出:hello world
# 首字母大写
print(s.title()) # 输出:Hello World
去除空格
s = " hello "
# 去除两边空格
print(s.strip()) # 输出:hello
# 去除左边空格
print(s.lstrip()) # 输出:hello
# 去除右边空格
print(s.rstrip()) # 输出: hello
查找和替换
s = "Hello World"
# 查找子串位置
print(s.find("World")) # 输出:6
print(s.find("Python")) # 输出:-1(找不到)
# 替换
print(s.replace("World", "Python")) # 输出:Hello Python
判断
# 判断开头
s = "Hello World"
print(s.startswith("Hello")) # 输出:True
print(s.startswith("World")) # 输出:False
# 判断结尾
print(s.endswith("World")) # 输出:True
# 判断全是数字
print("123".isdigit()) # 输出:True
print("abc".isdigit()) # 输出:False
# 判断全是字母
print("abc".isalpha()) # 输出:True
print("abc123".isalpha()) # 输出:False
给家长的小贴士:
- 这些方法的语法是
字符串.方法名(),可以理解为“让字符串做什么事“ - 方法名后面的括号
()是必须的,即使里面什么都不放 - 暂时不需要深入理解“方法“的概念,孩子只要会用即可
- 第5章我们会学到,
True和False是布尔值,用于判断
综合练习:密码检查器
让我们做一个简单的密码检查器:
- 密码不能少于6个字符
- 密码必须包含字母和数字
- 去除密码前后的空格
# 密码检查器
print("🔐 密码检查器 🔐")
print("=" * 25)
print()
# 获取密码
password = input("请输入密码:")
# 去除空格
password = password.strip()
# 检查长度
if len(password) < 6:
print("❌ 密码太短了,至少需要6个字符")
else:
# 检查是否包含数字
has_digit = False
for char in password:
if char.isdigit():
has_digit = True
break
# 检查是否包含字母
has_alpha = False
for char in password:
if char.isalpha():
has_alpha = True
break
if has_digit and has_alpha:
print("✅ 密码符合要求!")
else:
print("❌ 密码必须包含字母和数字")
if not has_digit:
print(" 缺少数字")
if not has_alpha:
print(" 缺少字母")
给家长的小贴士:
- 这个练习用到了第5章的条件语句和第6章的循环语句
- 如果孩子还没学到,可以先做简化版:只检查长度
- 这是一个实际应用的例子,让孩子看到编程的实用性
字符串的格式化(补充)
在第2章中,我们学习了用 + 拼接字符串。Python还有更强大的格式化方法。
f-string(推荐)
f-string 是Python 3.6引入的新特性,非常方便:
name = "小明"
age = 10
# 使用 f-string
message = f"我叫{name},今年{age}岁"
print(message) # 输出:我叫小明,今年10岁
# 可以进行计算
side = 5
area = side * side
print(f"边长是{side}的正方形,面积是{area}")
给家长的小贴士:
- f-string 的
f表示 format(格式化) - 花括号
{}中的变量会被替换成它的值 - 这比用
+和str()方便很多 - 建议让孩子使用 f-string,这是现代Python的推荐方式
章节小结
恭喜你完成了这一章!让我们回顾一下学到的内容:
核心概念
- 字符串:用引号括起来的一串字符
- 字符串变量:存储字符串的变量
- 索引:字符在字符串中的位置(从0开始)
- 切片:获取字符串的一部分
- 类型转换:
int()转成数字,str()转成字符串
常用操作
- 拼接:
+把两个字符串连起来 - 重复:
*让字符串重复多次 - 长度:
len()获取字符个数 - 索引:
s[0]获取第1个字符,s[-1]获取最后1个字符 - 切片:
s[0:5]获取从位置0到4的子串
常用方法
s.upper()/s.lower():大小写转换s.strip():去除空格s.find():查找子串s.replace():替换s.isdigit()/s.isalpha():判断
重要提示
- ✅ 字符串的
*是重复,数字的*是乘法 - ✅
input()得到的是字符串,需要int()转换才能计算 - ✅ 索引从 0 开始,切片不包括结束位置
- ✅ 字符串在内存中占用空间,越长占用越多
🖥️ 计算机知识回顾
- 内存存储:字符串存在内存的格子中,每个字符占一个格子
- 字符编码:计算机用数字来存储文字(ASCII、Unicode)
- 内存占用:字符越长,占用的内存空间越大
- 数据抽象:变量是数据的“标签“,让我们方便地访问和操作数据
📐 数学知识回顾
- 数轴类比:字符串的索引就像数轴上的刻度
- 位置标记:从0开始标记位置,是数学和编程中常用的方法
- 负数概念:负数索引就像从数轴右边往左数
给家长的小贴士:教学建议
教学重点
- 变量概念:用“盒子“类比,多举生活中的例子
- 类型转换:这是最容易出错的地方,要强调字符串和数字的区别
- 索引从0开始:这对孩子来说很反直觉,需要多练习
- 切片不包括结束位置:同样需要反复强调
常见问题及解答
-
问:为什么索引要从0开始?
- 答:这是计算机科学的传统,可以解释为“偏移量“——第1个字符的偏移量是0。如果孩子不理解,就说“这是规定,记住就好“。
-
问:什么时候用单引号,什么时候用双引号?
- 答:都可以,但要保持一致。建议主要用双引号,除非文字中包含双引号。
-
问:为什么
int("3.5")会出错?- 答:
int()只能转换整数,"3.5"是小数。这是进阶内容,现在先记住int()转换整数即可。
- 答:
-
问:
len()计算的是字数还是字符数?- 答:是字符数。在Python中,每个汉字、字母、符号、空格都是1个字符。
练习建议
- 让孩子用字符串操作制作各种“小工具“:名片生成器、密码检查器、名字分析器
- 多用生活中的例子:名字、地址、课程表
- 鼓励孩子尝试不同的组合,发现新玩法
挑战练习
-
回文检查器:编写程序检查一个词或句子是否是“回文“(正读反读都一样,如“上海自来水来自海上“)
-
名字生成器:输入姓氏和名字,生成3个不同的昵称
-
文字加密器:把每个字母替换成字母表中下一个字母(a→b, b→c, …, z→a)
-
格式化输出:把一个数字(如123456789)格式化成货币格式(如“123,456,789“)
🔗 下一章:数值变量与操作
在下一章中,我们将学习:
- 整数和小数的区别
- 数值的运算(加减乘除、求余数、幂运算)
- 数学函数的使用
- 数值的格式化输出
字符串帮我们处理文字,数值帮我们处理数字。两者结合起来,我们就可以编写更强大的程序了!
数值变量与操作
引言:生活中的数字
小明,你有没有想过,我们每天要和多少数字打交道?
- 📅 早上7:30起床,7:50出门
- 🚶 从家走到学校需要15分钟
- 📝 语文考了85分,数学考了92分
- 🛒 买一支铅笔5元,买一个本子12元
- 🎮 游戏里你已经升到了15级
数字帮我们:
- 📊 统计和比较:谁考得好?谁长得高?
- 💰 计算和管理:买东西要付多少钱?零花钱够不够?
- 📐 测量和描述:距离、时间、重量、温度
- 🎯 解决问题:平均分是多少?还差多少分?
在这一章,我们将学习:
- 什么是整数和小数
- 如何用Python做数学运算
- 计算机是如何存储和计算数字的
- 用编程解决数学应用题
👨🏫 给家长的辅导建议:
- 这一章是数学和编程结合的重点章节
- 建议让孩子先回忆数学课学过的内容:整数、小数、四则运算
- 可以用生活中的场景引导:购物计算、时间计算、测量等
- 本章融入了计算机如何存储数字的知识,这是理解计算机工作原理的基础
- 如果孩子在某些数学概念上不太清楚,可以借此机会复习
数值的类型
在Python中,数字主要有两种类型:整数和小数。
1. 整数(int) - 完整的数字
整数就是没有小数部分的数字,可以是正数、负数或零。
# 正整数 - 计数、年龄、等级
age = 10 # 年龄
height_cm = 145 # 身高(厘米)
score = 95 # 分数
level = 8 # 游戏等级
# 负整数 - 欠款、温度零下、反向
temperature = -5 # 零下5度
balance = -100 # 欠款100元
elevator = -3 # 地下3层
# 零
zero = 0
💡 思考一下:
- 为什么年龄用整数?你会说“我10岁半“吗?
- 为什么温度可以是负数?温度计上负数在哪边?
👨🏫 给家长的知识补充:
int是 integer(整数)的缩写- 整数用于计数场景(人数、物品数)和离散数据(年龄、等级)
- 生活中大多数计数都是整数,你不能有“2.5个人“
🖥️ 计算机如何存储整数?
计算机用二进制(0和1)来存储数字。这里有一个简单的理解方式:
想象你有几个开关,每个开关只有“开“(1)和“关“(0)两种状态:
十进制 0 → 二进制 0000
十进制 1 → 二进制 0001
十进制 2 → 二进制 0010
十进制 3 → 二进制 0011
十进制 4 → 二进制 0100
十进制 5 → 二进制 0101
...
十进制 10 → 二进制 1010
👨🏫 给家长的讲解建议:
- 小学阶段不需要深入理解二进制转换
- 重点让孩子知道:计算机用0和1表示所有数字
- 可以用“手指计数“类比:我们用10个手指计数(十进制),计算机用“开关“计数(二进制)
- 4个开关可以表示0-15的数字(2⁴=16种可能)
- 这就是为什么计算机存储容量是2、4、8、16、32、64等数字
2. 小数(float) - 精确的数字
小数也叫“浮点数“(float),是带小数点的数字。
# 测量数据 - 身高、体重、温度
height = 1.45 # 身高1.45米
weight = 38.5 # 体重38.5公斤
temperature = 36.5 # 体温36.5度
# 价格 - 金钱计算
price = 9.99 # 价格9.99元
discount = 0.85 # 8.5折扣
# 数学常数
pi = 3.14159 # 圆周率
# 科学计数法(表示很大或很小的数)
big_number = 3.14e10 # 3.14 × 10¹⁰ (314亿)
small_number = 1.23e-5 # 1.23 × 10⁻⁵ (0.0000123)
💡 思考一下:
- 为什么身高用小数?(因为人在不断长高,可能是1.45米、1.46米…)
- 为什么价格用小数?(因为金额需要精确,9.99元不等于10元)
👨🏫 给家长的知识补充:
float是“浮点数“(floating point number)的缩写- “浮点“是因为小数点可以“浮动“到不同位置
- 小数用于测量场景和连续数据
- 重要:计算机中的小数可能有微小误差
这是因为计算机用二进制表示小数,有些十进制小数无法精确表示(类似1/3=0.333…) 暂时不需要深入理解原理,孩子只要知道“小数可能有微小误差“即可print(0.1 + 0.2) # 输出: 0.30000000000000004
🖥️ 小数在内存中的占用
- 整数(int):通常占用4字节或8字节,取决于数字大小
- 小数(float):通常占用8字节,可以表示很大范围的数字
可以简单理解为:
- 整数盒子比较固定,装整数刚刚好
- 小数盒子需要更复杂的结构,所以占用空间更大
判断数值类型
我们可以用 type() 函数查看一个变量的类型:
# 查看类型
i = 10
f = 3.14
print(type(i)) # 输出:<class 'int'>
print(type(f)) # 输出:<class 'float'>
# 判断类型
print(type(i) == int) # 输出:True
print(type(f) == float) # 输出:True
👨🏫 给家长的讲解建议:
type()函数可以帮助检查变量的类型- 如果孩子觉得
type(i) == int太复杂,可以暂时不学 - 重点让孩子知道:整数是
int,小数是float
数学练习:应用题入门
在深入学习运算之前,让我们先看看如何用编程解决数学应用题。
练习1:年龄问题
问题:小明今年10岁,爸爸今年38岁。5年后,爸爸比小明大多少岁?
思路:
- 5年后小明的年龄 = 10 + 5
- 5年后爸爸的年龄 = 38 + 5
- 年龄差 = 爸爸的年龄 - 小明的年龄
# 现在的年龄
xiaoming = 10
dad = 38
# 5年后的年龄
years = 5
xiaoming_future = xiaoming + years
dad_future = dad + years
# 计算年龄差
diff = dad_future - xiaoming_future
print(f"现在:小明{xiaoming}岁,爸爸{dad}岁")
print(f"5年后:小明{xiaoming_future}岁,爸爸{dad_future}岁")
print(f"年龄差:{diff}岁")
运行结果:
现在:小明10岁,爸爸38岁
5年后:小明15岁,爸爸43岁
年龄差:28岁
💡 思考一下:
- 为什么要先算各自的年龄,再算差值?
- 能不能直接用 38 - 10?为什么?
👨🏫 给家长的教学提示:
- 这是典型的“年龄问题“
- 关键点:年龄差永远不变
- 可以让孩子先口算,再用编程验证
- 扩展练习:两人年龄和是多少?多少年前爸爸年龄是小明的3倍?
练习2:价格问题
问题:一支铅笔5元,一个本子12元。买3支铅笔和2个本子,一共多少钱?
思路:
- 铅笔总价 = 单价 × 数量
- 本子总价 = 单价 × 数量
- 总金额 = 铅笔总价 + 本子总价
# 单价
pencil_price = 5
notebook_price = 12
# 数量
pencil_count = 3
notebook_count = 2
# 计算
pencil_total = pencil_price * pencil_count
notebook_total = notebook_price * notebook_count
total = pencil_total + notebook_total
print(f"铅笔:{pencil_price}元 × {pencil_count} = {pencil_total}元")
print(f"本子:{notebook_price}元 × {notebook_count} = {notebook_total}元")
print(f"合计:{total}元")
运行结果:
铅笔:5元 × 3 = 15元
本子:12元 × 2 = 24元
合计:39元
💡 思考一下:
- 如果有50元,够不够买?还剩多少?
- 如果所有商品打8折,要付多少钱?
👨🏫 给家长的教学提示:
- 这是“总价 = 单价 × 数量“的基础应用
- 可以扩展到购物场景:带100元买东西,够不够?
- 逐步引导孩子理解:先算各项,再求和
练习3:速度问题
问题:小明从家走到学校,距离是1200米,他每分钟走80米。需要多少分钟?
思路:
- 时间 = 距离 ÷ 速度
# 已知条件
distance = 1200 # 距离(米)
speed = 80 # 速度(米/分钟)
# 计算时间
time = distance / speed
print(f"距离:{distance}米")
print(f"速度:{speed}米/分钟")
print(f"需要时间:{time}分钟")
运行结果:
距离:1200米
速度:80米/分钟
需要时间:15.0分钟
💡 思考一下:
- 为什么结果是15.0而不是15?(因为我们用了
/除法) - 如果要15分钟,应该用什么运算?(用
//整除)
👨🏫 给家长的教学提示:
- 这是“路程、速度、时间“的三个基本关系:
- 路程 = 速度 × 时间
- 时间 = 路程 ÷ 速度
- 速度 = 路程 ÷ 时间
- 可以结合物理课或数学课的知识讲解
- 注意单位的统一(米、千米、分钟、小时)
数值的基本运算
Python支持所有的基本数学运算。
算术运算符
a = 10
b = 3
# 加法 +
print(a + b) # 输出:13
# 减法 -
print(a - b) # 输出:7
# 乘法 *
print(a * b) # 输出:30
# 除法 /(结果总是小数)
print(a / b) # 输出:3.3333333333333335
# 整除 //(只保留整数部分)
print(a // b) # 输出:3
# 求余数 %(模运算)
print(a % b) # 输出:1(因为 10 = 3×3 + 1)
# 幂运算 **(乘方)
print(a ** b) # 输出:1000(10的3次方)
💡 实物类比:
- 整除
//:你有10颗糖,平均分给3个人,每人得3颗(整除) - 求余
%:你有10颗糖,分给3个人,每人3颗,还剩1颗(余数) - 幂运算
**:正方形的面积是边长的平方(5² = 5 × 5 = 25)
👨🏫 给家长的教学建议:
/是普通除法,结果总是小数(float)//是整除,结果是整数(int),相当于数学中的“商“%是求余数,可以理解为“除不尽剩下的部分“**是幂运算,2 ** 3就是 2³ = 8- 重点:用分糖果、分蛋糕等实物类比,帮助孩子理解整除和余数
运算的优先级
和数学一样,Python的运算也有优先级:
# 先乘除,后加减
result = 2 + 3 * 4
print(result) # 输出:14(不是20)
# 使用括号改变优先级
result = (2 + 3) * 4
print(result) # 输出:20
# 幂运算优先级最高
result = 2 ** 3 * 4
print(result) # 输出:32(先算2³=8,再算8×4)
# 同级运算从左到右
result = 10 - 3 - 2
print(result) # 输出:5(先算10-3=7,再算7-2=5)
优先级顺序(从高到低):
- 括号
() - 幂运算
** - 乘除
*///% - 加减
+-
👨🏫 给家长的教学建议:
- 建议孩子多使用括号,即使不是必须的,也可以让代码更清晰
- 如果不确定优先级,就用括号明确表示
- 可以和数学课学的运算优先级对比,帮助理解
🖥️ 计算机的计算能力
你可能好奇,计算机计算有多快?让我们来测试一下!
测试1:计算速度对比
import time
# 测试1:简单的加法
start = time.time()
result = 0
for i in range(10000000): # 一千万次
result = result + 1
end = time.time()
print(f"计算机执行一千万次加法用时:{end - start:.4f}秒")
print(f"也就是每秒可以执行约:{10000000 / (end - start):.0f}次加法")
运行结果(根据计算机不同会有差异):
计算机执行一千万次加法用时:0.5123秒
也就是每秒可以执行约:19519837次加法
💡 也就是说:
- 普通计算机每秒可以执行几千万次简单运算
- 如果是人来做,每秒做1次加法,一千万次需要约4个月!
- 这就是为什么计算机擅长做重复性工作
测试2:大数计算
# 计算很大的数字
big_number = 12345678901234567890 ** 100
print(f"计算大数的100次方...")
print(f"结果有{len(str(big_number))}位数字!")
👨🏫 给家长的知识补充:
- CPU(中央处理器)是计算机的“大脑“,负责计算
- CPU的主频表示每秒可以执行的周期数
- 1 GHz = 每秒10亿次周期
- 3 GHz = 每秒30亿次周期
- 但不是说CPU每秒只能做30亿次运算
- 现代CPU有多个“核心“(像有多个大脑)
- 每个核心可以同时处理多个任务
- 所以实际运算能力远超主频数字
实践1:基础计算器
让我们用学到的知识做一个多功能计算器:
# 基础计算器
print("=" * 40)
print(" 🧮 小小计算器 🧮 ")
print("=" * 40)
print()
# 获取输入
num1 = input("请输入第一个数字:")
num2 = input("请输入第二个数字:")
# 转换成数值
num1 = float(num1)
num2 = float(num2)
# 计算
print()
print("📊 计算结果:")
print("-" * 35)
print(f"{num1} + {num2} = {num1 + num2}")
print(f"{num1} - {num2} = {num1 - num2}")
print(f"{num1} × {num2} = {num1 * num2}")
print(f"{num1} ÷ {num2} = {num1 / num2:.4f}")
print(f"{num1} 整除 {num2} = {num1 // num2}")
print(f"{num1} 余 {num2} = {num1 % num2}")
print(f"{num1} 的 {num2} 次方 = {num1 ** num2:.4f}")
print("-" * 35)
运行示例:
========================================
🧮 小小计算器 🧮
========================================
请输入第一个数字:10
请输入第二个数字:3
📊 计算结果:
-----------------------------------
10.0 + 3.0 = 13.0
10.0 - 3.0 = 7.0
10.0 × 3.0 = 30.0
10.0 ÷ 3.0 = 3.3333
10.0 整除 3.0 = 3.0
10.0 余 3.0 = 1.0
10.0 的 3.0 次方 = 1000.0
-----------------------------------
👨🏫 给家长的教学建议:
- 这里我们用
float()而不是int(),因为用户可能输入小数 - f-string 让输出格式更清晰
- 可以让孩子尝试输入不同的数字,观察结果
- 可以讨论:为什么除法结果有很多小数?(因为 10/3 = 3.333… 无限循环)
数学函数
Python内置了一些数学函数,可以帮我们完成复杂的计算。
1. 绝对值、最大值、最小值
# 绝对值 - 数轴上的距离
print(abs(-5)) # 输出:5
print(abs(3.14)) # 输出:3.14
print(abs(0)) # 输出:0
# 最大值
print(max(1, 5, 3)) # 输出:5
print(max(10, 20, 30)) # 输出:30
print(max(-5, -2, -10)) # 输出:-2
# 最小值
print(min(1, 5, 3)) # 输出:1
print(min(10, 20, 30)) # 输出:10
print(min(-5, -2, -10)) # 输出:-10
# 也可以用于列表(后面会学)
numbers = [3, 1, 4, 1, 5]
print(max(numbers)) # 输出:5
print(min(numbers)) # 输出:1
💡 实物类比:
- 绝对值:小明向东走了5米,小红向西走了5米,他们距离起点都是5米
- 最大值:考试成绩,最高分是多少?
- 最小值:气温记录,最低气温是多少?
👨🏫 给家长的教学建议:
abs是 absolute value(绝对值)的缩写- 绝对值可以用“距离原点的距离“来解释:-5 到 0 的距离是 5
max和min可以接受多个数字或一个列表- 可以结合实际场景:班级最高身高、最低气温、最高分等
2. 四舍五入
# 四舍五入
print(round(3.14)) # 输出:3(默认保留整数)
print(round(3.5)) # 输出:4(.5会进位)
print(round(3.14159, 2)) # 输出:3.14(保留2位小数)
print(round(3.14159, 3)) # 输出:3.142(保留3位小数)
print(round(3.14159, 4)) # 输出:3.1416(保留4位小数)
# 负数也可以
print(round(-3.5)) # 输出:-4
# 金钱计算常用
price = 9.99
quantity = 3
total = price * quantity
print(f"总价:{total}元") # 输出:总价:29.970000000000002元
print(f"总价:{round(total, 2)}元") # 输出:总价:29.97元
👨🏫 给家长的知识补充:
round()的第二个参数是保留的小数位数- “四舍五入“在Python中其实是“银行家舍入”(.5会舍入到最近的偶数)
- 例如:2.5 → 2,3.5 → 4(而不是2.5→3,3.5→4)
- 这个细节孩子不需要深究,知道是四舍五入即可
- 在金钱计算时,建议用
round(total, 2)保留两位小数
3. 幂运算
# 幂运算(也可以用 **)
print(pow(2, 3)) # 输出:8(2的3次方)
print(pow(5, 2)) # 输出:25(5的2次方)
print(pow(10, 6)) # 输出:1000000(10的6次方)
# 平方根
print(4 ** 0.5) # 输出:2.0(4的平方根)
print(9 ** 0.5) # 输出:3.0(9的平方根)
print(16 ** 0.5) # 输出:4.0(16的平方根)
💡 实际应用:
- 平方:正方形的面积 = 边长²
- 立方:正方体的体积 = 边长³
- 平方根:如果一个正方形面积是16,边长是多少?(√16 = 4)
实践2:成绩统计器
让我们用学到的函数做一个成绩统计器:
# 成绩统计器
print("=" * 40)
print(" 📊 成绩统计器 📊 ")
print("=" * 40)
print()
# 获取成绩
chinese = input("请输入语文成绩:")
math_score = input("请输入数学成绩:")
english = input("请输入英语成绩:")
science = input("请输入科学成绩:")
# 转换成数值
chinese = float(chinese)
math_score = float(math_score)
english = float(english)
science = float(science)
# 计算
total = chinese + math_score + english + science
average = total / 4
highest = max(chinese, math_score, english, science)
lowest = min(chinese, math_score, english, science)
# 输出
print()
print("📈 统计结果:")
print("-" * 35)
print(f"语文:{chinese:.1f}分")
print(f"数学:{math_score:.1f}分")
print(f"英语:{english:.1f}分")
print(f"科学:{science:.1f}分")
print("-" * 35)
print(f"总分:{total:.1f}分")
print(f"平均分:{average:.2f}分")
print(f"最高分:{highest:.1f}分")
print(f"最低分:{lowest:.1f}分")
print(f"总分差:{highest - lowest:.1f}分")
print("-" * 35)
运行示例:
========================================
📊 成绩统计器 📊
========================================
请输入语文成绩:85
请输入数学成绩:92
请输入英语成绩:88
请输入科学成绩:90
📈 统计结果:
-----------------------------------
语文:85.0分
数学:92.0分
英语:88.0分
科学:90.0分
-----------------------------------
总分:355.0分
平均分:88.75分
最高分:92.0分
最低分:85.0分
总分差:7.0分
-----------------------------------
👨🏫 给家长的教学建议:
- 这个练习综合运用了:输入输出、类型转换、四则运算、函数
- 可以讨论:如果平均分低于60分,应该提示警告?(为第7章条件语句做铺垫)
- 可以扩展:添加更多科目,计算排名等
练习1:温度转换器
任务:编写一个温度转换程序
- 询问用户摄氏温度
- 转换成华氏温度(公式:F = C × 1.8 + 32)
- 输出结果,保留一位小数
📝 点击查看提示
提示:
- 用
float()获取小数温度 - 使用公式计算
- 用 f-string 格式化输出,如
{fahrenheit:.1f}可以保留一位小数
📝 点击查看参考答案
# 温度转换器
print("=" * 40)
print(" 🌡️ 温度转换器 🌡️ ")
print("=" * 40)
print()
# 获取摄氏温度
celsius = input("请输入摄氏温度:")
celsius = float(celsius)
# 转换成华氏温度
fahrenheit = celsius * 1.8 + 32
# 输出结果
print()
print(f"📍 {celsius}°C = {fahrenheit:.1f}°F")
运行示例:
========================================
🌡️ 温度转换器 🌡️
========================================
请输入摄氏温度:25
📍 25.0°C = 77.0°F
👨🏫 给家长的教学建议:
.1f表示保留1位小数,.2f表示保留2位小数- 可以和孩子讨论:为什么用小数而不是整数?(因为温度可能是小数)
- 可以扩展:添加华氏转摄氏的功能(C = (F - 32) / 1.8)
- 这是“一次函数“的实际应用:y = ax + b
💡 数学知识:
- 摄氏温度(°C)和华氏温度(°F)的换算关系
- 这是一个线性关系,可以用一次函数表示
- 0°C = 32°F(水的冰点)
- 100°C = 212°F(水的沸点)
练习2:购物折扣计算器
任务:编写一个购物清单程序
- 询问3件商品的价格
- 计算总价
- 如果总价超过100元,打9折
- 输出原价、折扣、最终价格
📝 点击查看提示
提示:
- 用
float()获取价格 - 用
if语句判断是否打折(第7章会详细学) - 9折就是原价 × 0.9,或者减去10%
📝 点击查看参考答案
# 购物清单程序
print("=" * 40)
print(" 🛒 购物清单 🛒 ")
print("=" * 40)
print()
# 获取价格
price1 = input("请输入第1件商品价格:")
price2 = input("请输入第2件商品价格:")
price3 = input("请输入第3件商品价格:")
# 转换成数值
price1 = float(price1)
price2 = float(price2)
price3 = float(price3)
# 计算总价
total = price1 + price2 + price3
# 判断折扣
discount = 0
final_price = total
if total > 100:
discount = total * 0.1 # 9折就是减去10%
final_price = total - discount
print("🎉 恭喜!消费满100元,享受9折优惠!")
# 输出
print()
print("💰 账单:")
print("-" * 35)
print(f"商品1:¥{price1:.2f}")
print(f"商品2:¥{price2:.2f}")
print(f"商品3:¥{price3:.2f}")
print("-" * 35)
print(f"原价:¥{total:.2f}")
print(f"折扣:-¥{discount:.2f}")
print(f"最终:¥{final_price:.2f}")
print("-" * 35)
运行示例:
========================================
🛒 购物清单 🛒
========================================
请输入第1件商品价格:35
请输入第2件商品价格:45
请输入第3件商品价格:30
🎉 恭喜!消费满100元,享受9折优惠!
💰 账单:
-----------------------------------
商品1:¥35.00
商品2:¥45.00
商品3:¥30.00
-----------------------------------
原价:¥110.00
折扣:-¥11.00
最终:¥99.00
-----------------------------------
👨🏫 给家长的教学建议:
- 这个练习用到了条件语句(第7章内容)
- 如果孩子还没学,可以先简化:不打折,只计算总价
- 可以扩展:
- 添加更多商品
- 多级折扣(满100打9折,满200打8折)
- 会员折扣
- 这是“分段函数“的实际应用
💡 数学知识:
- 折扣计算:原价 × 折扣率 = 折后价
- 9折 = 90% = 0.9
- 折扣金额 = 原价 × (1 - 折扣率)
- 这是“百分比“的实际应用
数值的格式化输出
在输出数值时,我们可以控制它的显示格式。
1. 控制小数位数
pi = 3.1415926
# 保留2位小数
print(f"π ≈ {pi:.2f}") # 输出:π ≈ 3.14
# 保留4位小数
print(f"π ≈ {pi:.4f}") # 输出:π ≈ 3.1416
# 不保留小数
print(f"π ≈ {pi:.0f}") # 输出:π ≈ 3
# 自动保留(不指定)
print(f"π = {pi}") # 输出:π = 3.1415926
2. 对齐和宽度
number = 42
# 右对齐,宽度10
print(f"[{number:>10}]") # 输出:[ 42]
# 左对齐,宽度10
print(f"[{number:<10}]") # 输出:[42 ]
# 居中,宽度10
print(f"[{number:^10}]") # 输出:[ 42 ]
# 小数也可以对齐
pi = 3.14
print(f"[{pi:^10.2f}]") # 输出:[ 3.14 ]
3. 添加千位分隔符
big_number = 1234567890
# 添加千位分隔符
print(f"{big_number:,}") # 输出:1,234,567,890
# 小数也可以
price = 1234.56
print(f"¥{price:,.2f}") # 输出:¥1,234.56
# 人口统计
population = 1400000000
print(f"中国人口约:{population:,}人")
# 输出:中国人口约约:1,400,000,000人
👨🏫 给家长的知识补充:
- 格式化字符串的语法是
f"{变量:格式}" :.2f表示保留2位小数:>10表示右对齐,宽度10:,表示添加千位分隔符- 这些格式可以组合使用,如
:>10,.2f - 暂时不需要孩子记住所有格式,需要时再查阅
实践3:几何计算器
让我们做一个几何图形计算器,复习数学中的几何知识!
梯形计算器
问题:梯形的上底是5cm,下底是8cm,高是3cm,求面积和周长?
# 梯形计算器
print("=" * 45)
print(" 📐 梯形计算器 📐 ")
print("=" * 45)
print()
print("梯形有四条边:上底、下底、两条腰")
print()
# 获取输入
top = input("请输入上底的长度(cm):")
bottom = input("请输入下底的长度(cm):")
left = input("请输入左侧腰的长度(cm):")
right = input("请输入右侧腰的长度(cm):")
height = input("请输入梯形的高度(cm):")
# 转换成数值
top = float(top)
bottom = float(bottom)
left = float(left)
right = float(right)
height = float(height)
# 计算
# 梯形面积公式:面积 = (上底 + 下底) × 高 ÷ 2
area = (top + bottom) * height / 2
# 梯形周长公式:周长 = 上底 + 下底 + 左腰 + 右腰
perimeter = top + bottom + left + right
# 输出
print()
print("📊 计算结果:")
print("-" * 40)
print(f"上底:{top:.2f} cm")
print(f"下底:{bottom:.2f} cm")
print(f"左腰:{left:.2f} cm")
print(f"右腰:{right:.2f} cm")
print(f"高度:{height:.2f} cm")
print("-" * 40)
print(f"面积:{area:.2f} cm²")
print(f"周长:{perimeter:.2f} cm")
print("-" * 40)
运行示例:
=============================================
📐 梯形计算器 📐
=============================================
梯形有四条边:上底、下底、两条腰
请输入上底的长度(cm):5
请输入下底的长度(cm):8
请输入左侧腰的长度(cm):4
请输入右侧腰的长度(cm):4
请输入梯形的高度(cm):3
📊 计算结果:
----------------------------------------
上底:5.00 cm
下底:8.00 cm
左腰:4.00 cm
右腰:4.00 cm
高度:3.00 cm
----------------------------------------
面积:19.50 cm²
周长:21.00 cm
----------------------------------------
💡 数学知识:
- 梯形面积公式:S = (a + b) × h ÷ 2
- a = 上底,b = 下底,h = 高
- 梯形周长公式:C = a + b + c + d
- a = 上底,b = 下底,c = 左腰,d = 右腰
👨🏫 给家长的教学建议:
- 可以用梯形图片或实物帮助孩子理解
- 可以扩展:检查输入是否合理(如上底、下底、高度不能为负数)
- 可以讨论:如果两条腰相等,是什么梯形?(等腰梯形)
- 可以联系实际:梯形的河堤、梯形的田地等
圆形计算器
问题:一个圆的半径是5cm,求面积和周长?
# 圆形计算器
print("=" * 40)
print(" ⭕ 圆形计算器 ⭕ ")
print("=" * 40)
print()
# 获取半径
radius = input("请输入圆的半径(cm):")
radius = float(radius)
# 圆周率
pi = 3.141592653589793
# 计算
# 圆面积公式:面积 = π × 半径²
area = pi * radius ** 2
# 圆周长公式:周长 = 2 × π × 半径
circumference = 2 * pi * radius
# 输出
print()
print("📊 计算结果:")
print("-" * 35)
print(f"半径:{radius:.2f} cm")
print(f"圆周率π:{pi:.10f}")
print("-" * 35)
print(f"面积:{area:.2f} cm²")
print(f"周长:{circumference:.2f} cm")
print("-" * 35)
运行示例:
========================================
⭕ 圆形计算器 ⭕
========================================
请输入圆的半径(cm):5
📊 计算结果:
-----------------------------------
半径:5.00 cm
圆周率π:3.1415926536
-----------------------------------
面积:78.54 cm²
周长:31.42 cm
-----------------------------------
💡 数学知识:
- 圆面积公式:S = πr²
- π = 圆周率 ≈ 3.14
- r = 半径
- 圆周长公式:C = 2πr
- 或者 C = πd(d = 直径)
👨🏫 给家长的教学建议:
- π是一个无理数,无限不循环小数
- 实际计算中通常取 π ≈ 3.14 或 π ≈ 3.1416
- Python中的
math.pi提供了更精确的π值(第13章会学)
常见错误和调试
在编程中,错误是学习的好机会!让我们看看常见的错误。
错误1:忘记类型转换
# ❌ 错误示例
a = input("请输入第一个数字:")
b = input("请输入第二个数字:")
print(a + b) # 错误!这是字符串拼接,不是加法
# 如果输入10和3,会输出"103",而不是13
# ✅ 正确做法
a = input("请输入第一个数字:")
b = input("请输入第二个数字:")
a = float(a) # 转换成数值
b = float(b)
print(a + b) # 正确!这是数值加法
👨🏫 给家长的讲解建议:
- 这是最常见的错误!
input()总是返回字符串,即使输入的是数字- 必须用
int()或float()转换成数值才能计算 - 让孩子亲自运行错误代码,理解为什么出错
错误2:整数除法vs小数除法
# 问题:想要得到整数的商
a = 10
b = 3
# ❌ 用普通除法
print(a / b) # 输出:3.3333333333333335
# ✅ 用整除
print(a // b) # 输出:3
# ✅ 或者用int()转换
print(int(a / b)) # 输出:3
👨🏫 给家长的讲解建议:
/总是得到小数- 如果想要整数结果,用
//或int() - 根据实际需求选择合适的方法
错误3:小数精度问题
# 小数可能有微小误差
print(0.1 + 0.2)
# 输出:0.30000000000000004
# 而不是我们期待的0.3
# ✅ 解决方法1:四舍五入
result = 0.1 + 0.2
print(round(result, 2)) # 输出:0.3
# ✅ 解决方法2:用整数计算(分转元)
fen_1 = 10 # 0.1元 = 10分
fen_2 = 20 # 0.2元 = 20分
total_fen = fen_1 + fen_2
total_yuan = total_fen / 100
print(total_yuan) # 输出:0.3
👨🏫 给家长的讲解建议:
- 这是计算机表示小数的方式造成的
- 在金钱计算时,建议用“分“做单位,避免小数误差
- 或者用
round()四舍五入 - 如果孩子觉得困惑,可以说“计算机有时候会有一点小误差“
章节小结
恭喜你完成了这一章!让我们回顾一下学到的内容。
📚 核心概念
- 整数(int):没有小数部分的数字,用于计数
- 小数(float):带小数点的数字,用于测量
- 算术运算:加
+、减-、乘*、除/、整除//、求余%、幂** - 运算优先级:括号 > 幂运算 > 乘除 > 加减
🛠️ 常用函数
abs(x):绝对值max(a, b, c):最大值min(a, b, c):最小值round(x, n):四舍五入,保留n位小数pow(x, y):x的y次方
🖥️ 计算机知识
- 计算机用二进制(0和1)存储数字
- CPU是计算机的“大脑“,负责计算
- 现代CPU每秒可以执行数十亿次运算
- 整数和小数在计算机中的存储方式不同
💡 数学知识应用
- 年龄问题:年龄差永远不变
- 价格问题:总价 = 单价 × 数量
- 速度问题:时间 = 距离 ÷ 速度
- 几何公式:
- 梯形面积:S = (上底 + 下底) × 高 ÷ 2
- 圆面积:S = πr²
- 圆周长:C = 2πr
⚠️ 重要提示
/是普通除法,//是整除%是求余数input()得到的是字符串,需要转换成数值才能计算- 小数可能有微小精度误差,可以用
round()解决
🎯 挑战练习
选择1-2个你感兴趣的题目完成!
1. 复利计算器 💰
输入本金、年利率、年数,计算复利。
- 公式:最终金额 = 本金 × (1 + 利率)^年数
- 例如:1000元,年利率5%,存3年,最终是多少?
💡 提示
- 利率5%要写成0.05
- 用
**计算幂
📝 参考答案
# 复利计算器
print("=" * 40)
print(" 💰 复利计算器 💰 ")
print("=" * 40)
print()
# 获取输入
principal = input("请输入本金(元):")
rate = input("请输入年利率(如5%输入5):")
years = input("请输入存款年数:")
# 转换
principal = float(principal)
rate = float(rate) / 100 # 5% → 0.05
years = int(years)
# 计算复利
amount = principal * (1 + rate) ** years
interest = amount - principal
# 输出
print()
print("📊 计算结果:")
print("-" * 35)
print(f"本金:¥{principal:.2f}")
print(f"年利率:{rate*100:.1f}%")
print(f"存款年数:{years}年")
print("-" * 35)
print(f"利息:¥{interest:.2f}")
print(f"本息合计:¥{amount:.2f}")
print("-" * 35)
💡 数学知识:
- 复利公式:F = P(1 + r)^n
- F = 未来金额(Future Value)
- P = 本金(Principal)
- r = 利率(Rate)
- n = 期数(Number of periods)
- 复利是“利滚利“,利息也会产生利息
2. BMI计算器 ⚖️
输入身高和体重,计算BMI,并判断是否正常。
- 公式:BMI = 体重 ÷ 身高²
- 判断标准:
- BMI < 18.5:偏瘦
- 18.5 ≤ BMI < 24:正常
- BMI ≥ 24:偏胖
💡 提示
- 身高单位是米,不是厘米
- 用条件语句判断(第7章会详细学)
📝 参考答案
# BMI计算器
print("=" * 40)
print(" ⚖️ BMI计算器 ⚖️ ")
print("=" * 40)
print()
# 获取输入
height = input("请输入身高(米):")
weight = input("请输入体重(公斤):")
# 转换
height = float(height)
weight = float(weight)
# 计算BMI
bmi = weight / (height ** 2)
# 判断
if bmi < 18.5:
status = "偏瘦"
elif bmi < 24:
status = "正常"
else:
status = "偏胖"
# 输出
print()
print("📊 计算结果:")
print("-" * 35)
print(f"身高:{height:.2f} 米")
print(f"体重:{weight:.1f} 公斤")
print("-" * 35)
print(f"BMI指数:{bmi:.1f}")
print(f"健康状态:{status}")
print("-" * 35)
💡 数学知识:
- BMI = Body Mass Index(身体质量指数)
- 是衡量一个人胖瘦的标准
- 公式:BMI = 体重 ÷ 身高²
- 注意单位:体重用kg,身高用m
3. 找零计算器 💵
输入商品价格和支付金额,计算应该找多少零钱。
- 尽量用大面额纸币(100元、50元、20元、10元、5元、1元)
- 例如:商品123元,支付200元,找77元(50+20+5+1+1)
💡 提示
- 用整除和求余计算各种面额的数量
- 77 ÷ 50 = 1余27 → 1张50元
- 27 ÷ 20 = 1余7 → 1张20元
- …
📝 参考答案
# 找零计算器
print("=" * 40)
print(" 💵 找零计算器 💵 ")
print("=" * 40)
print()
# 获取输入
price = input("请输入商品价格(元):")
paid = input("请输入支付金额(元):")
# 转换
price = float(price)
paid = float(paid)
# 计算找零
change = paid - price
# 计算各种面额
change_100 = int(change // 100)
change = change % 100
change_50 = int(change // 50)
change = change % 50
change_20 = int(change // 20)
change = change % 20
change_10 = int(change // 10)
change = change % 10
change_5 = int(change // 5)
change = change % 5
change_1 = int(change // 1)
change = change % 1
# 输出
print()
print("📊 找零方案:")
print("-" * 35)
print(f"商品价格:¥{price:.2f}")
print(f"支付金额:¥{paid:.2f}")
print(f"找零总额:¥{paid - price:.2f}")
print("-" * 35)
if change_100 > 0:
print(f"100元纸币:{change_100}张")
if change_50 > 0:
print(f"50元纸币:{change_50}张")
if change_20 > 0:
print(f"20元纸币:{change_20}张")
if change_10 > 0:
print(f"10元纸币:{change_10}张")
if change_5 > 0:
print(f"5元纸币:{change_5}张")
if change_1 > 0:
print(f"1元硬币:{change_1}枚")
print("-" * 35)
💡 数学知识:
- 这是“贪心算法“的简单应用
- 每次尽量用最大面额
- 用整除得到数量,用求余得到剩余金额
🎉 给家长的教学建议
教学重点
- 整数和小数的区别:什么时候用整数,什么时候用小数
- 类型转换:这是最容易出错的地方,要强调
- 整除和求余:对孩子来说比较抽象,需要用实物类比
- 运算优先级:可以用数学课的知识对比
- 数学融入:通过编程复习数学知识,一举两得
常见问题及解答
Q1: 什么时候用整数,什么时候用小数?
- A: 计数、年龄、排名用整数;测量、价格、精确计算用小数。
Q2: 为什么 10 / 3 结果不是整数?
- A: 因为
/是普通除法,结果总是小数。如果想要整数,用//整除。
Q3: 求余数有什么用?
- A: 可以用来判断能不能整除、判断奇数偶数、分东西等。
Q4: 为什么小数计算会有误差?
- A: 这是计算机表示小数的方式造成的。如果需要精确计算,可以用
decimal模块(进阶内容)。
Q5: 如何判断孩子是否掌握了?
- A: 看孩子能否独立完成:
- 基础计算器
- 至少一个应用题练习
- 理解为什么要类型转换
练习建议
-
基础练习:让孩子用数值计算制作各种“计算器“
- 温度转换
- 货币兑换
- 成绩统计
-
生活应用:
- 购物:计算总价、折扣
- 烹饪:食谱换算(2人份→4人份)
- 运动:步数、距离、速度
-
数学复习:
- 用编程验证数学题的答案
- 把数学应用题写成程序
- 用程序生成数学练习题
下一步学习
完成这一章后,孩子应该:
- ✅ 理解整数和小数的区别
- ✅ 掌握基本的算术运算
- ✅ 能解决简单的数学应用题
- ✅ 了解计算机如何存储和计算数字
下一章,我们将学习布尔变量(Bool),这是编程中做判断的基础!
- 什么是“真“和“假“
- 如何比较大小
- 如何进行逻辑判断
- 为学习条件语句做准备
🔗 下一章:Bool变量与条件判断
在下一章中,我们将学习:
- 什么是布尔值(True和False)
- 比较运算符(>、<、==、!=)
- 逻辑运算符(与、或、非)
- 布尔值在判断中的应用
数值帮我们处理计算,布尔值帮我们做判断。两者结合起来,我们就可以编写更智能的程序了!
Bool变量与操作
引言
在前面的章节中,我们学习了两种数据类型:
- 字符串:处理文字信息
- 数值:处理数字和计算
今天我们要学习第三种重要的数据类型:布尔值(bool)。
布尔值就像是计算机的“答案“:要么是“对“(True),要么是“错“(False)。布尔值只有这两个值,用来表示“是“或“否“、“真“或“假”。
在生活中,布尔值无处不在:
- 今天下雨了吗?(是/否)
- 你的年龄超过10岁了吗?(是/否)
- 这个答案正确吗?(对/错)
- 游戏通关了吗?(成功/失败)
这一章,我们要深入了解:
- 什么是布尔值(True和False)
- 如何使用比较运算符得到布尔值
- 如何使用逻辑运算符组合布尔值
- 布尔值在实际编程中的应用
布尔值的基本概念
True 和 False
在Python中,布尔值只有两个:
- True:表示“真“、“对”、“是”
- False:表示“假“、“错”、“否”
# 直接使用布尔值
print(True) # 输出:True
print(False) # 输出:False
# 布尔变量
is_raining = True
is_sunny = False
print(is_raining) # 输出:True
print(is_sunny) # 输出:False
注意:
True和False的首字母必须大写!- 它们不是字符串,不需要引号
- 它们不是数字,不能用于计算
👨🏫 给家长的知识补充:
bool是“布尔值“(boolean)的缩写,来自数学家乔治·布尔的名字- 布尔值可以用“开关“来类比:要么开(True),要么关(False)
- 强调首字母大写:
True不是true,False不是false - 暂时不需要深入讲解布尔代数,孩子只要知道 True/False 即可
🖥️ 布尔值在计算机中的表示
在计算机内部,布尔值是用数字来表示的:
- True 通常表示为 1
- False 通常表示为 0
# 布尔值可以转换成数字
print(int(True)) # 输出:1
print(int(False)) # 输出:0
# 数字也可以转换成布尔值
print(bool(1)) # 输出:True
print(bool(0)) # 输出:False
💡 也就是说:
- 计算机本质上只认识 0 和 1
- 所有的“真“和“假“,在计算机里都是用 0 和 1 存储的
- 这就是为什么计算机用二进制(0和1)来工作
👨🏫 给家长的讲解建议:
- 小学阶段不需要深入理解二进制和布尔代数
- 重点让孩子知道:计算机用数字(0和1)来表示真假
- 可以用“电灯开关“类比:开(1/True),关(0/False)
- 这为后续理解计算机工作原理打下基础
布尔值的类型
# 查看布尔值的类型
print(type(True)) # 输出:<class 'bool'>
print(type(False)) # 输出:<class 'bool'>
# 判断是否为布尔类型
print(type(True) == bool) # 输出:True
print(type(1) == bool) # 输出:False
比较运算符
比较运算符用来比较两个值,结果是一个布尔值(True或False)。
1. 相等和不等
# 相等(==)
print(5 == 5) # 输出:True
print(5 == 3) # 输出:False
print("hello" == "hello") # 输出:True
print("Hello" == "hello") # 输出:False(大小写不同)
# 不等(!=)
print(5 != 3) # 输出:True
print(5 != 5) # 输出:False
print("cat" != "dog") # 输出:True
重要提示:= 是赋值,== 是比较!
# 错误示例
a = 5
if a = 5: # 错误!应该用 ==
print("yes")
# 正确示例
a = 5
if a == 5: # 正确
print("yes")
给家长的小贴士:
==是比较运算,问“相等吗?“!=是“不等于“,来自键盘上的!(有些键盘!和1在同一个键)- 这是初学者最容易犯的错误:用
=代替== - 可以用类比:
=是“把东西放进盒子“,==是“比较两个东西“
2. 大小比较
# 大于(>)
print(5 > 3) # 输出:True
print(5 > 10) # 输出:False
# 小于(<)
print(5 < 10) # 输出:True
print(5 < 3) # 输出:False
# 大于等于(>=)
print(5 >= 5) # 输出:True
print(5 >= 10) # 输出:False
# 小于等于(<=)
print(5 <= 5) # 输出:True
print(5 <= 3) # 输出:False
给家长的小贴士:
>=和<=的顺序不能反,不能写成=>或=<- 可以用数学课学的符号对比:≥ 和 ≤
- 强调:
>=是“大于或等于“,不是“大于然后等于“
3. 字符串比较
# 字符串按字母顺序比较
print("apple" < "banana") # 输出:True(a < b)
print("cat" > "dog") # 输出:False(c < d)
# 数字字符串也可以比较(按字典序)
print("10" < "2") # 输出:True('1' < '2')
print("9" > "10") # 输出:True('9' > '1')
# 如果要比数值大小,先转换
print(int("10") > int("2")) # 输出:True
给家长的小贴士:
- 字符串比较是按“字典序“(字母表顺序)
- 数字字符串比较可能不符合直觉(“10” < “2” 因为 ‘1’ < ‘2’)
- 这是个进阶话题,孩子暂时不理解也没关系
4. 比较运算符总结
| 运算符 | 名称 | 示例 | 结果 |
|---|---|---|---|
== | 等于 | 5 == 5 | True |
!= | 不等于 | 5 != 3 | True |
> | 大于 | 5 > 3 | True |
< | 小于 | 5 < 10 | True |
>= | 大于等于 | 5 >= 5 | True |
<= | 小于等于 | 5 <= 5 | True |
实践 1:数字比较器
让我们用比较运算符做一个数字比较器:
# 数字比较器
print("=" * 35)
print(" 数字比较器 ")
print("=" * 35)
print()
# 获取输入
num1 = input("请输入第一个数字:")
num2 = input("请输入第二个数字:")
# 转换成数值
num1 = float(num1)
num2 = float(num2)
# 比较并输出
print()
print("比较结果:")
print("-" * 30)
print(f"{num1} == {num2} : {num1 == num2}")
print(f"{num1} != {num2} : {num1 != num2}")
print(f"{num1} > {num2} : {num1 > num2}")
print(f"{num1} < {num2} : {num1 < num2}")
print(f"{num1} >= {num2} : {num1 >= num2}")
print(f"{num1} <= {num2} : {num1 <= num2}")
print("-" * 30)
运行示例:
===================================
数字比较器
===================================
请输入第一个数字:5
请输入第二个数字:3
比较结果:
------------------------------
5.0 == 3.0 : False
5.0 != 3.0 : True
5.0 > 3.0 : True
5.0 < 3.0 : False
5.0 >= 3.0 : True
5.0 <= 3.0 : False
------------------------------
练习 1:猜数字
编写一个程序:
- 设定一个秘密数字(如 7)
- 询问用户猜的数字
- 告诉用户猜对了还是猜错了
📝 点击查看参考答案
# 猜数字游戏
secret_number = 7
print("猜数字游戏")
print("=" * 25)
print()
# 获取猜测
guess = input("请猜一个数字(1-10):")
guess = int(guess)
# 比较
print()
if guess == secret_number:
print("🎉 恭喜你,猜对了!")
else:
print(f"❌ 猜错了,秘密数字是 {secret_number}")
运行示例:
猜数字游戏
=========================
请猜一个数字(1-10):5
❌ 猜错了,秘密数字是 7
给家长的小贴士:
- 这个练习用到了条件语句(第7章内容)
- 如果孩子还没学,可以简化:直接输出比较结果
- 可以扩展:给3次机会,提示“大了“或“小了“
逻辑运算符
逻辑运算符用来组合多个布尔值,得到一个新的布尔值。
1. 与运算(and)
and 运算:只有两个都为 True,结果才为 True。
# 两个都为 True
print(True and True) # 输出:True
# 只要有一个为 False
print(True and False) # 输出:False
print(False and True) # 输出:False
print(False and False) # 输出:False
# 实际例子
age = 12
has_ticket = True
can_enter = age >= 10 and has_ticket
print(can_enter) # 输出:True(年龄≥10且有票)
类比:and 就像“同时满足两个条件“:
- 你需要同时有门票且年龄≥10才能进入
- 你需要同时完成作业且打扫房间才能玩游戏
给家长的小贴士:
- 可以用“两个条件都要满足“来解释
- 举生活中的例子:既要完成作业,又要打扫房间,才能看电视
- 可以画“真值表“帮助孩子理解,但不要深究
2. 或运算(or)
or 运算:只要有一个为 True,结果就为 True。
# 只要有一个为 True
print(True or True) # 输出:True
print(True or False) # 输出:True
print(False or True) # 输出:True
# 两个都为 False
print(False or False) # 输出:False
# 实际例子
is_weekend = True
is_holiday = False
can_play = is_weekend or is_holiday
print(can_play) # 输出:True(周末或假期可以玩)
类比:or 就像“满足任意一个条件“:
- 周末或假期可以玩游戏
- 带雨伞或雨衣都可以
给家长的小贴士:
- 可以用“至少满足一个条件“来解释
- 举生活中的例子:带雨伞或雨衣都可以(有一个就行)
- 和
and对比:and是“都要“,or是“任一“
3. 非运算(not)
not 运算:把 True 变成 False,把 False 变成 True。
print(not True) # 输出:False
print(not False) # 输出:True
# 实际例子
is_raining = False
need_umbrella = not is_raining
print(need_umbrella) # 输出:True(不下雨需要带伞?逻辑需要调整)
# 更合理的例子
is_sunny = True
need_umbrella = not is_sunny
print(need_umbrella) # 输出:False(晴天不需要带伞)
给家长的小贴士:
not就是“取反“、“相反”- 可以用“不是“来解释
- 举生活中的例子:如果你不饿,就去学习
4. 逻辑运算符的优先级
逻辑运算符也有优先级:not > and > or
# not 优先级最高
print(not True and False) # 输出:False(先算 not True)
print(not (True and False)) # 输出:True(先算括号里的)
# and 比 or 优先级高
print(True or False and False) # 输出:True(先算 and)
# 使用括号明确优先级
print((True or False) and False) # 输出:False
给家长的小贴士:
- 建议孩子多使用括号,即使不是必须的
- 如果不确定优先级,就用括号明确表示
- 暂时不需要记忆优先级,多写代码自然就熟悉了
5. 逻辑运算符总结
| 运算符 | 名称 | 规则 | 示例 |
|---|---|---|---|
and | 与 | 两个都为 True | True and True = True |
or | 或 | 至少一个为 True | False or True = True |
not | 非 | 取反 | not True = False |
实践 2:登录检查器
让我们用逻辑运算符做一个登录检查器:
# 登录检查器
print("=" * 35)
print(" 登录检查器 ")
print("=" * 35)
print()
# 设定正确的用户名和密码
correct_username = "xiaoming"
correct_password = "123456"
# 获取输入
username = input("请输入用户名:")
password = input("请输入密码:")
# 检查
print()
username_correct = username == correct_username
password_correct = password == correct_password
can_login = username_correct and password_correct
# 输出
print("检查结果:")
print("-" * 30)
print(f"用户名正确:{username_correct}")
print(f"密码正确:{password_correct}")
print("-" * 30)
if can_login:
print("✅ 登录成功!")
else:
print("❌ 登录失败,请检查用户名或密码")
运行示例:
===================================
登录检查器
===================================
请输入用户名:xiaoming
请输入密码:123
检查结果:
------------------------------
用户名正确:True
密码正确:False
------------------------------
❌ 登录失败,请检查用户名或密码
给家长的小贴士:
- 这里用
and因为用户名和密码都要正确 - 可以和孩子讨论:如果用
or会怎样?(只要对一个就能登录,不安全) - 可以扩展:添加账号锁定功能(3次错误后锁定)
练习 2:折扣检查器
编写一个程序:
- 询问用户是否为会员(yes/no)
- 询问消费金额
- 判断是否享受折扣:
- 会员且消费超过100元,享受8折
- 非会员且消费超过200元,享受9折
📝 点击查看参考答案
# 折扣检查器
print("=" * 30)
print(" 折扣检查器 ")
print("=" * 30)
print()
# 获取输入
member = input("你是会员吗?(yes/no):")
amount = input("请输入消费金额:")
# 转换
amount = float(amount)
is_member = member == "yes" or member == "y" or member == "是"
# 判断折扣
discount = 0
has_discount = False
# 会员消费超过100元,8折
if is_member and amount > 100:
discount = 0.2
has_discount = True
reason = "会员且消费超过100元"
# 非会员消费超过200元,9折
elif not is_member and amount > 200:
discount = 0.1
has_discount = True
reason = "消费超过200元"
# 输出
print()
print(f"会员:{is_member}")
print(f"消费金额:¥{amount:.2f}")
print()
if has_discount:
final_price = amount * (1 - discount)
print(f"✅ 享受折扣:{reason}")
print(f"折扣:{discount * 10:.0f}折")
print(f"原价:¥{amount:.2f}")
print(f"最终:¥{final_price:.2f}")
else:
print("❌ 不享受折扣")
print(f"应付金额:¥{amount:.2f}")
运行示例:
==============================
折扣检查器
==============================
你是会员吗?(yes/no):yes
请输入消费金额:150
会员:True
消费金额:¥150.00
✅ 享受折扣:会员且消费超过100元
折扣:8折
原价:¥150.00
最终:¥120.00
给家长的小贴士:
- 这个练习综合运用了
and和not member == "yes" or member == "y" or member == "是"让用户可以输入多种形式- 可以和孩子讨论:为什么会员的要求更宽松?(鼓励成为会员)
布尔值的实际应用
1. 验证输入
# 验证年龄输入
age = input("请输入你的年龄:")
age = int(age)
is_valid = age >= 0 and age <= 120
if is_valid:
print(f"你的年龄是 {age} 岁")
else:
print("❌ 年龄不合法!")
2. 检查范围
# 检查温度是否舒适
temperature = 25
is_comfortable = temperature >= 18 and temperature <= 28
print(f"温度舒适:{is_comfortable}")
# 更简洁的写法(数学课学过的区间表示)
is_comfortable = 18 <= temperature <= 28
print(f"温度舒适:{is_comfortable}")
给家长的小贴士:
18 <= temperature <= 28是Python的特殊写法,数学上很直观- 其他编程语言可能需要写成
temperature >= 18 and temperature <= 28
3. 闰年判断
判断闰年的规则:
- 能被4整除,但不能被100整除;或者
- 能被400整除
# 闰年判断器
year = input("请输入年份:")
year = int(year)
# 闰年规则
is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
print()
print(f"{year}年是闰年吗?{is_leap}")
if is_leap:
print("这一年有366天(2月有29天)")
else:
print("这一年有365天(2月有28天)")
运行示例:
请输入年份:2024
2024年是闰年吗?True
这一年有366天(2月有29天)
给家长的小贴士:
- 闰年规则比较复杂,可以和孩子一起查资料
%是求余数,year % 4 == 0表示能被4整除- 这个练习综合运用了
and、or、not
布尔值和其他类型的转换
1. 其他类型转布尔值
在Python中,任何值都可以转换成布尔值:
- 大多数值都是 True
- 只有少数“空“值是 False
# 数值转布尔值
print(bool(1)) # 输出:True
print(bool(0)) # 输出:False
print(bool(-5)) # 输出:True
print(bool(3.14)) # 输出:True
# 字符串转布尔值
print(bool("hello")) # 输出:True
print(bool("")) # 输出:False(空字符串)
# None 转布尔值
print(bool(None)) # 输出:False
规则总结:
- False 值:
0,0.0,"",None - True 值:其他所有值
给家长的小贴士:
- 这是个进阶话题,孩子暂时不理解也没关系
- 可以简单记忆:有东西就是 True,没东西就是 False
- 暂时不需要深入,知道有这个转换即可
2. 布尔值转其他类型
# 布尔值转数值
print(int(True)) # 输出:1
print(int(False)) # 输出:0
print(float(True)) # 输出:1.0
print(float(False)) # 输出:0.0
# 布尔值转字符串
print(str(True)) # 输出:"True"
print(str(False)) # 输出:"False"
给家长的小贴士:
True相当于1,False相当于0- 这个特性可以用于计算,但初学者不建议这样做
- 例如:
True + True + False = 2(但不要这样写,太容易混淆)
常见错误和调试
错误 1:使用 = 而不是 ==
# 错误示例
age = 10
if age = 10: # 错误!应该用 ==
print("你是10岁")
# 正确做法
age = 10
if age == 10: # 正确
print("你是10岁")
错误 2:字符串大小写
# 错误示例
name = input("请输入你的名字:")
if name == "xiaoming": # 如果用户输入 "Xiaoming" 就会出错
print("欢迎小明")
# 正确做法
name = input("请输入你的名字:")
if name.lower() == "xiaoming": # 统一转成小写比较
print("欢迎小明")
错误 3:比较数字字符串
# 错误示例
age = input("请输入年龄:")
if age > 10: # 错误!这是字符串比较,不是数值比较
print("你超过10岁了")
# 正确做法
age = input("请输入年龄:")
age = int(age) # 先转换成数值
if age > 10:
print("你超过10岁了")
给家长的小贴士:
- 这些错误是初学者最容易犯的
- 建议让孩子亲自运行这些错误代码,观察错误信息
- Python的错误信息通常很清楚,学会看错误信息很重要
章节小结
恭喜你完成了这一章!让我们回顾一下学到的内容:
核心概念
- 布尔值(bool):只有两个值,True(真)和 False(假)
- 比较运算符:
==,!=,>,<,>=,<= - 逻辑运算符:
and(与),or(或),not(非)
重要规则
=是赋值,==是比较and:两个都为 True,结果才为 Trueor:只要有一个为 True,结果就为 Truenot:取反,True 变 False,False 变 True- 优先级:
not>and>or
实际应用
- 比较数字大小
- 验证输入是否合法
- 检查多个条件
- 闰年判断等复杂逻辑
给家长的小贴士:教学建议
教学重点
- True 和 False:理解布尔值只有两个值
- 比较运算符:特别是
=和==的区别 - 逻辑运算符:用生活中的例子类比
- 实际应用:让孩子看到布尔值的用途
常见问题及解答
-
问:为什么 True 的首字母要大写?
- 答:这是Python的规定。就像人名首字母要大写一样,True 和 False 是Python的“名字“,首字母必须大写。
-
问:
=和==有什么区别?- 答:
=是“赋值“,把东西放进盒子;==是“比较“,问两个东西相等吗?
- 答:
-
问:什么时候用
and,什么时候用or?- 答:需要“两个条件都满足“用
and,需要“至少满足一个“用or。
- 答:需要“两个条件都满足“用
-
问:
not是什么意思?- 答:
not就是“不是“、“相反”。not True就是“不是True“,也就是 False。
- 答:
练习建议
- 让孩子用布尔值判断各种条件:年龄、成绩、温度等
- 多用生活中的例子:登录验证、折扣检查、游戏规则
- 鼓励孩子设计自己的“规则“并用布尔值表达
挑战练习
-
石头剪刀布:编写程序,判断两个输入谁赢(需要考虑所有情况)
-
成绩等级:输入分数,判断等级(A: 90-100, B: 80-89, C: 70-79, D: 60-69, F: 0-59)
-
三角形判断:输入三条边的长度,判断能否组成三角形(任意两边之和大于第三边)
-
密码强度检查:检查密码是否满足:至少8个字符、包含大写字母、包含小写字母、包含数字
🔗 下一章:顺序语句
在下一章中,我们将学习:
- 什么是程序的三种基本结构
- 顺序执行的概念
- 如何让程序按顺序执行语句
- 使用 turtle 库绘制图形
布尔值帮我们做判断,顺序语句帮我们组织代码。两者结合起来,我们就可以编写更复杂的程序了!
顺序语句与第一个图形程序
引言
在前面的章节中,我们学习了变量、数据类型和基本的输入输出。现在,让我们开始学习程序的控制流程——也就是程序执行的顺序。
想象一下,你正在按照菜谱做一道菜:
- 先准备食材
- 然后切菜
- 接着炒菜
- 最后装盘
这些步骤必须按照顺序执行,不能跳过或颠倒。Python程序也是如此,代码默认从上到下、从左到右依次执行,这就是顺序语句。
你知道吗? 🤔 计算机的**CPU(中央处理器)**就是这样工作的!它会一条一条地读取指令,按照顺序执行。就像你按照菜谱做菜一样,CPU也是严格按照代码的顺序来工作的。
这一章,我们将:
- 理解程序的执行顺序
- 了解CPU是如何执行指令的
- 学习什么是“库“和“函数“
- 使用turtle库画出第一个图形
- 学习坐标系的概念
- 复习几何知识(正方形、长方形、三角形的性质)
- 用代码创作各种有趣的图形
什么是顺序语句
代码执行顺序
在Python中,代码默认按照从上到下的顺序执行,一行一行地运行。
# 示例:按顺序执行的代码
print("第一步:起床")
print("第二步:刷牙")
print("第三步:吃早餐")
print("第四步:上学")
输出结果:
第一步:起床
第二步:刷牙
第三步:吃早餐
第四步:上学
如果改变顺序,结果也会改变:
# 改变顺序
print("第四步:上学")
print("第一步:起床")
print("第三步:吃早餐")
print("第二步:刷牙")
输出结果:
第四步:上学
第一步:起床
第三步:吃早餐
第二步:刷牙
👨🏫 给家长的Tips
教学方法建议:
- 可以用生活中的例子帮助孩子理解顺序的概念,比如:
- 穿衣服的顺序(内裤→裤子→外套)
- 做作业的步骤(打开书包→拿出作业→开始写作业)
- 刷牙的步骤(挤牙膏→刷牙→漱口)
- 重要提示:强调计算机很“笨“,完全按照我们写的代码顺序执行,不会自动调整
- 可以让孩子想一些生活中的例子,来说明顺序的重要性
常见问题解答:
- 问:为什么不能让计算机自己判断顺序?
- 答:计算机没有“常识“,它只能严格按照我们写的代码执行。这就像一个只会按字面意思执行的机器人
为什么顺序很重要
顺序错误可能导致程序出错或结果不正确。让我们看一个例子:
# 正确的顺序:先赋值,再使用
age = 10
print(f"我的年龄是{age}岁")
# 错误的顺序:先使用,后赋值(会报错)
# print(f"我的身高是{height}厘米") # 变量还不存在
# height = 150
练习1:下面的代码输出什么?想一想为什么。
a = 5
b = 10
a = b
b = a
print(a, b)
👉 点击查看答案
答案:10 10
解释:
a = 5:a的值是5b = 10:b的值是10a = b:把b的值(10)赋给a,现在a是10b = a:把a的值(10)赋给b,b还是10- 最终输出
10 10
如果想交换两个变量的值,需要用第三个变量:
a = 5
b = 10
temp = a # 先保存a的值
a = b # 把b给a
b = temp # 把原来的a给b
print(a, b) # 输出:10 5
CPU是如何执行指令的 💡
你知道吗? 当你运行Python程序时,计算机的**CPU(中央处理器)**正在做以下工作:
- 取指令:CPU从内存中读取一行代码
- 译码:CPU理解这行代码要做什么
- 执行:CPU执行这行代码
- 重复:然后读取下一行代码,继续执行
这个过程就像你按菜谱做菜:
- 看菜谱上的一行指令(取指令)
- 理解这行指令的意思(译码)
- 按照指令去做(执行)
- 然后看下一行指令(重复)
比喻时间 🎯 想象CPU是一个非常勤奋的厨师:
- 代码就是菜谱
- CPU就是厨师
- 厨师严格按照菜谱的顺序,一行一行地做菜
- 如果菜谱写错了,厨师也会照做(因为厨师不会自己思考)
数学小知识 📐
- 如果一个CPU每秒能执行10亿次运算(1GHz)
- 执行100行简单的代码,只需要0.0000001秒!
- 这就是为什么计算机这么快的原因!
👨🏫 给家长的Tips
知识点补充(针对家长):
- CPU是计算机的“大脑“,负责执行所有的计算和控制
- CPU的主频(如2GHz、3GHz)表示每秒能执行多少个时钟周期
- 1GHz = 10亿次/秒,3GHz = 30亿次/秒
- 现代CPU非常复杂,但基本原理就是“取指-译码-执行“的循环
如何给孩子讲解:
- 不需要讲太多技术细节
- 重点让孩子理解:CPU是按顺序执行代码的
- 可以用“机器人厨师“的比喻来帮助理解
- 强调:代码的顺序非常重要,因为CPU完全按顺序执行
库和函数的概念
什么是库
Python非常强大,但有些功能不是Python自带的,需要我们额外引入。这些额外的功能集合叫做库(library)或模块(module)。
库就像是一个工具箱:
- Python自带了一些基本工具(比如print、input)
- 但如果我们需要特殊工具(比如画图、做数学运算),就需要引入专门的工具箱
什么是函数
函数(function)就像是一个“快捷指令“或“小机器“:
- 你给它一些材料(参数)
- 它内部进行处理
- 最后返回结果
比如,我们一直在用的print()和input()都是函数:
print("Hello"):给print函数一个字符串,它负责显示在屏幕上input("姓名:"):给input函数一个提示语,它负责接收用户输入
引入库的方法
使用import语句引入库:
# 引入整个库
import turtle
# 使用库中的函数:库名.函数名()
turtle.forward(100)
或者给库起个简短的名字:
# 引入库并给它起个简短的名字
import turtle as t
# 使用时更简短
t.forward(100)
认识Turtle库
什么是Turtle库
Turtle(海龟)是Python自带的一个画图库,特别适合初学者。它的原理很简单:
- 屏幕上有一只“小海龟“
- 我们可以用代码控制它移动、转向
- 小海龟爬过的轨迹会留下线条
这种方式画图非常直观,能帮助孩子们理解坐标系、角度等数学概念。
给家长的小贴士:
- Turtle库是1960年代为儿童学习编程设计的,历史悠久且效果很好
- 它能将抽象的编程概念可视化
- 建议家长和孩子一起运行代码,观察效果
安装Turtle库
Turtle库通常是Python自带的,不需要额外安装。但如果遇到问题,可以用以下方法安装:
# 在命令行中运行
pip install turtle
坐标系的概念
在使用Turtle画图前,我们需要了解坐标系:
y轴(向上为正)
↑
|
|
|
•------→ x轴(向右为正)
(0,0)
- 屏幕中心是原点 (0, 0)
- 向右是x轴正方向(正数)
- 向上是y轴正方向(正数)
- 向左是x轴负方向(负数)
- 向下是y轴负方向(负数)
Turtle的基本命令
让我们学习Turtle的基本命令:
1. 移动命令
import turtle
# 创建一只海龟
t = turtle.Turtle()
# 前进(画线)
t.forward(100) # 向前移动100像素
t.fd(100) # forward的简写
# 后退(画线)
t.backward(50) # 向后移动50像素
t.bk(50) # backward的简写
# 保持窗口打开
turtle.done()
效果:海龟向前画一条100像素的线,然后向后退50像素。
2. 转向命令
import turtle
t = turtle.Turtle()
# 左转
t.left(90) # 左转90度
t.lt(90) # left的简写
# 右转
t.right(90) # 右转90度
t.rt(90) # right的简写
turtle.done()
注意:
left(90)表示左转90度- 转向时海龟停留在原地,只是改变了朝向
- 转向后继续移动就会朝新的方向前进
给家长的小贴士:
- 可以用实物演示:让孩子站起来,模拟海龟的移动和转向
- 强调“转向“和“移动“是两个独立的动作
- 介绍角度概念:90度是直角,180度是掉头
3. 画笔控制
import turtle
t = turtle.Turtle()
# 抬起画笔(移动不留痕迹)
t.penup()
t.goto(50, 50) # 移动到(50, 50),不画线
# 放下画笔(移动会画线)
t.pendown()
t.goto(100, 100) # 移动到(100, 100),会画线
# 简写
t.up() # 抬笔
t.down() # 落笔
turtle.done()
4. 颜色和填充
import turtle
t = turtle.Turtle()
# 设置画笔颜色
t.pencolor("red") # 设置为红色
t.forward(100)
# 设置填充颜色
t.fillcolor("blue") # 填充色为蓝色
# 开始填充
t.begin_fill()
# 画一个正方形(用顺序语句,每条边都写出来)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 结束填充
t.end_fill()
turtle.done()
绘制基本图形
1. 画正方形 🟥
先复习数学知识! 📚
在数学课上,我们学过正方形的性质:
- ✅ 有4条边
- ✅ 每条边的长度都相等
- ✅ 有4个角,每个角都是直角(90度)
- ✅ 内角和 = 4 × 90° = 360度
现在让我们用代码画一个正方形:
import turtle
t = turtle.Turtle()
# 画正方形 - 第1条边
t.forward(100) # 边长100像素
t.left(90) # 左转90度
# 第2条边
t.forward(100)
t.left(90)
# 第3条边
t.forward(100)
t.left(90)
# 第4条边
t.forward(100)
t.left(90) # 画完后转回原方向
turtle.done()
效果:一个边长为100像素的正方形。
想一想 🤔
- 为什么要写4次
forward(100)?- 因为正方形有4条边
- 为什么要写4次
left(90)?- 因为每次要转90度(360° ÷ 4 = 90°)
数学小挑战 📐
- 如果边长改为200,代码怎么改?
- 把所有的
forward(100)改成forward(200)
- 把所有的
- 如果要画正六边形(6条边),每次转多少度?
- 360° ÷ 6 = 60度
👨🏫 给家长的Tips
教学方法建议:
- 先让孩子在纸上手算:画正方形需要写多少行代码?
- 4条边,每条边需要2行代码(forward + left)
- 所以需要 4 × 2 = 8行代码
- 引导孩子思考:
- “如果画正十边形,需要写多少行代码?” (10 × 2 = 20行)
- “如果画正一百边形,要写多少行代码?” (100 × 2 = 200行!)
- 告诉孩子:“这样重复写代码很麻烦,下一章我们会学习更简洁的方法!”
数学知识融入:
- 正方形的性质:4边相等,4角直角
- 多边形外角和公式:每次转向角度 = 360° ÷ 边数
- 这个公式适用于所有正多边形
2. 观察代码的重复规律
上面的代码重复了4次相同的操作(forward和left)。你可能会想:有没有更简单的方法呢?
答案是有的!在第8章《循环语句》中,我们将学习循环,可以让我们用更少的代码完成相同的任务。
👨🏫 给家长的Tips
这是一个很好的教学时机!
- 先让孩子用顺序语句完成图形绘制,理解每一步在做什么
- 引导孩子观察代码的重复规律
- 告诉孩子:“你看,这些代码重复了4次,很相似对吧?下一章我们要学一种更聪明的方法!”
- 这样在学循环时,孩子会有强烈的期待感,理解为什么要学循环
3. 画长方形 ▭
复习数学知识! 📚
在数学课上,我们学过长方形的性质:
- ✅ 有4条边
- ✅ 对边相等(上边=下边,左边=右边)
- ✅ 有4个角,每个角都是直角(90度)
- ✅ 内角和 = 360度
现在让我们用代码画一个长方形:
import turtle
t = turtle.Turtle()
# 设置长和宽
length = 150 # 长
width = 80 # 宽
# 画长方形 - 第1条边(长边)
t.forward(length) # 向前150像素
t.left(90) # 左转90度
# 第2条边(宽边)
t.forward(width) # 向前80像素
t.left(90) # 左转90度
# 第3条边(长边)
t.forward(length) # 向前150像素
t.left(90) # 左转90度
# 第4条边(宽边)
t.forward(width) # 向前80像素
t.left(90) # 左转90度
turtle.done()
效果:一个长150像素、宽80像素的长方形。
想一想 🤔
- 为什么长边和宽边的数值要交替出现?
- 因为长方形是对边相等!
- 如果要画正方形,应该怎么设置length和width?
- 把length和width设为相同的值!
数学小练习 📐
- 长方形的周长 = (长 + 宽) × 2
- 上面的长方形周长 = (150 + 80) × 2 = 460像素
- 你能算出如果length=200, width=50,周长是多少吗?
- (200 + 50) × 2 = 500像素
练习2:修改上面的代码,画一个长200、宽50的长方形。
👉 点击查看答案
import turtle
t = turtle.Turtle()
length = 200
width = 50
# 用顺序语句画出长方形(4条边)
t.forward(length)
t.left(90)
t.forward(width)
t.left(90)
t.forward(length)
t.left(90)
t.forward(width)
t.left(90)
turtle.done()
思考:上面的代码也重复了(forward, left, forward, left)两次。在学完循环后,你可以尝试用循环简化这段代码!
👨🏫 给家长的Tips
教学方法建议:
- 对比正方形和长方形的代码:
- 正方形:4次forward(100) - 数值相同
- 长方形:forward(150)和forward(80)交替出现 - 数值不同
- 引导孩子理解“对边相等“的概念
- 可以让孩子计算:
- 画长方形需要多少行代码?(8行)
- 如果画20个长方形,要写多少行代码?(20 × 8 = 160行!)
- 告诉孩子:“下一章学了循环,3行代码就能解决重复问题!”
4. 画三角形 △
复习数学知识! 📚
在数学课上,我们学过等边三角形(正三角形)的性质:
- ✅ 有3条边
- ✅ 每条边的长度都相等
- ✅ 有3个角,每个角都是60度
- ✅ 内角和 = 3 × 60° = 180度(所有三角形内角和都是180度!)
现在让我们用代码画一个等边三角形:
import turtle
t = turtle.Turtle()
# 等边三角形
side = 100 # 边长
# 第1条边
t.forward(side)
t.left(120) # 左转120度
# 第2条边
t.forward(side)
t.left(120)
# 第3条边
t.forward(side)
t.left(120)
turtle.done()
效果:一个边长为100像素的等边三角形。
重要问题 🤔
- 三角形的内角是60度,为什么代码里写的是
left(120)? - 答案:因为海龟转的是外角,不是内角!
- 外角 = 180° - 内角 = 180° - 60° = 120°
更简单的计算方法 📐
- 对于任意正n边形,每次转向角度 = 360° ÷ n
- 正三角形:360° ÷ 3 = 120°
- 正方形:360° ÷ 4 = 90°
- 正五边形:360° ÷ 5 = 72°
数学小挑战 📐
- 三角形的周长 = 100 × 3 = 300像素
- 三角形的内角和 = 60° + 60° + 60° = 180度
- 所有三角形的内角和都是180度,你记住了吗?
👨🏫 给家长的Tips
知识点补充(针对家长):
- 外角的概念:延长线与边的夹角
- 为什么要转外角:因为海龟是“转弯“,不是“掉头“
- 外角公式:360° ÷ 边数 (适用于所有正多边形)
如何给孩子讲解:
- 可以让孩子站起来,模拟海龟走路:
- 向前走100步
- 原地左转(不是掉头,是转弯)
- 想象你要“转弯多少度“才能走向下一个方向
- 也可以用“走路转弯“的生活例子来帮助理解
练习3:计算五边形每次应该转多少度?
👉 点击查看答案
答案:360 ÷ 5 = 72度
代码:
import turtle
t = turtle.Turtle()
side = 100
angle = 360 / 5 # 72度
# 用顺序语句画出五边形(5条边)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
turtle.done()
思考:五边形需要重复5次相同操作。想象一下,如果要画10边形或20边形,代码会变得很长。在学习循环后,你就可以用短短几行代码完成!
5. 画圆形
import turtle
t = turtle.Turtle()
# 方法1:使用circle命令
t.circle(50) # 画半径为50的圆
# 移动位置
t.penup()
t.goto(100, 0)
t.pendown()
# 方法2:通过画多边形近似圆
t.circle(80, steps=100) # 用100条线段近似圆
turtle.done()
实践项目:彩色多边形艺术
项目1:多彩正方形
让我们画一个填充颜色的正方形:
import turtle
t = turtle.Turtle()
# 设置画笔和填充颜色
t.pencolor("blue") # 边框蓝色
t.fillcolor("yellow") # 填充黄色
# 开始填充
t.begin_fill()
# 画正方形(用顺序语句)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 结束填充
t.end_fill()
# 写上文字
t.penup()
t.goto(0, -20)
t.write("正方形", align="center", font=("Arial", 16, "bold"))
turtle.done()
项目2:彩色圆圈
import turtle
t = turtle.Turtle()
# 画第1个圆(红色,半径20)
t.penup()
t.goto(0, 0)
t.pendown()
t.pencolor("red")
t.circle(20)
# 画第2个圆(橙色,半径40)
t.penup()
t.goto(0, -20)
t.pendown()
t.pencolor("orange")
t.circle(40)
# 画第3个圆(黄色,半径60)
t.penup()
t.goto(0, -40)
t.pendown()
t.pencolor("yellow")
t.circle(60)
turtle.done()
给家长的Tips:
- 这个项目画了3个圆圈,每个圆圈的位置和大小都不同
- 引导孩子观察:每个圆圈的代码都很相似,只是颜色和数字不同
- 告诉孩子:“如果我们想画10个圆圈,就要写30行类似的代码。学完循环后,3行代码就能搞定!”
- 这为学习循环埋下伏笔
练习:尝试在上面的代码基础上,继续添加第4个、第5个圆圈,让它们越来越大!
项目3:星星(挑战题)
五角星的每个角是36度,我们来画一个五角星:
import turtle
t = turtle.Turtle()
# 设置画笔颜色
t.pencolor("gold")
t.fillcolor("orange")
# 移动到合适的位置
t.penup()
t.goto(0, 100)
t.pendown()
# 开始填充
t.begin_fill()
# 画五角星(用顺序语句,5条边)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
# 结束填充
t.end_fill()
turtle.done()
给家长的小贴士:
- 五角星有5个角,每个角36度
- 每次转向的是外角:180 - 36 = 144度
- 可以让孩子先在纸上画五角星,数数每次转多少度
Turtle常用函数速查表
给孩子打印一张函数表,方便他们查找使用:
移动命令
| 函数 | 简写 | 说明 |
|---|---|---|
forward(距离) | fd(距离) | 向前移动指定距离 |
backward(距离) | bk(距离) | back(距离) |
goto(x, y) | 移动到指定坐标 | |
setx(x) | 设置x坐标 | |
sety(y) | 设置y坐标 |
转向命令
| 函数 | 简写 | 说明 |
|---|---|---|
left(角度) | lt(角度) | 左转指定角度 |
right(角度) | rt(角度) | 右转指定角度 |
setheading(角度) | seth(角度) | 设置朝向(0=东,90=北,180=西,270=南) |
画笔控制
| 函数 | 简写 | 说明 |
|---|---|---|
penup() | up() | pu() |
pendown() | down() | pd() |
pensize(宽度) | width(宽度) | 设置画笔粗细 |
pencolor(颜色) | 设置画笔颜色 | |
fillcolor(颜色) | 设置填充颜色 | |
begin_fill() | 开始填充 | |
end_fill() | 结束填充 |
其他命令
| 函数 | 说明 |
|---|---|
circle(半径) | 画圆 |
dot(大小) | 画点 |
write(文字) | 写文字 |
clear() | 清除画布 |
reset() | 重置画布和海龟 |
hideturtle() | 隐藏海龟 |
showturtle() | 显示海龟 |
speed(速度) | 设置速度(1-10,0最快) |
综合练习
练习1:画房子
用Turtle画一个简单的房子:
import turtle
t = turtle.Turtle()
t.speed(5) # 设置速度
# 房子主体(正方形)
t.fillcolor("yellow")
t.begin_fill()
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.end_fill()
# 房顶(三角形)
t.penup()
t.goto(0, 100)
t.pendown()
t.fillcolor("red")
t.begin_fill()
t.forward(100)
t.left(120)
t.forward(100)
t.left(120)
t.forward(100)
t.left(120)
t.end_fill()
# 门(长方形)
t.penup()
t.goto(30, -50)
t.pendown()
t.fillcolor("brown")
t.begin_fill()
t.forward(40)
t.left(90)
t.forward(60)
t.left(90)
t.forward(40)
t.left(90)
t.forward(60)
t.left(90)
t.end_fill()
turtle.done()
练习2:画花朵
这个练习使用循环来画多个花瓣。由于我们还没学循环,这个练习我们先跳过,等学完第8章循环语句后,再回来完成它!
作为替代,你可以尝试:
- 画一个简单的花朵(用多个圆形组成)
- 画一棵树(用长方形做树干,三角形或圆形做树冠)
- 或者发挥创意,画你自己想画的任何东西!
👨🏫 给家长的Tips
这个画花朵的练习需要使用循环来重复画花瓣。可以:
- 告诉孩子:“这个练习需要重复画6次花瓣,每次都要写很多相似的代码,有点复杂”
- “我们先学习更简单的图形,等学完循环后,再用短短几行代码完成这个美丽的花朵!”
- 保持孩子的学习兴趣和期待感
练习3:创意绘画
让孩子自由发挥,创作自己的作品!
提示:
- 可以画动物、植物、建筑等
- 尝试使用不同的颜色和形状
- 组合多个图形形成复杂图案
调试技巧
常见问题
-
窗口一闪而过
# 在程序最后加上 turtle.done() -
画图速度太慢
t = turtle.Turtle() t.speed(0) # 0是最快速度,10是快,1是慢 -
找不到海龟
t.showturtle() # 显示海龟 -
颜色不生效
# 确保颜色名称正确(英文) t.pencolor("red") # 正确 # t.pencolor("红色") # 错误
给家长的小贴士:
- 教孩子学会看错误信息
- 使用
t.speed()设置速度,方便观察画图过程- 使用
t.clear()清除画布重新开始- 鼓励孩子多尝试,不怕出错
章节小结
我们学到了什么
- 顺序语句:代码从上到下依次执行
- CPU执行原理 💡:
- CPU按照“取指-译码-执行“的循环工作
- 代码的顺序非常重要,因为CPU完全按顺序执行
- 现代CPU每秒可以执行几十亿次运算!
- 库的概念:Python的扩展功能集合
- 函数的概念:完成特定功能的代码块
- import语句:如何引入库
- 坐标系:二维平面的定位方法
- Turtle库:用代码画图
- 移动命令:forward, backward, goto
- 转向命令:left, right
- 画笔控制:penup, pendown, color
- 基本图形:正方形、长方形、三角形、圆形
- 数学知识 📐:
- 正方形:4边相等,4角直角,内角和360°
- 长方形:对边相等,4角直角,内角和360°
- 等边三角形:3边相等,3角60°,内角和180°
- 正多边形外角公式:每次转向角度 = 360° ÷ 边数
重要概念回顾
- 执行顺序:代码按从上到下的顺序执行
- 函数调用:
库名.函数名(参数) - 坐标系:中心是(0,0),向右x正,向上y正
- 角度:360度是一圈,90度是直角
- CPU工作原理:取指→译码→执行→重复
给家长的总结 📋
本章核心知识点:
- ✅ 顺序执行的概念(程序控制的基础)
- ✅ 计算机硬件基础(CPU的工作原理)
- ✅ 几何知识融入(正方形、长方形、三角形的性质)
- ✅ Turtle库的基本使用
- ✅ 坐标系和角度的概念
教学检查点:
- 孩子能理解为什么代码的顺序很重要?
- 孩子能复述CPU是如何执行代码的吗?
- 孩子能独立用代码画出正方形、长方形、三角形吗?
- 孩子能计算正n边形每次应该转多少度吗?
- 孩子对学习循环有期待感吗?(知道顺序语句的局限性)
常见问题与解答:
- 问:为什么一定要学顺序语句?直接学循环不行吗? 答:顺序执行是编程的基础,必须先理解“一步一步执行“,才能理解“重复执行“。这是从具体到抽象的认知过程。
- 问:孩子觉得写重复代码很无聊怎么办? 答:这正是我们想要的效果!让孩子感受到重复代码的麻烦,学循环时才会有强烈的需求感和学习动力。
- 问:CPU的内容会不会太深奥? 答:我们只需要让孩子理解“按顺序执行“的概念即可,不需要深入技术细节。用“厨师按菜谱做菜“的比喻就足够了。
下一步
在下一章(第7章),我们将学习条件语句(if语句),让程序能够根据不同情况做出不同的决定。结合Turtle库,我们就能画出更加智能和有趣的图形!
再下一章(第8章),我们将学习循环语句,到时候你就可以用短短几行代码画出正方形、长方形、三角形和多边形了!是不是很期待?😊
挑战练习
-
必做:
- 画一个边长为80的正方形,填充绿色
- 画一个长150、宽100的长方形,填充蓝色
- 画一个六边形(💡提示:每次转多少度?)
-
选做:
- 画出你的名字首字母
- 画一个笑脸(圆形脸+眼睛+嘴巴)
- 画一个彩虹(7个半圆)
-
挑战 🌟:
- 画出自己设计的房子(至少有主体、门窗、屋顶)
- 创作一个抽象艺术画(使用不同颜色和形状)
- 数学挑战:计算一下,画一个正100边形需要写多少行代码?如果用循环,可以节省多少行?(答案:100边形需要200行代码,用循环只需要5行!)
加油!你已经能用代码画出美丽的图形了!🎨🐢
预告 📢 下一章学完条件语句,后面我们还要学循环语句。到时候,你就可以用短短几行代码完成:
# 用循环画正方形(第8章会学)
for i in range(4):
t.forward(100)
t.left(90)
是不是很简洁?让我们一起期待吧!
条件语句
引言
在前面的章节中,我们学习了顺序语句——程序按从上到下的顺序执行。但现实生活中,很多决定需要根据条件来做不同的选择。
想象一下:
- 如果下雨,就带伞;如果不下雨,就不带伞
- 如果温度高于30度,就开空调;否则就开窗
- 如果作业写完了,就可以玩游戏;否则就继续写作业
这些都需要判断一个条件,然后根据判断结果做不同的事情。在Python中,我们用条件语句来实现这种功能。
你知道吗? 🤔 在上一章,我们学习了CPU如何按顺序执行代码。但CPU不仅能按顺序执行,还能做逻辑判断!
- CPU可以比较两个数字的大小
- CPU可以判断一个条件是True还是False
- 根据判断结果,CPU可以决定执行哪一段代码
这就是条件语句的硬件基础!
这一章,我们将学习:
- 什么是条件语句
- if语句的基本用法
- if-else语句(两种选择)
- if-elif-else语句(多种选择)
- 嵌套if语句(条件中的条件)
- 复习数学比较大小的知识
- 用条件语句解决数学应用题
回顾:布尔值和比较运算
在第5章,我们学习了布尔值(True和False)和比较运算符。它们是条件语句的基础。
数学小知识 📐 在数学课上,我们学过比较两个数的大小:
- 大于:a > b (a比b大)
- 小于:a < b (a比b小)
- 等于:a = b (a和b相等)
- 大于等于:a ≥ b (a大于或等于b)
- 小于等于:a ≤ b (a小于或等于b)
Python中的比较运算符和数学中的符号很像,只是写法稍有不同!
比较运算符
让我们快速回顾一下:
# 等于 (数学中是 =,Python中是 ==)
print(5 == 5) # True
print(5 == 3) # False
# 不等于 (数学中是 ≠)
print(5 != 3) # True
print(5 != 5) # False
# 大于 (和数学一样)
print(10 > 5) # True
print(5 > 10) # False
# 小于 (和数学一样)
print(3 < 7) # True
print(7 < 3) # False
# 大于等于 (数学中是 ≥)
print(8 >= 8) # True
print(8 >= 5) # True
# 小于等于 (数学中是 ≤)
print(6 <= 10) # True
print(6 <= 6) # True
数学练习 📝 用Python比较以下数字的大小:
- 100 和 200 (答案: 100 < 200,所以100 < 200是True)
- 3.14 和 3.14159 (答案: 3.14 < 3.14159)
- -5 和 -10 (答案: -5 > -10,负数绝对值越大,数值越小)
注意 ⚠️
- 在数学中,我们用“=“表示相等
- 在Python中,“=“是赋值(把值给变量),”==“才是比较(判断是否相等)
- 这个区别非常重要!
布尔运算符
我们也学过如何组合多个条件:
# and(两个条件都满足)
age = 15
print(age >= 10 and age <= 18) # True(10到18岁之间)
# or(至少一个条件满足)
day = "周六"
print(day == "周六" or day == "周日") # True(是周末)
# not(取反)
is_raining = False
print(not is_raining) # True(不下雨)
数学中的“且“和“或“ 📐 在数学中,我们学过:
- 且(∧): 两个条件都满足 (对应Python的
and) - 或(∨): 至少一个条件满足 (对应Python的
or) - 非(¬): 取反 (对应Python的
not)
数学练习 📝
-
如果x > 5且x < 10,Python应该写成?
x > 5 and x < 10 -
如果x ≤ 0或x ≥ 100,Python应该写成?
x <= 0 or x >= 100
👨🏫 给家长的Tips
教学方法建议:
- 确保孩子理解比较运算符和布尔值
- 可以用生活中的例子练习:判断年龄、分数、温度等
- 重点强调:“==“是等于(比较),”=“是赋值(赋值)
- 可以在纸上画数轴,帮助孩子理解大于、小于的概念
知识点补充(针对家长):
- CPU有专门的比较指令(如CMP指令),用于比较两个数的大小
- CPU有逻辑运算指令(如AND、OR、NOT),用于组合条件
- 这些指令的结果都是布尔值(True/False),在CPU中用1和0表示
- 条件判断的底层原理:CPU根据比较结果(0或1)决定是否“跳转“到其他代码执行
如何给孩子讲解:
- 不需要深入CPU指令集的细节
- 重点让孩子理解:CPU可以比较数字,并根据结果做决定
- 可以用“如果温度>30度,就开空调“的例子来类比CPU的逻辑判断
if语句:最简单的条件判断
if语句的基本语法
if 条件:
# 条件为True时执行的代码
代码块
语法要点:
if后面跟着一个条件(布尔表达式)- 条件后面必须有冒号
:(英文冒号) - 要执行的代码必须缩进(通常用4个空格或1个Tab)
- 只有条件为True时,代码块才会执行
示例1:分数奖励
假设小明的Python成绩大于98分,就能获得一个霸王龙玩具:
# 设置分数
score = 99
# 判断分数是否大于98
if score > 98:
print("恭喜你!")
print("你获得了一个霸王龙玩具!")
print("程序结束")
输出结果:
恭喜你!
你获得了一个霸王龙玩具!
程序结束
如果分数不满足条件:
# 设置分数
score = 95
# 判断分数是否大于98
if score > 98:
print("恭喜你!")
print("你获得了一个霸王龙玩具!")
print("程序结束")
输出结果:
程序结束
可以看到,当条件不满足时,if语句内的代码不会执行,程序直接跳过。
示例2:判断奇数
# 输入一个数字
num = int(input("请输入一个整数:"))
# 判断是否为奇数(除以2余1)
if num % 2 == 1:
print(f"{num}是奇数")
print("判断结束")
给家长的小贴士:
- 解释什么是“奇数“:不能被2整除的数(除以2余1)
- 解释
%运算符:求余数- 让孩子尝试输入不同的数字,观察结果
练习1
题目:小明考试如果及格(分数≥60),爸爸奖励他一辆汽车(输出“gift: car“),如果不及格则没有奖励(输出“gift: none“)。
👉 点击查看答案
# 输入分数
score = int(input("请输入小明的考试分数:"))
# 判断是否及格
if score >= 60:
print("gift: car")
else:
print("gift: none")
注意:这个练习需要用到if-else语句,下面马上就会学到!
if-else语句:两种选择
当我们需要在两种情况中做选择时,使用if-else语句。
if-else的基本语法
if 条件:
# 条件为True时执行
代码块1
else:
# 条件为False时执行
代码块2
示例:
- 如果小明Python考试成绩大于98分,老师就奖励他一个小汽车
- 否则老师就罚他抄代码100遍
# 输入分数
score = int(input("请输入小明的Python成绩:"))
# 判断分数
if score > 98:
print("🎉 恭喜你!奖励一个小汽车!")
else:
print("😢 很遗憾,请抄代码100遍")
print("判断结束")
运行示例1(分数大于98):
请输入小明的Python成绩:100
🎉 恭喜你!奖励一个小汽车!
判断结束
运行示例2(分数不大于98):
请输入小明的Python成绩:95
😢 很遗憾,请抄代码100遍
判断结束
示例:用户登录验证
设定一个用户名和密码,用户输入用户名和密码都正确,打印“welcome“,否则输出“error“。
# 设定正确的用户名和密码
correct_username = "admin"
correct_password = "123456"
# 用户输入
username = input("请输入用户名:")
password = input("请输入密码:")
# 判断用户名和密码是否都正确
if username == correct_username and password == correct_password:
print("welcome")
else:
print("error")
给家长的小贴士:
- 解释为什么用
and而不是or(两个条件都要满足)- 可以让孩子故意输入错误的用户名或密码,测试程序
- 强调安全:实际程序中密码不会明文存储
示例:判断奇数和偶数
# 输入一个数字
num = int(input("请输入一个整数:"))
# 判断奇偶
if num % 2 == 0:
print(f"{num}是偶数")
else:
print(f"{num}是奇数")
练习2
题目:一张桌子5岁的男孩能推动,7岁以上的女孩能推动。根据输入的性别和年龄,判断是否能推动。
👉 点击查看答案
# 输入性别和年龄
gender = input("请输入性别(男/女):")
age = int(input("请输入年龄:"))
# 判断是否能推动(男孩且5岁,或女孩且大于7岁)
if (gender == "男" and age == 5) or (gender == "女" and age > 7):
print("能推动桌子")
else:
print("不能推动桌子")
另一种写法(嵌套if):
gender = input("请输入性别(男/女):")
age = int(input("请输入年龄:"))
if gender == "男":
if age == 5:
print("能推动桌子")
else:
print("不能推动桌子")
else: # 性别是"女"
if age > 7:
print("能推动桌子")
else:
print("不能推动桌子")
if-elif-else语句:多种选择
当需要在三种或更多情况中做选择时,我们使用if-elif-else语句。
if-elif-else的基本语法
if 条件1:
# 条件1为True时执行
代码块1
elif 条件2:
# 条件2为True时执行
代码块2
elif 条件3:
# 条件3为True时执行
代码块3
...
else:
# 所有条件都不满足时执行
代码块n
语法要点:
elif是else if的缩写- 可以有多个
elif else是可选的- 程序会从上到下检查条件,一旦某个条件满足,就执行对应的代码块,然后跳出整个if语句
示例1:成绩分级
从键盘输入小明的Python期末成绩:
- 当成绩为100分时,奖励一张出游机票
- 当成绩为[80-99]时,奖励一个iPhone
- 当成绩为[60-79]时,奖励一本参考书
- 其他时(低于60),什么奖励也没有
# 输入分数
score = int(input("请输入Python期末成绩:"))
# 判断分数等级
if score == 100:
print("🎉 完美!奖励一张出游机票!")
elif score >= 80: # 80-99分
print("👏 很棒!奖励一个iPhone!")
elif score >= 60: # 60-79分
print("👍 及格了!奖励一本参考书!")
else: # 低于60分
print("😢 继续努力,没有奖励...")
print("判断结束")
运行示例1(100分):
请输入Python期末成绩:100
🎉 完美!奖励一张出游机票!
判断结束
运行示例2(85分):
请输入Python期末成绩:85
👏 很棒!奖励一个iPhone!
判断结束
运行示例3(65分):
请输入Python期末成绩:65
👍 及格了!奖励一本参考书!
判断结束
运行示例4(50分):
请输入Python期末成绩:50
😢 继续努力,没有奖励...
判断结束
👨🏫 给家长的Tips
教学方法建议:
- 解释为什么
score >= 80不需要写成score >= 80 and score < 100- 因为如果score是100,第一个条件就满足了,不会继续检查
- 这种写法叫“短路“逻辑,效率更高
- 可以在纸上画数轴,标出不同分数段的位置
数学知识融入:分段函数 📐
在数学中,我们学过分段函数,就是一个函数在不同区间有不同的表达式。
例如,快递费的计算:
- 重量 ≤ 1kg:5元
- 1kg < 重量 ≤ 3kg:10元
- 重量 > 3kg:15元
这就是一个分段函数!用if-elif-else可以轻松实现!
数学练习:快递费计算 📝
# 输入快递重量(kg) weight = float(input("请输入快递重量(kg): ")) # 根据重量计算费用(分段函数) if weight <= 1: fee = 5 elif weight <= 3: # 注意:1 < weight ≤ 3 fee = 10 else: # weight > 3 fee = 15 print(f"快递费用为: {fee}元")数学小挑战 🌟
出租车计费也是分段函数:
- 3公里以内:起步价10元
- 3-10公里:每公里2元
- 10公里以上:每公里3元
你能写出计算出租车费用的代码吗?
👉 点击查看答案
# 输入里程数(km) distance = float(input("请输入里程数(km): ")) # 根据里程计算费用 if distance <= 3: fare = 10 elif distance <= 10: # 3 < distance ≤ 10 fare = 10 + (distance - 3) * 2 else: # distance > 10 fare = 10 + (10 - 3) * 2 + (distance - 10) * 3 print(f"出租车费用为: {fare}元")
数学应用题练习 📝
题目1:年龄分类 写一个程序,根据年龄输出人生阶段:
- 0-6岁:婴幼儿
- 7-12岁:小学生
- 13-15岁:初中生
- 16-18岁:高中生
- 19-22岁:大学生
- 23-60岁:成年人
- 60岁以上:老年人
👉 点击查看答案
# 输入年龄
age = int(input("请输入年龄: "))
# 判断人生阶段
if age <= 6:
print("婴幼儿 👶")
elif age <= 12: # 7-12岁
print("小学生 🎒")
elif age <= 15: # 13-15岁
print("初中生 📚")
elif age <= 18: # 16-18岁
print("高中生 🏫")
elif age <= 22: # 19-22岁
print("大学生 🎓")
elif age <= 60: # 23-60岁
print("成年人 💼")
else: # 60岁以上
print("老年人 👴")
示例2:周末活动计划
周末组织活动:
- 如果是晴天,就出去郊游
- 如果是阴天,就去参观动物园
- 如果是下雨天,就去室内游乐场
# 输入天气
weather = input("今天是什么天气?(晴天/阴天/雨天):")
# 根据天气决定活动
if weather == "晴天":
print("我们去郊游吧!")
elif weather == "阴天":
print("我们去参观动物园吧!")
elif weather == "雨天":
print("我们去室内游乐场玩吧!")
else:
print("输入错误,请重新输入!")
print("活动计划结束")
示例3:学生成绩等级
根据成绩判断等级:
- 100分:best
- 90-99分:very good
- 80-89分:good
- 60-79分:pass
- 低于60分:not pass
# 输入分数
score = int(input("请输入学生成绩:"))
# 判断等级
if score == 100:
print("等级:best 🌟")
elif score >= 90:
print("等级:very good 👍")
elif score >= 80:
print("等级:good 🙂")
elif score >= 60:
print("等级:pass 😐")
else:
print("等级:not pass 😞")
print("判断结束")
练习3
题目:根据用户输入的数字判断是奇数还是偶数。
👉 点击查看答案
# 输入数字
num = int(input("请输入一个整数:"))
# 判断奇偶
if num % 2 == 0:
print(f"{num}是偶数")
else:
print(f"{num}是奇数")
练习4
题目:根据指定的月份打印该月份所属的季节。(3-5月:春天,6-8月:夏天,9-11月:秋天,12-2月:冬天)
👉 点击查看答案
# 输入月份
month = int(input("请输入月份(1-12):"))
# 判断季节
if 3 <= month <= 5:
print("春天 🌸")
elif 6 <= month <= 8:
print("夏天 ☀️")
elif 9 <= month <= 11:
print("秋天 🍂")
else:
print("冬天 ❄️")
也可以用or写法:
month = int(input("请输入月份(1-12):"))
if month == 3 or month == 4 or month == 5:
print("春天 🌸")
elif month == 6 or month == 7 or month == 8:
print("夏天 ☀️")
elif month == 9 or month == 10 or month == 11:
print("秋天 🍂")
else:
print("冬天 ❄️")
嵌套if语句:条件中的条件
有时候,我们需要在一个条件判断内部再进行条件判断,这就是嵌套if语句。
嵌套if的基本语法
if 外层条件:
if 内层条件:
# 外层和内层条件都满足时执行
代码块1
else:
# 外层满足但内层不满足时执行
代码块2
else:
# 外层条件不满足时执行
代码块3
注意:每层if都要有自己的缩进!
示例1:活动计划(考虑工作日和天气)
活动计划的安排:
- 如果今天是工作日,则去上班
- 如果今天是周末,则外出游玩
- 同时,如果周末天气晴朗,则去室外游乐场游玩
- 否则去室内游乐场游玩
# 输入星期几和天气
day = input("今天是星期几?(1-7,1是周一):")
weather = input("今天天气如何?(晴天/其他):")
# 判断是工作日还是周末
if day in ["1", "2", "3", "4", "5"]:
print("今天是工作日,要去上班 😢")
else: # 周末(6或7)
print("今天是周末!🎉")
# 嵌套判断天气
if weather == "晴天":
print("天气晴朗,去室外游乐场玩!")
else:
print("天气不好,去室内游乐场玩!")
示例2:运动会决赛分组
学校举行运动会,百米赛跑跑入10秒内的学生有资格进决赛,根据性别分别进入男子组和女子组。
# 输入成绩和性别
time = float(input("请输入百米赛跑成绩(秒):"))
gender = input("请输入性别(男/女):")
# 判断是否有资格进决赛
if time < 10:
print("恭喜!你有资格进入决赛!")
# 嵌套判断性别分组
if gender == "男":
print("你被分到男子组 🏃♂️")
else:
print("你被分到女子组 🏃♀️")
else:
print("很遗憾,成绩未达标,不能进决赛")
给家长的小贴士:
- 解释“嵌套“的概念:一个if在另一个if里面
- 强调缩进的重要性:每层都有自己的缩进
- 建议先用自然语言描述逻辑,再转化为代码
练习5
题目:写一个简单的猜数字游戏。程序随机设定一个数字(可以先固定为7),用户输入猜测的数字,程序给出提示“太大了“、“太小了“或“猜对了”。
👉 点击查看答案
# 设定目标数字
target = 7
# 用户输入
guess = int(input("请输入你猜的数字(1-10):"))
# 判断大小
if guess == target:
print("🎉 恭喜你,猜对了!")
else:
if guess > target:
print("太大了!再试一次")
else:
print("太小了!再试一次")
print("游戏结束")
运行示例:
请输入你猜的数字(1-10):5
太小了!再试一次
游戏结束
请输入你猜的数字(1-10):9
太大了!再试一次
游戏结束
请输入你猜的数字(1-10):7
🎉 恭喜你,猜对了!
游戏结束
综合应用案例
案例1:计算周数和剩余天数
用户输入一个天数,可以输出包含多少周,以及剩余几天。
例如:
- 输入57天,打印“8 weeks and 1 day“
- 输入9天,打印“1 week and 2 days“
# 输入天数
days = int(input("请输入总天数:"))
# 计算周数和剩余天数
weeks = days // 7
remaining_days = days % 7
# 根据数量决定单复数
if weeks == 1:
week_str = "week"
else:
week_str = "weeks"
if remaining_days == 1:
day_str = "day"
else:
day_str = "days"
# 输出结果
print(f"{weeks} {week_str} and {remaining_days} {day_str}")
运行示例:
请输入总天数:57
8 weeks and 1 day
请输入总天数:9
1 week and 2 days
给家长的小贴士:
- 解释
//(整除)和%(求余)的区别- 强调英语中单数和复数的区别
- 这是一个综合练习,涉及运算、条件判断、字符串格式化
案例2:计算四位数数字之和
从键盘输入任意一个四位数,计算它四位数字相加的和。
# 输入一个四位数
num_str = input("请输入一个四位数:")
# 检查是否为四位数
if len(num_str) != 4:
print("输入错误!请输入一个四位数!")
else:
# 将字符串转换为数字
num = int(num_str)
# 分解每一位数字
# 方法1:用字符串切片
digit1 = int(num_str[0])
digit2 = int(num_str[1])
digit3 = int(num_str[2])
digit4 = int(num_str[3])
# 计算和
total = digit1 + digit2 + digit3 + digit4
print(f"四位数字之和为:{total}")
运行示例:
请输入一个四位数:1234
四位数字之和为:10
案例3:判断闰年
写出可以判定某一年是否是闰年的逻辑表达式。
闰年规则:
- 能被4整除但不能被100整除,或者能被400整除的年份
# 输入年份
year = int(input("请输入年份:"))
# 判断闰年
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
print(f"{year}年是闰年 📅")
else:
print(f"{year}年不是闰年")
运行示例:
请输入年份:2024
2024年是闰年 📅
请输入年份:1900
1900年不是闰年
请输入年份:2000
2000年是闰年 📅
给家长的小贴士:
- 解释闰年的历史背景(为什么会有闰年)
- 强调逻辑运算符的优先级:
and优先于or- 可以让孩子计算自己出生年份是否是闰年
案例4:狗狗年龄换算
根据用户输入的狗狗的年龄得出相当于人的多少岁。
换算规则:
- 狗狗的前2年,第一年相当于人的10.5岁,第二年也相当于10.5岁
- 往后每一年相当于4岁计算
- 狗狗最长活20年
# 输入狗狗年龄
dog_age = float(input("请输入狗狗的年龄:"))
# 检查年龄是否合理
if dog_age < 0 or dog_age > 20:
print("狗狗的年龄应该在0-20岁之间!")
else:
# 计算相当于人的年龄
if dog_age <= 2:
# 前两年,每年10.5岁
human_age = dog_age * 10.5
else:
# 前两年21岁,往后每年4岁
human_age = 21 + (dog_age - 2) * 4
print(f"狗狗{dog_age}岁,相当于人类{human_age}岁")
运行示例:
请输入狗狗的年龄:1
狗狗1.0岁,相当于人类10.5岁
请输入狗狗的年龄:5
狗狗5.0岁,相当于人类37.0岁
案例5:找三个数中的最大值
用户输入三个数,输出最大的。
# 输入三个数
num1 = float(input("请输入第一个数:"))
num2 = float(input("请输入第二个数:"))
num3 = float(input("请输入第三个数:"))
# 找最大值
if num1 >= num2 and num1 >= num3:
max_num = num1
elif num2 >= num1 and num2 >= num3:
max_num = num2
else:
max_num = num3
print(f"最大的数是:{max_num}")
运行示例:
请输入第一个数:5
请输入第二个数:12
请输入第三个数:8
最大的数是:12.0
另一种写法(逐步比较):
num1 = float(input("请输入第一个数:"))
num2 = float(input("请输入第二个数:"))
num3 = float(input("请输入第三个数:"))
# 假设第一个数最大
max_num = num1
# 如果第二个数更大,更新最大值
if num2 > max_num:
max_num = num2
# 如果第三个数更大,更新最大值
if num3 > max_num:
max_num = num3
print(f"最大的数是:{max_num}")
给家长的小贴士:
- 两种方法各有优缺点,可以讨论哪种更好理解
- 第二种方法更容易扩展到更多数字
- 为第10章(List)铺垫:可以用list和max()函数简化
常见错误和调试
错误1:忘记冒号
# 错误:if后面没有冒号
if score > 60
print("及格了")
# 正确
if score > 60:
print("及格了")
错误2:缩进不正确
# 错误:缩进不一致
if score > 60:
print("及格了") # 2个空格
print("恭喜!") # 4个空格
# 正确:缩进一致
if score > 60:
print("及格了")
print("恭喜!")
错误3:赋值和比较混淆
# 错误:用=而不是==
if score = 100:
print("完美")
# 正确:用==比较
if score == 100:
print("完美")
错误4:条件顺序错误
score = 85
# 错误:顺序错了,永远无法判断到80-89
if score >= 60:
print("及格")
elif score >= 80:
print("良好")
elif score >= 90:
print("优秀")
# 正确:从高到低判断
if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
给家长的小贴士:
- 教孩子学会看错误信息(SyntaxError, IndentationError等)
- 使用print语句在关键位置输出中间结果,帮助调试
- 用简单的例子测试条件是否正确
条件表达式(三元运算符)
Python还提供了一种简洁的条件表达式,也叫三元运算符。
基本语法
结果1 if 条件 else 结果2
解释:如果条件为True,返回结果1;否则返回结果2。
示例:找出两个数中的较大值
# 传统写法
a = 10
b = 20
if a > b:
max_num = a
else:
max_num = b
print(f"较大的数是:{max_num}")
用条件表达式简化:
a = 10
b = 20
max_num = a if a > b else b
print(f"较大的数是:{max_num}")
练习6
题目:用条件表达式判断一个数是正数、负数还是零,并输出“正数“、“负数“或“零”。
👉 点击查看答案
num = float(input("请输入一个数字:"))
result = "正数" if num > 0 else "负数" if num < 0 else "零"
print(f"{num}是{result}")
注意:这种嵌套的三元表达式可读性较差,不建议过度使用。
综合练习:星期几判断器
题目:请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母。
# 输入第一个字母
first_letter = input("请输入星期几的第一个字母:").lower()
# 判断第一个字母
if first_letter == 'm':
print("星期一 Monday")
elif first_letter == 't':
# 需要判断第二个字母
second_letter = input("请输入第二个字母:").lower()
if second_letter == 'u':
print("星期二 Tuesday")
elif second_letter == 'h':
print("星期四 Thursday")
else:
print("输入错误!")
elif first_letter == 'w':
print("星期三 Wednesday")
elif first_letter == 'f':
print("星期五 Friday")
elif first_letter == 's':
# 需要判断第二个字母
second_letter = input("请输入第二个字母:").lower()
if second_letter == 'a':
print("星期六 Saturday")
elif second_letter == 'u':
print("星期日 Sunday")
else:
print("输入错误!")
else:
print("输入错误!")
运行示例:
请输入星期几的第一个字母:s
请输入第二个字母:a
星期六 Saturday
请输入星期几的第一个字母:t
请输入第二个字母:u
星期二 Tuesday
章节小结
我们学到了什么
- 条件语句:让程序能够根据不同情况做不同决定
- if语句:最简单的条件判断
- if-else语句:两种选择
- if-elif-else语句:多种选择
- 嵌套if语句:条件中的条件
- 条件表达式:简洁的三元运算符
重要语法回顾
| 语句结构 | 用途 |
|---|---|
if 条件: | 单一条件判断 |
if-else: | 两种选择 |
if-elif-else: | 多种选择 |
| 嵌套if | 复杂条件判断 |
编程技巧
- 缩进很重要:Python用缩进来组织代码块
- 条件顺序:在if-elif中,条件从上到下检查,满足即停止
- 冒号不能忘:if、elif、else后面都要有冒号
- 布尔运算:用and、or、not组合多个条件
- 调试方法:用print输出中间结果,帮助定位问题
下一步
在下一章(第8章),我们将学习循环语句(for和while),让程序能够重复执行某些操作。结合条件语句和循环,我们就能写出更强大的程序!
挑战练习
-
必做:
- 写一个程序,输入三个数,输出最小的数
- 写一个程序,输入年份和月份,输出该月有多少天
- 写一个程序,输入三角形的三边长,判断能否构成三角形
-
选做:
- 写一个简单的计算器,可以加减乘除
- 写一个石头剪刀布游戏
- 写一个温度转换器(摄氏度/华氏度/开尔文)
-
挑战:
- 写一个猜数字游戏,限制猜测次数(比如5次)
- 写一个登录系统,可以有注册、登录、修改密码功能
- 用Turtle库画一个图形,根据用户输入的数字决定画什么图形
加油!你已经学会让程序做决定的能力了!🎉
循环语句
引言
在前面的章节中,我们学习了顺序语句和条件语句。顺序语句让程序按顺序执行,条件语句让程序根据不同情况做不同决定。
但是,如果需要重复做某些事情呢?
想象一下:
- 老师让你把“我要好好学习“这句话写100遍
- 你要帮妈妈数一共有多少颗糖果
- 计算从1加到100的和
- 画一个正方形,要画4条边
这些都需要重复执行相同的操作。在Python中,我们用循环语句来实现这种功能。
这一章,我们将学习:
- 什么是循环
- while循环(条件循环)
- for循环(计数循环)
- 循环嵌套(循环中的循环)
- break和continue(控制循环)
- 用循环解决实际问题
为什么需要循环
让我们先看一个例子:假设我们要打印5次“Python真有趣!“。
不用循环的方法
print("Python真有趣!")
print("Python真有趣!")
print("Python真有趣!")
print("Python真有趣!")
print("Python真有趣!")
问题:
- 需要写很多重复的代码
- 如果要打印100次,会非常麻烦
- 代码容易出错,难以维护
用循环的方法
# 用循环打印5次
count = 0
while count < 5:
print("Python真有趣!")
count = count + 1
优势:
- 代码简洁,只写一次
- 想打印多少次都可以,只需修改条件
- 容易维护和修改
给家长的小贴士:
- 用生活中的例子解释循环:绕操场跑圈、抄写生字、数数
- 强调循环的好处:省时、省力、不容易出错
- 可以让孩子想想生活中有哪些“重复“的事情
💡 计算机为什么擅长重复工作?
CPU的“超能力“——重复执行
在第6章,我们学习了CPU是如何执行指令的:
- 取指令→译码→执行→重复
现在,我们要学习循环,这正好发挥了CPU最强大的能力——高速重复执行!
比喻时间 🎯 想象你和计算机比赛抄写生字:
- 你:抄写100遍“我要好好学习“,需要1-2小时,手会酸
- CPU:每秒能执行几十亿次运算,100遍对它来说不到0.000001秒!
数学小挑战 🧮 让我们算一算CPU有多快:
示例:假设有一个1GHz的CPU(每秒执行10亿次运算)
- 每秒能执行:1,000,000,000次运算
- 执行100次简单循环需要:100 ÷ 1,000,000,000 = 0.0000001秒!
- 执行1,000,000次(100万次)需要:0.001秒!
- 执行1,000,000,000次(10亿次)需要:1秒
# 让我们感受一下CPU的速度
import time
# 测试:执行1000次循环
start = time.time() # 记录开始时间
for i in range(1000):
result = i * 2 # 简单的乘法
end = time.time() # 记录结束时间
print(f"执行1000次循环用时:{(end - start) * 1000:.4f}毫秒")
print(f"如果每秒能执行10亿次运算,1000次只需要0.000001秒!")
运行结果(因电脑而异):
执行1000次循环用时:0.0980毫秒
如果每秒能执行10亿次运算,1000次只需要0.000001秒!
👨🏫 给家长的Tips
知识点补充(针对家长):
- CPU主频(如2GHz、3GHz)表示每秒的时钟周期数
- 1GHz = 10亿个周期/秒,3GHz = 30亿个周期/秒
- 每个周期可能执行1-4条指令(现代CPU有指令级并行)
- 所以一个3GHz CPU理论上每秒可执行几十亿到上百亿条指令!
如何给孩子讲解:
- 不需要深入技术细节
- 重点让孩子理解:计算机不怕重复,速度极快
- 用“抄写生字“的类比:人讨厌重复,但计算机擅长重复
- 这就是为什么我们用循环——让计算机发挥它的“超能力“!
为什么计算机适合做重复性工作?
人类 vs 计算机:
| 任务 | 人类 | 计算机 |
|---|---|---|
| 抄写100遍生字 | 1-2小时,手酸,无聊 | 不到0.001秒,不会累 |
| 数1到100万 | 几天,数错概率高 | 不到1秒,100%准确 |
| 搜索1000个名字 | 几十分钟,会疲劳 | 不到0.1秒,不会错 |
| 画1000个正方形 | 几小时,画得不一样 | 几秒钟,一模一样 |
人类的优势:
- ✅ 创造力(画画、写作、发明)
- ✅ 情感理解(理解笑话、安慰人)
- ✅ 灵活适应(处理突发情况)
计算机的优势:
- ✅ 高速重复(不嫌累、不嫌烦)
- ✅ 精确无误(不会算错)
- ✅ 海量存储(记住无数数据)
结论 🎯
- 让人类做创造性的工作(设计游戏、写故事、发明)
- 让计算机做重复性的工作(计算、搜索、排序)
- 循环就是让计算机发挥重复工作的“超能力“!
👨🏫 给家长的Tips
教育意义:
- 让孩子理解:学习编程不是为了取代人类
- 而是为了让计算机帮我们做重复、枯燥的工作
- 这样人类就能把精力花在更有创造性的任务上
- 这就是“人机协作“的思想
生活中的例子:
- 计算器:做复杂的数学计算(重复性工作)
- 搜索引擎:在亿万网页中搜索信息(重复性工作)
- Excel:自动计算1000行数据的总和(重复性工作)
- 人类:设计算法、写文章、创作艺术(创造性工作)
while循环:条件循环
while循环是条件循环,只要条件为True,就一直重复执行代码块。
while循环的基本语法
while 条件:
# 条件为True时重复执行的代码
代码块
语法要点:
while后面跟着一个条件(布尔表达式)- 条件后面必须有冒号
: - 要执行的代码必须缩进
- 当条件为False时,循环结束
循环的三个重要元素
- 初始值: 循环变量的初始值
- 条件: 判断是否继续循环
- 更新: 循环变量如何变化
示例模式:
# 1. 初始值
count = 0
# 2. 条件
while count < 5:
print(f"第{count + 1}次: Python真有趣!")
# 3. 更新循环变量
count = count + 1
print("循环结束!")
输出结果:
第1次: Python真有趣!
第2次: Python真有趣!
第3次: Python真有趣!
第4次: Python真有趣!
第5次: Python真有趣!
循环结束!
给家长的小贴士:
- 重点讲解“循环变量更新“的重要性
- 如果忘记更新,会变成“死循环“(无限循环)
- 可以用“计数器“的概念来解释循环变量
- 建议画出表格,记录每次循环时变量的值
示例1:打印数字
# 打印1到5的数字
count = 1
while count <= 5:
print(count)
count = count + 1
print("打印完成!")
输出结果:
1
2
3
4
5
打印完成!
示例2:累加求和
# 计算1到5的和
total = 0 # 累积变量,保存总和
count = 1 # 计数变量
while count <= 5:
total = total + count # 累加
print(f"加{count}, 当前和:{total}")
count = count + 1
print(f"1到5的和是:{total}")
输出结果:
加1, 当前和:1
加2, 当前和:3
加3, 当前和:6
加4, 当前和:10
加5, 当前和:15
1到5的和是:15
给家长的小贴士:
- 用“存钱罐“类比累积变量
- 每次循环往存钱罐里加钱
- 循环结束时,存钱罐里的钱就是总和
- 强调初始值的重要性:total要从0开始
示例3:打印三角形*
# 打印一个直角三角形
line = 1
while line <= 5:
# 每行打印line个*
print("*" * line)
line = line + 1
输出结果:
*
**
***
****
*****
练习1:打印一棵圣诞树
题目:用while循环打印一棵圣诞树。
要求:
- 树冠:3层,每层*数量递增
- 树干:1层,用|表示
👉 点击查看答案
# 打印圣诞树
# 树冠部分
line = 1
while line <= 3:
# 打印空格(居中)
spaces = " " * (3 - line)
# 打印*
stars = "*" * (2 * line - 1)
print(spaces + stars)
line = line + 1
# 树干部分
print(" | ") # 树干
print(" | ") # 树干
输出结果:
*
***
*****
|
|
简单版本:
# 简单的圣诞树
line = 1
while line <= 3:
print("*" * line)
line = line + 1
print("*") # 树干
while循环中嵌套条件
在循环中,我们可以结合条件语句,实现更复杂的逻辑。
示例1:打印偶数
# 打印1到10中所有的偶数
count = 1
while count <= 10:
# 判断是否为偶数
if count % 2 == 0:
print(f"{count}是偶数")
count = count + 1
print("打印完成!")
输出结果:
2是偶数
4是偶数
6是偶数
8是偶数
10是偶数
打印完成!
示例2:标记特殊数字
# 打印1到10,在3的倍数前加标记
count = 1
while count <= 10:
# 判断是否为3的倍数
if count % 3 == 0:
print(f"[3的倍数] {count}")
else:
print(count)
count = count + 1
输出结果:
1
2
[3的倍数] 3
4
5
[3的倍数] 6
7
8
[3的倍数] 9
10
示例3:统计奇数和偶数的和
# 计算1到10之间偶数和奇数的和
even_sum = 0 # 偶数和
odd_sum = 0 # 奇数和
count = 1
while count <= 10:
if count % 2 == 0:
# 偶数加到even_sum
even_sum = even_sum + count
print(f"{count}是偶数, 偶数和:{even_sum}")
else:
# 奇数加到odd_sum
odd_sum = odd_sum + count
print(f"{count}是奇数, 奇数和:{odd_sum}")
count = count + 1
print(f"\n偶数和:{even_sum}")
print(f"奇数和:{odd_sum}")
输出结果:
1是奇数, 奇数和:1
2是偶数, 偶数和:2
3是奇数, 奇数和:4
4是偶数, 偶数和:6
5是奇数, 奇数和:9
6是偶数, 偶数和:12
7是奇数, 奇数和:16
8是偶数, 偶数和:20
9是奇数, 奇数和:25
10是偶数, 偶数和:30
偶数和:30
奇数和:25
给家长的小贴士:
- 解释“累加器“的概念
- 每个累加器都要有自己的初始值
- 建议画图理解:两个篮子,分别装奇数和偶数
- 强调print语句在循环中的调试作用
练习2:倒三角形
题目:用while循环打印倒三角形。
👉 点击查看答案
# 打印倒三角形
line = 5
while line >= 1:
print("*" * line)
line = line - 1
输出结果:
*****
****
***
**
*
练习3:求能被3整除的数字的乘积
题目:计算1到10之间能被3整除的数字的乘积。
👉 点击查看答案
# 计算1到10中能被3整除的数字的乘积
product = 1 # 乘积的初始值是1,不是0!
count = 1
while count <= 10:
if count % 3 == 0:
product = product * count
print(f"乘{count}, 当前乘积:{product}")
count = count + 1
print(f"乘积是:{product}")
输出结果:
乘3, 当前乘积:3
乘6, 当前乘积:18
乘9, 当前乘积:162
乘积是:162
重要提示:
- 乘积的初始值必须是1,不能是0!
- 如果初始值是0,乘积永远是0
for循环和range函数
for循环通常和range()函数一起使用,用于已知循环次数的情况。
range函数
range()函数生成一个数字序列。
基本用法:
# range(开始, 结束, 步长)
# 注意:结束值不包含在内!
示例:
# range(5): 生成0, 1, 2, 3, 4
for i in range(5):
print(i)
print("------")
# range(1, 6): 生成1, 2, 3, 4, 5
for i in range(1, 6):
print(i)
print("------")
# range(1, 10, 2): 生成1, 3, 5, 7, 9 (奇数)
for i in range(1, 10, 2):
print(i)
print("------")
# range(10, 0, -1): 生成10, 9, 8, 7, 6, 5, 4, 3, 2, 1 (倒数)
for i in range(10, 0, -1):
print(i)
给家长的小贴士:
- 重点强调“结束值不包含“
- range(1, 5)生成1, 2, 3, 4,不包括5
- 用“排队“类比:从1号排到4号,5号不排
- 步长可以是负数,实现倒序
for循环的基本语法
for 变量 in range(开始, 结束):
# 循环体
示例1:打印数字
# 用for循环打印1到5
for i in range(1, 6):
print(i)
print("完成!")
输出结果:
1
2
3
4
5
完成!
示例2:求和
# 用for循环计算1到5的和
total = 0
for i in range(1, 6):
total = total + i
print(f"加{i}, 当前和:{total}")
print(f"1到5的和是:{total}")
示例3:遍历字符串
# 遍历字符串中的每个字符
name = "Python"
for ch in name:
print(ch)
输出结果:
P
y
t
h
o
n
while vs for:如何选择?
| 特点 | while循环 | for循环 |
|---|---|---|
| 使用场景 | 不知道循环次数 | 知道循环次数 |
| 循环条件 | 根据条件判断 | 遍历序列 |
| 需要手动 | 更新循环变量 | 自动更新变量 |
| 例子 | “直到用户输入正确” | “打印1到100” |
示例对比:
# while循环版本
count = 1
while count <= 5:
print(count)
count = count + 1
print("------")
# for循环版本(更简洁!)
for i in range(1, 6):
print(i)
给家长的小贴士:
- 如果知道循环次数,优先用for循环
- for循环更简洁,不容易出错(自动更新变量)
- while循环更灵活,适合复杂条件
- 建议让孩子用两种方法写同一个程序,体会区别
break和continue
在循环中,我们可以用break和continue来控制循环的执行。
break:跳出循环
break会立即终止整个循环。
示例:
# 找到第一个能被7整除的数
for i in range(1, 100):
if i % 7 == 0:
print(f"找到了!第一个能被7整除的数是:{i}")
break # 找到就退出循环
print("程序结束")
输出结果:
找到了!第一个能被7整除的数是:7
程序结束
continue:跳过本次循环
continue会跳过本次循环,直接进入下一次循环。
示例:
# 打印1到10中的奇数(跳过偶数)
for i in range(1, 11):
if i % 2 == 0:
continue # 跳过偶数,不执行后面的print
print(i)
print("打印完成")
输出结果:
1
3
5
7
9
打印完成
示例:累加直到和大于等于100
# 计算1+2+3+...,直到和大于等于100
total = 0
count = 1
while True: # 无限循环
total = total + count
print(f"加{count}, 当前和:{total}")
if total >= 100:
print(f"和达到{total}, 停止!")
break # 达到目标,退出循环
count = count + 1
输出结果:
加1, 当前和:1
加2, 当前和:3
加3, 当前和:6
...
加13, 当前和:91
加14, 当前和:105
和达到105, 停止!
示例:QQ登录验证
# 模拟QQ登录
correct_username = "admin"
correct_password = "123456"
while True:
# 输入用户名和密码
username = input("请输入用户名:")
password = input("请输入密码:")
# 验证
if username == correct_username and password == correct_password:
print("登录成功!")
break # 登录成功,退出循环
else:
print("用户名或密码错误,请重新输入!\n")
print("欢迎进入系统!")
给家长的小贴士:
break就像“紧急出口“,随时可以离开循环continue就像“跳过“,这次不做,继续下一次while True是一个无限循环,必须有break才能退出- 强调滥用break和continue会让代码难以理解
- 建议先用普通循环写法,熟练后再用这些控制语句
循环嵌套
一个循环内部可以再包含另一个循环,这就是循环嵌套。
示例1:打印数字矩形
# 打印数字矩形
for i in range(1, 4): # 外层循环:控制行
for j in range(1, 4): # 内层循环:控制列
print(f"{i}", end=" ") # end=" "表示不换行
print() # 每行结束后换行
输出结果:
1 1 1
2 2 2
3 3 3
示例2:打印乘法口诀表
# 打印乘法口诀表(9x9)
for i in range(1, 10): # 行:1到9
for j in range(1, i + 1): # 列:1到i
result = i * j
print(f"{j}x{i}={result}", end="\t") # \t是制表符
print() # 换行
输出结果:
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
给家长的小贴士:
- 用“时钟“类比嵌套循环:时针和分针
- 外层循环执行一次,内层循环执行完整一轮
- 建议画出执行过程,理解嵌套逻辑
- 强调缩进的重要性:内层循环要多缩进一层
示例3:找出所有三位数
题目:用1、2、3、4四个数字,能组成多少个三位数?
# 用1、2、3、4组成三位数
count = 0 # 计数器
print("可以组成的三位数:")
for i in [1, 2, 3, 4]: # 百位
for j in [1, 2, 3, 4]: # 十位
for k in [1, 2, 3, 4]: # 个位
num = i * 100 + j * 10 + k
print(num, end=" ")
count = count + 1
# 每行打印10个
if count % 10 == 0:
print()
print(f"\n总共可以组成{count}个三位数")
示例4:找出无重复数字的三位数
题目:用1、2、3、4四个数字,能组成多少个无重复数字的三位数?
# 用1、2、3、4组成无重复数字的三位数
count = 0
print("无重复数字的三位数:")
for i in [1, 2, 3, 4]: # 百位
for j in [1, 2, 3, 4]: # 十位
if j == i: # 十位和百位不能相同
continue
for k in [1, 2, 3, 4]: # 个位
if k == i or k == j: # 个位不能和百位、十位相同
continue
num = i * 100 + j * 10 + k
print(num, end=" ")
count = count + 1
# 每行打印10个
if count % 10 == 0:
print()
print(f"\n总共可以组成{count}个无重复数字的三位数")
输出结果:
无重复数字的三位数:
123 124 132 134 142 143 213 214 231 234
241 243 312 314 321 324 341 342 412 413
421 423 431 432
总共可以组成24个无重复数字的三位数
常见循环模式和技巧
模式1:计数器模式
# 计数器:统计满足条件的数量
count = 0
for i in range(1, 101):
if i % 7 == 0:
count = count + 1
print(f"1到100之间有{count}个数能被7整除")
模式2:累加器模式
# 累加器:求和
total = 0
for i in range(1, 101):
total = total + i
print(f"1到100的和是:{total}")
模式3:累乘器模式
# 累乘器:求阶乘(5! = 5x4x3x2x1)
factorial = 1
for i in range(1, 6):
factorial = factorial * i
print(f"5的阶乘是:{factorial}")
模式4:最大值/最小值查找
# 找最大值
numbers = [23, 45, 12, 67, 34, 89, 5]
max_num = numbers[0] # 假设第一个是最大的
for num in numbers:
if num > max_num:
max_num = num
print(f"最大的数是:{max_num}")
模式5:正序和反序遍历
# 正序遍历
for i in range(1, 6):
print(i, end=" ")
print()
# 反序遍历
for i in range(5, 0, -1):
print(i, end=" ")
print()
# 步长为2
for i in range(1, 10, 2):
print(i, end=" ")
给家长的小贴士:
- 这些模式在编程中非常常见
- 建议让孩子记住这些基本模式
- 可以用生活中的例子类比:计数器、存钱罐、找最大数
- 鼓励孩子用这些模式解决新问题
综合练习
练习1:打印30以内的自然数
题目:分别用while和for循环打印30以内的自然数(包含30)。
👉 点击查看答案
while版本:
# while循环
count = 0
while count <= 30:
print(count, end=" ")
count = count + 1
for版本:
# for循环
for i in range(31): # range(31) = range(0, 31) = 0到30
print(i, end=" ")
练习2:挑水问题
题目:一口缸容量有180升,一个和尚每次挑水20升,多少次挑满?
👉 点击查看答案
# 挑水问题
capacity = 180 # 缸的容量
each_time = 20 # 每次挑水量
current = 0 # 当前水量
count = 0 # 挑水次数
while current < capacity:
current = current + each_time
count = count + 1
print(f"第{count}次挑水,当前水量:{current}升")
print(f"需要{count}次才能挑满")
输出结果:
第1次挑水,当前水量:20升
第2次挑水,当前水量:40升
...
第9次挑水,当前水量:180升
需要9次才能挑满
更简洁的写法:
capacity = 180
each_time = 20
# 用整除计算
times = capacity // each_time
# 如果有余数,需要多挑一次
if capacity % each_time != 0:
times = times + 1
print(f"需要{times}次才能挑满")
练习3:统计学生成绩
题目:循环录入Java课的学生成绩,统计分数大于等于80分的学生比例。
👉 点击查看答案
# 统计学生成绩
total_students = int(input("请输入学生人数:"))
pass_count = 0 # 大于等于80分的人数
for i in range(total_students):
score = int(input(f"请输入第{i + 1}个学生的成绩:"))
if score >= 80:
pass_count = pass_count + 1
print(f"成绩{score}:优秀!")
else:
print(f"成绩{score}:继续努力!")
# 计算比例
percentage = (pass_count / total_students) * 100
print(f"\n统计结果:")
print(f"总人数:{total_students}")
print(f"优秀人数:{pass_count}")
print(f"优秀比例:{percentage:.1f}%")
运行示例:
请输入学生人数:5
请输入第1个学生的成绩:85
成绩85:优秀!
请输入第2个学生的成绩:72
成绩72:继续努力!
请输入第3个学生的成绩:90
成绩90:优秀!
请输入第4个学生的成绩:68
成绩68:继续努力!
请输入第5个学生的成绩:82
成绩82:优秀!
统计结果:
总人数:5
优秀人数:3
优秀比例:60.0%
练习4:小芳存钱
题目:小芳的妈妈每天给她2.5元钱,她都会存起来。从存钱开始,每过5天她就会花去6元钱。请问要到第几天,小芳才可以存满100元钱?
👉 点击查看答案
# 小芳存钱问题
money = 0 # 当前存款
day = 0 # 天数
while money < 100:
day = day + 1
money = money + 2.5 # 每天存2.5元
print(f"第{day}天:存2.5元,当前存款:{money}元")
# 每5天花6元
if day % 5 == 0:
money = money - 6
print(f" -> 第{day}天:花6元,剩余存款:{money}元")
print(f"\n第{day}天,小芳存满了100元!")
输出结果:
第1天:存2.5元,当前存款:2.5元
第2天:存2.5元,当前存款:5.0元
第3天:存2.5元,当前存款:7.5元
第4天:存2.5元,当前存款:10.0元
第5天:存2.5元,当前存款:12.5元
-> 第5天:花6元,剩余存款:6.5元
...
第50天:存2.5元,当前存款:97.5元
第51天:存2.5元,当前存款:100.0元
第51天,小芳存满了100元!
练习5:求100以内偶数之和
题目:求100以内的偶数之和。
👉 点击查看答案
方法1:用if判断:
total = 0
for i in range(1, 101):
if i % 2 == 0:
total = total + i
print(f"100以内偶数之和:{total}")
方法2:用步长2(更高效):
total = 0
for i in range(0, 101, 2): # 直接生成偶数
total = total + i
print(f"100以内偶数之和:{total}")
输出结果:
100以内偶数之和:2550
练习6:求100以内6的倍数
题目:求出100以内的所有6的倍数,以及个数。
👉 点击查看答案
# 求100以内6的倍数
count = 0
print("100以内的6的倍数:")
for i in range(1, 101):
if i % 6 == 0:
print(i, end=" ")
count = count + 1
print(f"\n总共{count}个")
输出结果:
100以内的6的倍数:
6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96
总共16个
练习7:打印数字矩形
题目:在控制台输出图形,第一行输出一个1,第二行输出二个2,第n行输出n个n。
👉 点击查看答案
# 打印数字矩形
n = int(input("请输入行数:"))
for i in range(1, n + 1):
# 打印i个i
for j in range(i):
print(i, end=" ")
print() # 换行
运行示例:
请输入行数:5
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
练习8:水仙花数
题目:打印所有水仙花数。
什么是水仙花数?
- 一个三位数
- 例如153,1³ + 5³ + 3³ = 153
- 即:各位数字的立方和等于它本身
👉 点击查看答案
# 打印水仙花数
print("三位数的水仙花数:")
for num in range(100, 1000): # 遍历所有三位数
# 分解百位、十位、个位
hundreds = num // 100 # 百位
tens = (num // 10) % 10 # 十位
ones = num % 10 # 个位
# 计算各位数字的立方和
sum_of_cubes = hundreds ** 3 + tens ** 3 + ones ** 3
# 判断是否为水仙花数
if sum_of_cubes == num:
print(num)
print("查找完成!")
输出结果:
三位数的水仙花数:
153
370
371
407
查找完成!
给家长的小贴士:
- 解释“水仙花数“的含义
- 重点讲解如何分解一个三位数的百位、十位、个位
- 用除法和取余运算:
- 百位 = num // 100
- 十位 = (num // 10) % 10
- 个位 = num % 10
- 这是一个经典的编程练习,锻炼数学和编程结合的能力
练习9:交错数列求和
题目:计算1 - 2 + 3 - 4 + 5 - … + 99的结果。
👉 点击查看答案
# 计算交错数列求和: 1 - 2 + 3 - 4 + ... + 99
total = 0
for i in range(1, 100): # 1到99
if i % 2 == 1:
# 奇数相加
total = total + i
print(f"+{i}", end=" ")
else:
# 偶数相减
total = total - i
print(f"-{i}", end=" ")
print(f"\n结果:{total}")
输出结果:
+1 -2 +3 -4 +5 -6 +7 -8 +9 -10 +11 -12 +13 -14 +15 -16 +17 -18 +19 -20 +21 -22 +23 -24 +25 -26 +27 -28 +29 -30 +31 -32 +33 -34 +35 -36 +37 -38 +39 -40 +41 -42 +43 -44 +45 -46 +47 -48 +49 -50 +51 -52 +53 -54 +55 -56 +57 -58 +59 -60 +61 -62 +63 -64 +65 -66 +67 -68 +69 -70 +71 -72 +73 -74 +75 -76 +77 -78 +79 -80 +81 -82 +83 -84 +85 -86 +87 -88 +89 -90 +91 -92 +93 -94 +95 -96 +97 -98 +99
结果:50
更简洁的写法:
# 方法2:观察规律
# (1-2) + (3-4) + (5-6) + ... + (97-98) + 99
# = -1 + -1 + -1 + ... + -1 + 99
# 共49个-1,最后+99
# = -49 + 99 = 50
# 或者换个角度:
# 1 + 3 + 5 + ... + 99 = 2500 (奇数和)
# 2 + 4 + 6 + ... + 98 = 2450 (偶数和)
# 2500 - 2450 = 50
odd_sum = 0
even_sum = 0
for i in range(1, 100):
if i % 2 == 1:
odd_sum = odd_sum + i
else:
even_sum = even_sum + i
result = odd_sum - even_sum
print(f"奇数和:{odd_sum}, 偶数和:{even_sum}, 结果:{result}")
练习10:猜数字游戏(限制次数)
题目:写一个猜数字游戏,猜对了结束,猜不对继续,最多猜9次。
👉 点击查看答案
# 猜数字游戏
import random # 随机数库
target = random.randint(1, 100) # 生成1到100的随机数
max_attempts = 9
print("=== 猜数字游戏 ===")
print(f"我已经想好了一个1到100之间的数字,你有{max_attempts}次机会猜!")
for attempt in range(1, max_attempts + 1):
guess = int(input(f"\n第{attempt}次猜测,请输入你的猜测(1-100):"))
if guess == target:
print(f"🎉 恭喜你!第{attempt}次就猜对了!数字是:{target}")
break # 猜对了,退出循环
elif guess < target:
print(f"太小了!还有{max_attempts - attempt}次机会")
else:
print(f"太大了!还有{max_attempts - attempt}次机会")
else:
# for循环正常结束(没有break)时执行
print(f"\n😢 很遗憾,你没有猜对。正确答案是:{target}")
print("\n游戏结束!")
运行示例:
=== 猜数字游戏 ===
我已经想好了一个1到100之间的数字,你有9次机会猜!
第1次猜测,请输入你的猜测(1-100):50
太大了!还有8次机会
第2次猜测,请输入你的猜测(1-100):25
太小了!还有7次机会
第3次猜测,请输入你的猜测(1-100):37
太大了!还有6次机会
第4次猜测,请输入你的猜测(1-100):31
🎉 恭喜你!第4次就猜对了!数字是:31
游戏结束!
给家长的小贴士:
- 这是一个综合练习,用到了循环、条件、break、else等
for...else语法:当for循环正常结束(没有break)时,执行else- 可以和孩子一起玩这个游戏,增加趣味性
- 可以讨论如何用“二分查找“策略提高猜测效率
练习11:求素数
题目:输入一个正整数n,判断它是否为素数。
什么是素数?
- 只能被1和它本身整除的数
- 例如:2, 3, 5, 7, 11, 13, 17, 19, 23, …
- 1不是素数
- 2是最小的素数,也是唯一的偶数素数
👉 点击查看答案
# 判断一个数是否为素数
num = int(input("请输入一个正整数:"))
# 处理特殊情况
if num < 2:
print(f"{num}不是素数")
elif num == 2:
print(f"{num}是素数")
elif num % 2 == 0:
print(f"{num}不是素数(能被2整除)")
else:
# 判断从3到num-1是否有能整除的数
is_prime = True # 假设是素数
for i in range(3, num):
if num % i == 0:
is_prime = False
print(f"{num}不是素数(能被{i}整除)")
break # 找到一个因数就够了
# 如果循环正常结束,说明没有找到因数
if is_prime:
print(f"{num}是素数!")
运行示例:
请输入一个正整数:17
17是素数!
请输入一个正整数:15
15不是素数(能被3整除)
进阶:打印100以内的所有素数:
# 打印100以内的所有素数
print("100以内的素数:")
for num in range(2, 101):
if num == 2:
print(num, end=" ")
continue
if num % 2 == 0:
continue
# 判断是否为素数
is_prime = True
for i in range(3, num):
if num % i == 0:
is_prime = False
break
if is_prime:
print(num, end=" ")
输出结果:
100以内的素数:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
给家长的小贴士:
- 素数判断是一个经典算法问题
- 可以优化:只需要判断到√n,不需要到n-1
- 这是密码学的基础( RSA加密算法用到素数)
- 可以和孩子讨论为什么素数很重要
用循环简化Turtle图形
还记得第6章我们用Turtle画图形吗?当时我们用顺序语句,每个边都要写一遍代码。现在学完循环后,我们可以大大简化这些代码!
回顾:第6章的画图代码
在第6章,我们画正方形时是这样的:
import turtle
t = turtle.Turtle()
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
问题:这段代码重复了4次相同的内容!如果我们想画正六边形、正八边形,代码会变得很长。
用循环改进:画正n边形
现在我们可以用循环来简化:
import turtle
t = turtle.Turtle()
# 画正方形(4条边)
for i in range(4):
t.forward(100)
t.left(90)
turtle.done()
优势:
- 代码从8行减少到3行!
- 如果要画正六边形,只需要改数字:
for i in range(6): t.forward(100) t.left(60) # 360 ÷ 6 = 60度
👨🏫 给家长的Tips
这是一个绝佳的教学时机!
- 让孩子对比两种写法的代码行数
- 问孩子:“哪种写法更简单?如果我要画正12边形呢?”
- 引导孩子理解:循环就是让计算机帮我们重复做相同的事
- 强调:程序员很“懒“,总在想办法让代码更简洁
练习1:改写长方形画法
第6章的代码(顺序语句):
length = 150
width = 80
t.forward(length)
t.left(90)
t.forward(width)
t.left(90)
t.forward(length)
t.left(90)
t.forward(width)
t.left(90)
用循环改进:
length = 150
width = 80
for i in range(2): # 重复2次
t.forward(length)
t.left(90)
t.forward(width)
t.left(90)
代码从10行减少到5行!
练习2:改写五边形
第6章的代码:
side = 100
angle = 360 / 5 # 72度
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
t.forward(side)
t.left(angle)
用循环改进:
side = 100
angle = 360 / 5
for i in range(5):
t.forward(side)
t.left(angle)
代码从11行减少到3行!
练习3:改写五角星
第6章的代码:
t.pencolor("gold")
t.fillcolor("orange")
t.begin_fill()
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.forward(200)
t.right(144)
t.end_fill()
用循环改进:
t.pencolor("gold")
t.fillcolor("orange")
t.begin_fill()
for i in range(5):
t.forward(200)
t.right(144)
t.end_fill()
挑战项目:用循环画复杂图形
现在你掌握了循环,可以尝试画更复杂的图形了!
项目1:彩色多边形螺旋
import turtle
t = turtle.Turtle()
t.speed(0) # 最快速度
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
# 画36个逐渐变大的正方形
for i in range(36):
t.pencolor(colors[i % 6]) # 循环使用6种颜色
t.forward(50 + i * 5) # 每次边长增加
t.left(90) # 转向
t.forward(50 + i * 5)
t.left(90)
t.forward(50 + i * 5)
t.left(90)
t.forward(50 + i * 5)
t.left(90)
t.left(10) # 每次多转10度,形成螺旋
turtle.done()
项目2:花朵(第6章留下的挑战)
在第6章,我们说花朵练习要等学完循环再做。现在可以了!
import turtle
t = turtle.Turtle()
t.speed(10)
colors = ["red", "orange", "yellow", "pink", "purple", "blue"]
# 画6个花瓣
for i in range(6):
t.color(colors[i])
t.begin_fill()
# 画椭圆(通过多次小角度转向实现)
for j in range(36):
t.forward(20)
t.left(10)
t.left(60) # 转到下一个花瓣
t.end_fill()
# 画花心
t.penup()
t.goto(0, -10)
t.pendown()
t.color("green")
t.begin_fill()
t.circle(20)
t.end_fill()
turtle.done()
👨🏫 给家长的Tips
这个花朵项目使用了嵌套循环:
- 外层循环:画6个花瓣
- 内层循环:每个花瓣由36条短线段组成
- 这是循环的高级应用,让孩子看到循环的威力
- 可以让孩子修改参数(如花瓣数量、颜色),观察变化
练习4:创意画图
用循环发挥你的创意!
想法:
- 用循环画一排五角星(10个,位置不同)
- 用循环画同心圆(10个圆,半径逐渐增大)
- 用循环画一个“图案生成器“(旋转对称图形)
示例:旋转的五角星
import turtle
t = turtle.Turtle()
t.speed(0)
# 画12个旋转的五角星
for i in range(12):
t.pencolor("gold")
t.begin_fill()
for j in range(5):
t.forward(100)
t.right(144)
t.end_fill()
t.right(30) # 旋转30度(360 ÷ 12 = 30)
turtle.done()
总结:循环的威力
通过对比第6章和现在的代码,我们发现:
| 图形 | 第6章(顺序语句) | 现在(循环) | 减少行数 |
|---|---|---|---|
| 正方形 | 8行 | 3行 | 减少5行 |
| 五边形 | 11行 | 3行 | 减少8行 |
| 五角星 | 11行 | 3行 | 减少8行 |
| 花朵 | 不现实 | 15行 | 不可想象 |
循环的优势:
- 代码更短:从几十行减少到几行
- 更易修改:想画正12边形?只改一个数字
- 更易阅读:代码意图更清晰
- 减少错误:不用重复写相同的代码
👨🏫 给家长的Tips
这个对比非常重要!
- 让孩子真切感受到循环的价值
- 回顾第6章时留下的“伏笔“,现在终于“解密“了
- 告诉孩子:“这就是为什么我们要学循环——让代码更简洁、更强大”
- 鼓励孩子用循环改写之前的所有画图代码
变量的作用域
在循环中定义的变量,在循环外面可以使用吗?
示例:循环变量的作用域
# 循环变量的作用域
for i in range(1, 6):
print(f"循环内:i = {i}")
print(f"循环外:i = {i}") # 可以访问i!
# 但是,如果循环一次都没执行呢?
for j in range(0): # range(0)是空的
print(f"循环内:j = {j}")
# print(f"循环外:j = {j}") # 错误!j不存在
输出结果:
循环内:i = 1
循环内:i = 2
循环内:i = 3
循环内:i = 4
循环内:i = 5
循环外:i = 5
给家长的小贴士:
- Python中,for循环的变量在循环外仍然可以访问
- 但是,如果循环一次都没执行,变量就不存在
- 建议:在循环外定义好所有需要的变量
- 这样代码更清晰,不容易出错
循环和分支互相嵌套
示例:求和或求乘积
题目:要求用户输入一个正整数n,然后问用户计算求和还是求乘积。如果用户输入求和,则输出1+2+…+n的结果;用户输入求乘积,则输出1×2×…×n的结果。
👉 点击查看答案
# 求和或求乘积
n = int(input("请输入一个正整数n:"))
choice = input("请选择计算方式(求和/求乘积):")
if choice == "求和":
# 计算求和
total = 0
for i in range(1, n + 1):
total = total + i
print(f"1+2+...+{n} = {total}")
elif choice == "求乘积":
# 计算求乘积
product = 1
for i in range(1, n + 1):
product = product * i
print(f"1×2×...×{n} = {product}")
else:
print("Error!!! 输入不正确")
运行示例:
请输入一个正整数n:5
请选择计算方式(求和/求乘积):求和
1+2+...+5 = 15
请输入一个正整数n:5
请选择计算方式(求和/求乘积):求乘积
1×2×...×5 = 120
常见错误和调试
错误1:忘记更新循环变量
# 错误:死循环
count = 0
while count < 5:
print(count)
# 忘记了 count = count + 1
# 正确
count = 0
while count < 5:
print(count)
count = count + 1 # 更新循环变量!
错误2:循环条件错误
# 错误:永远不会执行
count = 5
while count > 10: # 5 > 10是False
print(count)
# 正确
count = 5
while count < 10: # 5 < 10是True
print(count)
count = count + 1
错误3:off-by-one错误
# 常见错误:想打印1到10,但只打印到9
for i in range(1, 10): # 错误!range(1, 10)是1到9
print(i)
# 正确
for i in range(1, 11): # 正确!range(1, 11)是1到10
print(i)
错误4:缩进错误
# 错误:缩进不一致
for i in range(5):
print(i) # 2个空格
print(i * 2) # 4个空格
# 正确:缩进一致
for i in range(5):
print(i)
print(i * 2)
调试技巧
- 使用print语句:
for i in range(1, 6):
print(f"调试:i = {i}") # 调试信息
total = total + i
print(f"调试:total = {total}") # 调试信息
-
画表格追踪变量: | 循环次数 | i | total | |———|—|—––| | 第1次 | 1 | 1 | | 第2次 | 2 | 3 | | 第3次 | 3 | 6 |
-
简化问题:
- 先用小的数字测试(比如1到5,而不是1到100)
- 确认逻辑正确后再扩大范围
-
检查边界条件:
- 0会怎样?
- 1会怎样?
- 最大值会怎样?
给家长的小贴士:
- 教孩子学会看错误信息
- 鼓励孩子用print调试
- 建议先在纸上画出执行过程
- 强调“从小到大“测试策略
章节小结
我们学到了什么
- 循环的概念:重复执行某些操作
- while循环:条件循环,适合不知道循环次数的情况
- for循环:计数循环,适合知道循环次数的情况
- range()函数:生成数字序列
- break和continue:控制循环的执行
- 循环嵌套:循环中的循环
- 常见模式:计数器、累加器、累乘器、最大值查找
重要语法回顾
| 循环类型 | 语法 | 用途 |
|---|---|---|
| while | while 条件: | 条件循环 |
| for | for i in range(): | 计数循环 |
| break | break | 跳出循环 |
| continue | continue | 跳过本次 |
循环的三个要素
- 初始值:循环变量的起点
- 条件:判断是否继续循环
- 更新:循环变量如何变化
编程技巧
- 避免死循环:记得更新循环变量
- 注意边界:range(1, 5)是1到4,不包括5
- 缩进正确:循环体要统一缩进
- 简化测试:先用小数字测试,确认逻辑后再扩大
- 调试方法:用print输出中间结果
下一步
在下一章(第9章),我们将学习流程图,用图形化的方式表示程序的执行流程。流程图能帮助我们更好地理解程序的逻辑!
挑战练习
-
必做:
- 用for循环计算1到1000的和
- 打印所有三位数中,个位、十位、百位都相同的数字(如111, 222, 333)
- 用while循环实现:输入密码,直到输入正确为止
-
选做:
- 打印“斐波那契数列“的前20项(1, 1, 2, 3, 5, 8, 13, …)
- 计算阶乘:n! = 1×2×3×…×n
- 打印“杨辉三角“的前10行
-
挑战:
- 用循环实现“九九乘法表“的倒三角版本
- 找出所有“完全数“:一个数等于它的所有真因数之和(如6=1+2+3)
- 实现“猜数字“游戏,并在猜测次数上设置难度级别
-
综合项目:
- 写一个简单的计算器,可以循环计算,直到用户选择退出
- 写一个成绩管理系统,可以录入、查询、统计成绩
- 用Turtle库和循环,画一个螺旋图形
加油!你已经掌握了让程序重复工作的能力!🎉
流程图
引言
在前面的章节中,我们学习了三种基本的程序控制结构:
- 顺序语句(第6章):程序按从上到下的顺序执行
- 条件语句(第7章):根据条件选择执行不同的代码
- 循环语句(第8章):重复执行某些代码
这些结构让程序能够处理各种复杂的情况。但是,当程序变得比较复杂时,仅靠阅读代码来理解逻辑可能会有些困难。
有没有一种方法,可以用图形的方式来表示程序的执行流程呢?
答案是:有!这就是流程图。
流程图(Flowchart)是用图形符号来表示程序执行流程的图示方法。它能帮助我们:
- 更清晰地理解程序的逻辑
- 在编写代码之前设计程序
- 与他人交流程序的设计思路
- 调试和优化程序
这一章,我们将学习:
- 流程图的基本符号
- 如何用流程图表示顺序、条件和循环
- 如何从流程图写出代码
- 如何从代码画出流程图
- 什么是算法 💡
- 用流程图表示计算机的工作过程 💡
💡 什么是算法?
在学流程图之前,我们先了解一个重要的概念——算法(Algorithm)。
算法就是解决问题的步骤。
生活中的例子 🍳 比如“做番茄炒蛋“的算法:
- 准备食材:番茄2个、鸡蛋3个
- 处理食材:番茄切块、鸡蛋打散
- 炒鸡蛋:热锅加油,倒入鸡蛋炒熟
- 炒番茄:加入番茄翻炒
- 调味:加盐,翻炒均匀
- 装盘:盛到盘子里
**这就是一个算法!**它告诉我们:
- 从哪里开始(准备食材)
- 每一步做什么(炒鸡蛋、炒番茄)
- 什么时候结束(装盘)
编程中的算法 💻 我们前面学过的程序也是算法:
# 计算1到n的和(算法)
n = int(input("请输入n:")) # 步骤1:输入n
total = 0 # 步骤2:初始化总和
i = 1 # 步骤3:初始化计数器
while i <= n: # 步骤4:循环累加
total = total + i
i = i + 1
print(total) # 步骤5:输出结果
算法的三个特征:
- 有输入:比如上面的程序输入n
- 有步骤:一步一步执行(初始化→循环→输出)
- 有输出:最后输出总和
为什么流程图和算法是一回事? 🤔
- 算法:用文字描述解决问题的步骤
- 流程图:用图形描述解决问题的步骤
它们描述的是同一件事,只是表达方式不同!
👨🏫 给家长的Tips
知识点补充(针对家长):
- 算法是计算机科学的核心概念
- 一个算法可以用多种方式表示:
- 自然语言(文字描述)
- 流程图(图形表示)
- 伪代码(介于自然语言和代码之间)
- 编程语言(Python、C++等)
- 流程图是算法的一种“可视化“表示
如何给孩子讲解:
- 用“做菜的菜谱“类比算法
- 菜谱可以用文字写,也可以画成图示
- 流程图就是程序的“图示版菜谱“
- 强调:算法是“想法“,流程图是“画出来的想法“
💡 用流程图表示计算机的工作过程
在第6章,我们学习了CPU是如何执行指令的:
- 取指令→译码→执行→重复
现在我们用流程图来表示CPU的工作过程:
CPU的指令执行循环
flowchart TD
Start([开始]) --> Init[PC = 0<br/>PC=程序计数器]
Init --> Fetch{是否还有指令?}
Fetch -->|是| FetchStep[从内存读取指令]
FetchStep --> Decode[译码:理解指令含义]
Decode --> Execute[执行指令]
Execute --> UpdatePC[PC = PC + 1<br/>指向下一条指令]
UpdatePC --> Fetch
Fetch -->|否| End([结束])
流程图解释:
- 开始:启动计算机
- 初始化:PC(程序计数器)设为0,指向第一条指令
- 判断:是否还有指令要执行?
- 取指:从内存读取当前指令
- 译码:CPU理解这条指令要做什么
- 执行:CPU执行指令(加法、减法、判断等)
- 更新PC:PC加1,指向下一条指令
- 返回:回到第3步,继续执行
- 结束:程序执行完毕
这正好解释了为什么计算机这么快! ⚡
- 这个循环每秒可以执行几十亿次!
- 每次循环(取指→译码→执行)只需要纳秒(1纳秒=0.000000001秒)
👨🏫 给家长的Tips
知识点补充(针对家长):
- CPU的工作过程就是一个“无限循环“
- 术语叫“指令循环“(Instruction Cycle)
- 每个时钟周期执行一次循环
- 3GHz CPU = 每秒30亿次指令循环
如何给孩子讲解:
- 用“传送带“类比:
- CPU就像一个工人
- 指令就像传送带上的零件
- 工人不断拿起零件(取指)
- 理解零件怎么用(译码)
- 处理零件(执行)
- 然后拿起下一个零件…
- 强调:这个循环比人类快亿万倍
数学小计算 🧮:
- 如果CPU主频是3GHz(每秒30亿个周期)
- 执行1亿条简单指令需要:100,000,000 ÷ 3,000,000,000 = 0.03秒!
- 这就是为什么计算机适合做重复性工作!
程序执行流程图
让我们用一个简单的程序来看CPU是如何执行的:
代码:
# 计算2的3次方
result = 1
result = result * 2 # 第1次乘法
result = result * 2 # 第2次乘法
result = result * 2 # 第3次乘法
print(result)
CPU执行过程流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────────┐
│ PC = 0 (指向第1行)│
└────┬─────────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱PC<4? ╲───┐ ← 代码共4行
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌───────┐ ╲ │
│执行指令│ ╲ │
│PC指向的│ ↓ │
└───┬───┘ ┌─────┘
│ │
↓ │
┌──────────┐│
│ PC = PC+1││ → 指向下一条指令
└─────┬────┘│
│ │
└─────┘
↓
┌─────────────────╲
╱ 输出: result ╲
╱────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
执行过程详解:
- PC=0:执行第1行
result = 1,然后PC变为1 - PC=1:执行第2行
result = result * 2,然后PC变为2 - PC=2:执行第3行
result = result * 2,然后PC变为3 - PC=3:执行第4行
result = result * 2,然后PC变为4 - PC=4:PC>=4,退出循环,执行下一条指令(print)
- 输出:打印result的值(8)
👨🏫 给家长的Tips
重要概念:
- 程序计数器(PC):CPU中的“书签“,记录执行到哪一行
- PC从0开始,每执行一行就+1
- 当PC超出程序行数时,程序结束
- 这就是“顺序执行“的硬件原理!
如何给孩子讲解:
- 用“看书“类比:
- PC就像你的“手指“,指到哪行就读哪行
- 读完后,手指移到下一行(PC+1)
- 读到最后一页,书就结束了
- 强调:CPU每秒可以做这样的“翻页“几十亿次!
流程图与算法的关系
现在我们理解了:
- 算法 = 解决问题的步骤(文字描述)
- 流程图 = 算法的图形表示
- 程序 = 算法的代码实现
- CPU执行 = 按照流程图的步骤执行
四种表示方式的对比:
| 表示方式 | 例子 | 优点 | 缺点 |
|---|---|---|---|
| 算法(文字) | “1.输入n 2.初始化sum=0 3.循环累加 4.输出” | 易理解,不要求技术 | 不够精确,有歧义 |
| 流程图(图形) | 用符号和箭头表示 | 直观清晰,逻辑一目了然 | 复杂程序图画起来麻烦 |
| 程序(代码) | for i in range(n+1): sum+=i | 精确,计算机能执行 | 需要学习编程语法 |
| CPU执行 | 取指→译码→执行的循环 | 计算机真正的工作方式 | 过于底层,不适合设计算法 |
👨🏫 给家长的Tips
教学建议:
- 告诉孩子:程序员写代码时,通常的流程是:
- 先想算法(用文字描述思路)
- 画流程图(把思路图形化)
- 写代码(把流程图翻译成Python)
- 这就是为什么我们要学流程图——它是“想法“和“代码“之间的桥梁!
- 鼓励孩子养成“先画流程图,再写代码“的习惯
流程图的基本符号
流程图使用不同的图形符号来表示不同的操作。让我们先认识这些符号。
1. 开始/结束符号(圆角矩形)
flowchart TD
Start([开始])
End([结束])
作用:表示程序的开始或结束
特点:
- 通常使用圆角矩形或椭圆形
- “开始“符号只有一个向外的箭头
- “结束“符号只有一个向内的箭头
2. 输入/输出符号(平行四边形)
flowchart TD
Input[/输入n/]
Output[/输出结果/]
作用:表示输入(input)或输出(print)操作
示例:
n = int(input("请输入n:"))print("结果是:", sum)
3. 处理符号(矩形)
flowchart TD
Process[sum = 0]
作用:表示计算、赋值等处理操作
示例:
sum = sum + ii = i + 1area = length * width
4. 判断符号(菱形)
flowchart TD
Decision{i <= n?}
Decision-->|是| TruePath
Decision-->|否| FalsePath
作用:表示条件判断
特点:
- 有两个出口:True(是)和False(否)
- 用于if语句和循环的条件
5. 流程线(箭头)
flowchart LR
A[开始] --> B[下一步]
作用:表示程序的执行方向
符号总结表
| 符号 | 名称 | 作用 | Python示例 |
|---|---|---|---|
| ⬭ | 开始/结束 | 程序的开始或结束 | - |
| ╱ ╲ | 输入/输出 | input()或print() | input(), print() |
| ┌─┐ | 处理 | 计算、赋值 | sum = 0, i = i + 1 |
| ◇ | 判断 | 条件判断 | if, while, for |
| ↓ | 流程线 | 执行方向 | - |
给家长的小贴士:
- 建议让孩子把这些符号画在卡片上
- 可以玩“配对游戏“:将符号与对应的代码配对
- 强调每个符号的形状和用途的关联
- 菱形有尖角,像路口需要选择方向
- 平行四边形倾斜,像数据进进出出
用流程图表示顺序语句
顺序语句是最简单的程序结构,按照从上到下的顺序执行。
示例1:计算长方形面积
代码:
# 计算长方形面积
length = 5
width = 3
area = length * width
print(area)
流程图:
flowchart TD
Start([开始]) --> A[length = 5]
A --> B[width = 3]
B --> C[area = length * width]
C --> D[/输出: area/]
D --> End([结束])
要点:
- 箭头始终向下,表示顺序执行
- 每个步骤按顺序完成后再进行下一个
- 没有分支,没有循环
示例2:带输入的顺序程序
代码:
# 输入长和宽,计算面积
length = int(input("请输入长度:"))
width = int(input("请输入宽度:"))
area = length * width
print(f"面积是:{area}")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: length ╲
╱─────────────────────╲
↓
╱─────────────────╲
╱ 输入: width ╲
╱─────────────────────╲
↓
┌──────────────────┐
│ area = l * w │
└────┬─────────────┘
↓
╱─────────────────╲
╱ 输出: area ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
给家长的小贴士:
- 顺序语句的流程图最简单:一条直线向下
- 可以让孩子“用手指走一遍“流程图
- 强调:一步接一步,不能跳跃
- 可以用生活中的例子类比:做菜的步骤、早晨起床的流程
练习1:画出温度转换程序的流程图
题目:画流程图表示下面的程序。
# 温度转换:摄氏度转华氏度
celsius = float(input("请输入摄氏度:"))
fahrenheit = celsius * 9 / 5 + 32
print(f"华氏度是:{fahrenheit}")
👉 点击查看答案
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱────────────────────╲
╱ 输入: celsius ╲
╱────────────────────────╲
↓
┌──────────────────────────┐
│ f = c * 9 / 5 + 32 │
└────┬─────────────────────┘
↓
╱────────────────────╲
╱ 输出: fahrenheit ╲
╱────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
用流程图表示条件语句
条件语句需要根据条件判断选择执行不同的代码分支,在流程图中用菱形表示。
示例1:简单的if语句
代码:
# 判断数字是否为正数
num = int(input("请输入一个数字:"))
if num > 0:
print("这是正数")
print("程序结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: num ╲
╱─────────────────────╲
↓
num > 0?
╱ ╲
是 否
╱ ╲
↓ ╲
┌────────┐ ╲
│输出"正数"│ ╲
└────┬────┘ ╲
↓ ╲
└────┬────┘
↓
╱─────────────────╲
╱ 输出"程序结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- 菱形表示判断条件
- “是”(True)分支和“否“(False)分支
- 两个分支最终汇合到一起
示例2:if-else语句
代码:
# 判断奇偶数
num = int(input("请输入一个数字:"))
if num % 2 == 0:
print("这是偶数")
else:
print("这是奇数")
print("程序结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: num ╲
╱─────────────────────╲
↓
num % 2 == 0?
╱ ╲
是 否
╱ ╲
↓ ↓
┌────────┐ ┌────────┐
│输出"偶数"│ │输出"奇数"│
└────┬────┘ └────┬───┘
└────┬────┘
↓
╱─────────────────╲
╱ 输出"程序结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- if-else的两个分支是对称的
- 两个分支都会执行完后汇合
示例3:if-elif-else语句
代码:
# 成绩等级判断
score = int(input("请输入成绩:"))
if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")
print("程序结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: score ╲
╱─────────────────────╲
↓
score >= 90?
╱ ╲
是 否
╱ ╲
↓ ↓
┌────────┐ score >= 80?
│输出"优秀"│ ╱ ╲
└────┬───┘ 是 否
└─┬────┘ ╲
↓ ╲
┌────────┐ score >= 60?
│输出"良好"│ ╱ ╲
└────┬───┘ 是 否
└─┬────┘ ╲
↓ ╲
┌────────┐ ┌────────┐
│输出"及格"│ │输出"不及格"│
└────┬───┘ └────┬───┘
└────┬────┘
↓
╱─────────────────╲
╱ 输出"程序结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- 多个条件依次判断
- 一旦某个条件为True,执行对应分支后不再判断其他条件
- 所有条件都不满足时,执行else分支
给家长的小贴士:
- 条件语句的流程图像一棵“树“
- 强调:菱形有两个出口
- 让孩子用手指沿着不同的路径走一遍
- 可以画在纸上,用不同颜色的笔标记不同的路径
- 对于if-elif-else,强调“一旦满足就不再判断“
练习2:画出绝对值程序的流程图
题目:画流程图表示下面的程序。
# 计算绝对值
num = int(input("请输入一个数字:"))
if num < 0:
num = -num
print(f"绝对值是:{num}")
👉 点击查看答案
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: num ╲
╱─────────────────────╲
↓
num < 0?
╱ ╲
是 否
╱ ╲
↓ ╲
┌──────────┐ ╲
│ num = -num│ ╲
└────┬─────┘ ╲
└────┬────┘
↓
╱────────────────────╲
╱ 输出: num (绝对值) ╲
╱────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
用流程图表示循环语句
循环语句的流程图与条件语句类似,也用菱形表示判断,但有一个重要的区别:循环有返回箭头,形成回路。
示例1:while循环
代码:
# 打印1到5
count = 1
while count <= 5:
print(count)
count = count + 1
print("循环结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────┐
│count = 1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱count<=5?╲───────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌────────┐ ╲ │
│输出count│ ↓ │
└───┬────┘ ┌─────────┐
↓ │count = c │
│ │ + 1 │
│ └────┬────┘
│ │
└─────────────┘
↓
╱─────────────────╲
╱ 输出"循环结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- while循环的三个要素:
- 初始值:
count = 1 - 条件:
count <= 5 - 更新:
count = count + 1
- 初始值:
- 当条件为True时,执行循环体,然后返回再次判断条件
- 当条件为False时,退出循环
示例2:for循环(等价while)
代码:
# 用for循环打印1到5
for count in range(1, 6):
print(count)
print("循环结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────┐
│count = range(1,6)│
└────┬─────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱count<=5?╲───────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌────────┐ ╲ │
│输出count│ ↓ │
└───┬────┘ ┌──────────┐
↓ │count自动+1│
│ └────┬─────┘
│ │
└─────────────┘
↓
╱─────────────────╲
╱ 输出"循环结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- for循环的菱形判断条件来自range()
- for循环会自动更新循环变量
- 流程图与while类似,但更新是自动的
示例3:带break的循环
代码:
# 找第一个能被7整除的数
for i in range(1, 100):
if i % 7 == 0:
print(f"找到了:{i}")
break
print("程序结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────┐
│ i = range │
│ (1, 100) │
└────┬─────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱i < 100? ╲─────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
i % 7 == 0? │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌────────┐ ╲ │
│输出: i │ ╲ │
│ break│────→╲──┘ ←─ break直接跳出
└────────┘ ╲ 循环
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- break会立即跳出循环
- 不再返回判断条件
- 直接执行循环后的语句
示例4:带continue的循环
代码:
# 打印1到10中的奇数
for i in range(1, 11):
if i % 2 == 0:
continue # 跳过偶数
print(i)
print("程序结束")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────┐
│ i = range │
│ (1, 11) │
└────┬─────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱i < 11? ╲──────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
i % 2 == 0? │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ↓ │
│continue┐ ┌──────┤
│(跳过) │ │输出 i│
└────────┘ └──┬───┘
↑ │
│ │
└──────────┘
↓
╱─────────────────╲
╱ 输出"程序结束" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- continue跳过本次循环的剩余代码
- 立即返回判断条件,进入下一次循环
- 不像break那样退出循环
给家长的小贴士:
- 循环流程图的关键是“回路“
- 强调:条件满足时“返回“再次判断
- 可以用“跑道“类比:跑完一圈回到起点
- break是“离开跑道“,continue是“重跑一圈“
- 让孩子用手指沿着箭头走,体验循环
循环vs条件语句:流程图的区别
| 特征 | 条件语句 | 循环语句 |
|---|---|---|
| 菱形判断 | 有 | 有 |
| 两个分支 | 是/否 | 是/否 |
| 返回箭头 | 无 | 有 |
| 执行次数 | 一次 | 可能多次 |
| 目的 | 选择分支 | 重复执行 |
总结:
- 条件语句:菱形→分支→汇合→向下(无返回)
- 循环语句:菱形→分支→返回(有返回)
练习3:画出累加程序的流程图
题目:画流程图表示下面的程序。
# 计算1到n的和
n = int(input("请输入n:"))
total = 0
i = 1
while i <= n:
total = total + i
i = i + 1
print(f"1到{n}的和是:{total}")
👉 点击查看答案
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: n ╲
╱─────────────────────╲
↓
┌──────────┐
│ total=0 │
│ i=1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ i <= n?╲──────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌────────────┐ ╲ │
│total=total+i│ ↓ │
│ i = i+1 │ ┌──┘
└─────┬──────┘
│
└───────────┘
↓
╱────────────────────╲
╱ 输出: total (和) ╲
╱────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
综合示例:嵌套结构的流程图
让我们看一个更复杂的例子,包含条件语句和循环语句的嵌套。
示例:计算能被3整除的数字之和
代码:
# 计算1到n中能被3整除的数字之和
n = int(input("请输入n:"))
sum = 0
i = 1
while i <= n:
if i % 3 == 0:
sum = sum + i
i = i + 1
print(f"1到{n}中能被3整除的数字之和是:{sum}")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: n ╲
╱─────────────────────╲
↓
┌──────────┐
│ sum = 0 │
│ i = 1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ i <= n?╲───────────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
i % 3 == 0? │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌────────┐ ╲ │
│sum=sum+i│ ╲ │
└────┬───┘ ╲ │
└───┬─────╲ │
↓ ╲ │
┌─────────┐ ╲ │
│ i = i+1 │ ↓ │
└────┬────┘ ┌────┘
│
└───────────┘
↓
╱───────────────────────╲
╱ 输出: sum ╲
╱───────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
要点:
- 外层循环:while(i <= n)
- 内层条件:if(i % 3 == 0)
- 内层条件在循环内部
- 不管是否满足内层条件,都要执行
i = i + 1
给家长的小贴士:
- 嵌套结构的流程图可以分层理解
- 先看外层结构(while循环)
- 再看内层结构(if条件)
- 让孩子用不同颜色的笔标记不同的层级
- 强调:缩进在代码中对应嵌套在流程图中
从流程图写代码
学会了画流程图,现在我们来学习如何从流程图写出代码。
示例:求最大值
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: a, b, c ╲
╱─────────────────────╲
↓
a >= b?
╱ ╲
是 否
╱ ╲
↓ ↓
max = a max = b
└────┬────┘
↓
max >= c?
╱ ╲
是 否
╱ ╲
↓ ↓
(不变) max = c
└────┬────┘
↓
╱─────────────────╲
╱ 输出: max ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
步骤:
- 开始:程序开始
- 输入:
a = int(input()),b = int(input()),c = int(input()) - 第一个判断(a >= b):
if a >= b: max = a else: max = b - 第二个判断(max >= c):
if max >= c: # max不变 pass else: max = c - 输出:
print(max)
完整代码:
# 求三个数的最大值
a = int(input("请输入第一个数:"))
b = int(input("请输入第二个数:"))
c = int(input("请输入第三个数:"))
# 第一步:比较a和b
if a >= b:
max = a
else:
max = b
# 第二步:比较max和c
if max >= c:
# max已经是最大的,不需要做任何事
pass
else:
max = c
print(f"最大的数是:{max}")
或者更简洁的写法:
# 求三个数的最大值(简洁版)
a = int(input("请输入第一个数:"))
b = int(input("请输入第二个数:"))
c = int(input("请输入第三个数:"))
max = a # 假设a最大
if b > max: # 如果b更大
max = b
if c > max: # 如果c更大
max = c
print(f"最大的数是:{max}")
给家长的小贴士:
- 从流程图写代码的关键步骤:
- 识别符号类型(输入、输出、处理、判断)
- 按照箭头方向顺序转换
- 菱形转换为if语句
- 回路转换为while或for循环
- 鼓励孩子先写“直译版“,再优化
- 强调:流程图和代码要一一对应
练习4:从流程图写代码(累加)
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: n ╲
╱─────────────────────╲
↓
┌──────────┐
│ sum = 0 │
│ i = 1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ i <= n?╲──────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌──────────┐ ╲ │
│sum = sum+i│ ↓ │
│ i = i+1 │ ┌──┘
└─────┬────┘
│
└───────────┘
↓
╱─────────────────╲
╱ 输出: sum ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
👉 点击查看答案
代码:
# 计算1到n的和
n = int(input("请输入n:"))
sum = 0
i = 1
while i <= n:
sum = sum + i
i = i + 1
print(f"1到{n}的和是:{sum}")
从代码画流程图
现在我们反过来,从代码画流程图。
示例:水仙花数
代码:
# 打印水仙花数
print("三位数的水仙花数:")
for num in range(100, 1000):
# 分解百位、十位、个位
hundreds = num // 100
tens = (num // 10) % 10
ones = num % 10
# 计算各位数字的立方和
sum_of_cubes = hundreds ** 3 + tens ** 3 + ones ** 3
# 判断是否为水仙花数
if sum_of_cubes == num:
print(num)
print("查找完成!")
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────────╲
╱ 输出:"三位数的水仙花数"╲
╱─────────────────────────╲
↓
┌──────────────────┐
│ num = range(100,│
│ 1000) │
└────┬─────────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱num<1000?╲────────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
┌─────────────┐ ╲ │
│h = num//100│ ↓ │
│t = (num//10)%10│ ┌──┘
│o = num % 10 │ │
└──────┬──────┘ │
↓ │
┌──────────────────┐
│sum = h³ + t³ + o³│
└──────┬───────────┘
↓
sum == num?
╱ ╲
是 否
╱ ╲
↓ ╲
┌────────┐ ╲
│输出num │ ╲
└────────┘ ╲
└────┬──────┘
↓
╱─────────────────╲
╱ 输出"查找完成!" ╲
╱─────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
练习5:画出猜数字游戏的流程图
题目:画流程图表示下面的猜数字游戏程序。
# 猜数字游戏
import random
target = random.randint(1, 100)
print("我想了一个1到100之间的数字,你来猜!")
guess = int(input("请输入你的猜测:"))
while guess != target:
if guess < target:
print("太小了!")
else:
print("太大了!")
guess = int(input("请再次输入你的猜测:"))
print("恭喜你!猜对了!")
👉 点击查看答案
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────────┐
│生成随机数target │
│ (1到100) │
└────┬─────────────┘
↓
╱───────────────────────╲
╱ 输出:"我想了一个数字..."╲
╱───────────────────────────╲
↓
╱─────────────────╲
╱ 输入: guess ╲
╱─────────────────────╲
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱guess!=target?╲─────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
guess<target? │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ↓ │
┌─────────┐ ┌─────────┐ │
│输出"太小"│ │输出"太大"│ │
└────┬────┘ └────┬────┘ │
└────┬────┘ │
↓ │
╱─────────────────╲ │
╱ 输入: guess ╲ │
╱─────────────────────╲ │
│ │
└──────────────┘
↓
╱─────────────────────╲
╱ 输出"恭喜你!猜对了!" ╲
╱────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
流程图练习:反向推理
现在让我们做一些有趣的练习:根据流程图填空,或者根据不完整的流程图写出完整的程序。
练习6:补全流程图
题目:下面的流程图中有一些空白,请根据程序逻辑补全。
程序:计算1到n中所有偶数的和
n = int(input("请输入n:"))
sum = 0
i = 1
while i <= n:
if i % 2 == 0: # 判断是否为偶数
sum = sum + i
i = i + 1
print(f"1到{n}中偶数的和是:{sum}")
不完整的流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: _____ ╲ ← 空白1
╱─────────────────────╲
↓
┌──────────┐
│ sum = 0 │
│ i = ___ │ ← 空白2
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ i <= n? ╲──────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
_________? │ ← 空白3
╱ ╲ ╲
是 否 ╲
╱ ╲ ╲
↓ ╲ ╲
┌────────┐ ╲ ╲
│sum = + i│ ↓ ╲
└────┬───┘ ┌──────┐ ╲
└───────┤i = i+1│ ╲
└──────┘ ╲
└───────┘
↓
╱────────────────────╲
╱ 输出: sum (偶数和) ╲
╱───────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
👉 点击查看答案
答案:
- 空白1:
n - 空白2:
1 - 空白3:
i % 2 == 0?
完整流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: n ╲
╱─────────────────────╲
↓
┌──────────┐
│ sum = 0 │
│ i = 1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ i <= n? ╲──────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
i%2==0? ╲
╱ ╲ ╲
是 否 ╲
╱ ╲ ╲
↓ ╲ ╲
┌────────┐ ╲ ╲
│sum=sum+i│ ↓ ╲
└────┬───┘ ┌──────┐ ╲
└───────┤i = i+1│ ╲
└──────┘ ╲
└───────┘
↓
╱────────────────────╲
╱ 输出: sum (偶数和) ╲
╱───────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
练习7:根据流程图写程序
题目:根据下面的流程图写出完整的程序。
流程图:
┌─────────┐
│ 开始 │
└────┬────┘
↓
╱─────────────────╲
╱ 输入: n ╲
╱─────────────────────╲
↓
┌──────────┐
│ count = 0│
│ num = 1 │
└────┬─────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱ num <= n?╲─────┐
╱ (判断) ╲ │
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲ │
n % num == 0? ╲
╱ ╲ ╲
是 否 ╲
╱ ╲ ╲
↓ ╲ ╲
┌─────────┐ ╲ ╲
│count=c+1│ ╲ ╲
└────┬────┘ ╲ ╲
└───┬───────╲ ╲
↓ ╲ ╲
┌─────────┐ ╲ ╲
│num=num+1│ ↓ ╲
└────┬────┘ ┌───┘
│
└───────────┘
↓
╱────────────────────╲
╱ 输出: count ╲
╱────────────────────────╲
↓
┌─────────┐
│ 结束 │
└─────────┘
👉 点击查看答案
分析:
- 这个程序计算:1到n中有多少个数能整除n
- 也就是:n的因数个数
- 例如:n = 6,因数有1, 2, 3, 6,共4个
代码:
# 计算n的因数个数
n = int(input("请输入n:"))
count = 0
num = 1
while num <= n:
if n % num == 0:
count = count + 1
num = num + 1
print(f"{n}的因数个数是:{count}")
运行示例:
请输入n:6
6的因数个数是:4
解释:
- 6的因数:1, 2, 3, 6
- 6 % 1 == 0 → count = 1
- 6 % 2 == 0 → count = 2
- 6 % 3 == 0 → count = 3
- 6 % 4 != 0 → count不变
- 6 % 5 != 0 → count不变
- 6 % 6 == 0 → count = 4
for循环的特殊流程图
for循环的流程图有一个需要注意的地方:循环变量的自动更新。
示例:对比while和for的流程图
while版本:
i = 1
while i <= 5:
print(i)
i = i + 1 # 手动更新
for版本:
for i in range(1, 6):
print(i)
# 自动更新,不需要i = i + 1
对比流程图:
while流程图:
┌──────┐
│ i=1 │
└───┬──┘
↓
↑
╱ ╲
╱ ╲
╱i<=5?╲───┐
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲│
┌────┐ ↓
│输出i│ ┌──────┐
└─┬──┘ │ i=i+1│ ← 手动更新
│ └──┬───┘
└───────┘
for流程图:
┌─────────────┐
│ i = range │
│ (1, 6) │
└─────┬───────┘
↓
↑
╱ ╲
╱ ╲
╱i<=5?╲───┐
╱ ╲ │
是 否 │
╱ ╲ │
↓ ╲│
┌───┐ ↓
│输出i│ ┌─────────┐
└─┬─┘ │i自动+1 │ ← 自动更新
│ └────┬────┘
│ │
└──────────┘
给家长的小贴士:
- for循环的更新是“隐式“的(自动完成)
- 在流程图中,可以用虚线框表示自动操作
- 或者用注释说明:“自动更新”
- 强调:for循环更简洁,不容易忘记更新
流程图的实际应用
流程图不仅仅是学习工具,在实际编程中也非常有用。
应用1:设计程序
在写代码之前,先用流程图设计程序结构。
例子:设计一个登录验证程序
┌─────────┐
│ 开始 │
└────┬────┘
↓
┌──────────────────┐
│设置正确的用户名 │
│和密码 │
└────┬─────────────┘
↓
↑
╱ ╲
╱ ╲
╱ ╲
╱登录成功?╲────┐
╱ (判断) ╲ │
╱ ╲ │
否 是 │
╱ ╲ │
↓ ╲ │
╱──────────╲ ╲│
╱ 输入用户名 ╲ ↓
╱和密码 ╲┌─────┐
╱────────────╲│结束 │
└────┬────┘└─────┘
│
└───────────┘
根据流程图写代码:
# 登录验证
correct_username = "admin"
correct_password = "123456"
while True:
username = input("请输入用户名:")
password = input("请输入密码:")
if username == correct_username and password == correct_password:
print("登录成功!")
break
else:
print("用户名或密码错误,请重试!")
应用2:调试程序
当程序出现问题时,画出流程图帮助找出错误。
例子:调试一个有bug的程序
有bug的代码:
# 计算1到n的和(有bug)
n = 5
sum = 0
while i <= n: # 错误!i没有定义
sum = sum + i
i = i + 1 # 错误!i第一次使用时不存在
print(sum)
画流程图找问题:
┌──────┐
│ n=5 │
└───┬──┘
↓
┌──────┐
│sum=0 │
└───┬──┘
↓
↑
╱ ╲
╱ ╲
╱i<=n?╲ ← 问题:i没有初始值!
╱ ╲
是 否
╱ ╲
↓ ╲
... ↓
┌─────┐
│输出sum│
└─────┘
发现问题:循环变量i没有初始值!
修正:
# 修正后的代码
n = 5
sum = 0
i = 1 # 添加初始值
while i <= n:
sum = sum + i
i = i + 1
print(sum)
应用3:与他人交流
流程图是程序员之间交流的好工具,能让别人快速理解你的程序逻辑。
给家长的小贴士:
- 鼓励孩子在写复杂程序前先画流程图
- 可以用纸笔,或者用专门的流程图软件
- 流程图可以是“草图“,不需要太完美
- 重点是理清思路,而不是画得漂亮
常见流程图符号的ASCII表示
在文本中画流程图时,我们常用ASCII字符来表示图形符号:
| 符号 | ASCII表示 | 说明 |
|---|---|---|
| 开始/结束 | ┌─────┐ (圆角矩形) | 或用(开始)表示 |
| 输入/输出 | ╱ ╲ (平行四边形) | 倾斜的矩形 |
| 处理 | ┌─────┐ (矩形) | 普通矩形 |
| 判断 | ◇ 或 ╱ ╲ (菱形) | 有两个出口 |
| 流程线 | ↓ ↑ │ → | 箭头表示方向 |
章节小结
我们学到了什么
-
流程图的基本符号:
- 开始/结束:圆角矩形
- 输入/输出:平行四边形
- 处理:矩形
- 判断:菱形
- 流程线:箭头
-
用流程图表示程序结构:
- 顺序语句:箭头一直向下,无分支
- 条件语句:菱形判断,两个分支,无返回箭头
- 循环语句:菱形判断,有返回箭头形成回路
-
break和continue的流程图:
- break:跳出循环,不再返回
- continue:跳过本次,立即返回判断条件
-
流程图的应用:
- 设计程序
- 调试程序
- 与他人交流
重要概念对比
| 结构 | 流程图特征 | Python关键字 |
|---|---|---|
| 顺序 | 箭头向下,无分支 | - |
| 条件 | 菱形判断,无返回 | if, else, elif |
| 循环 | 菱形判断,有返回 | while, for |
| break | 箭头跳出循环 | break |
| continue | 箭头返回判断 | continue |
画流程图的步骤
-
从代码画流程图:
- 找出程序的开始和结束
- 识别输入和输出
- 找出所有的判断点
- 判断是条件还是循环(有无返回箭头)
- 用箭头连接各部分
-
从流程图写代码:
- 从开始到结束,依次转换符号
- 输入/输出符号 → input()/print()
- 处理符号 → 赋值语句
- 菱形判断 → if语句或循环
- 有返回箭头 → while/for循环
- 无返回箭头 → if语句
编程技巧
- 先设计后编码:复杂程序先画流程图
- 分层理解:嵌套结构分内外层理解
- 用不同颜色:不同层级用不同颜色标记
- 简化测试:用小数字测试流程图逻辑
- 工具辅助:可以用专门的流程图软件
下一步
在下一章(第10章),我们将学习列表(List),这是一种新的数据结构,可以存储多个数据。结合循环和列表,我们可以处理更复杂的数据!
挑战练习
-
必做:
- 画出“计算阶乘“程序的流程图(n! = 1×2×3×…×n)
- 画出“判断素数“程序的流程图
- 根据流程图写出“找最大值“的代码
-
选做:
- 画出“九九乘法表“程序的流程图
- 画出“斐波那契数列“程序的流程图
- 根据流程图写出“存钱问题“的代码
-
挑战:
- 设计一个流程图:用户输入5个数,找出最大值、最小值和平均值
- 画出完整的“猜数字游戏“流程图(包括次数限制)
- 用流程图设计一个简单的“学生成绩管理系统“
-
综合项目:
- 选择你之前写过的最复杂的程序,画出它的流程图
- 用流程图设计一个“文字冒险游戏“
- 尝试使用流程图软件(如draw.io)绘制专业的流程图
加油!你已经学会了用图形方式表示程序的逻辑!🎉
流程图是程序员的“地图“,它能帮你和他人更好地理解程序的运行逻辑。继续努力,成为一名优秀的程序员!💪
数据结构:List(列表)
引言
在前面的章节中,我们学习了三种基本的数据类型:
- 字符串(第3章):存储文字,比如“Hello“
- 数值(第4章):存储数字,比如42、3.14
- 布尔值(第5章):存储True或False
但是,如果我们想要存储多个数据呢?
比如:
- 存储一个班级所有学生的名字
- 存储一周7天的温度
- 存储购物清单上的所有商品
这时候,我们就需要一种新的数据类型:列表(List)。
列表(List)就像一个有顺序的容器,可以存放多个数据。它就像:
- 一串珍珠项链(每颗珍珠都是一个数据)
- 一列火车(每节车厢都是一个数据)
- 一个多层笔筒(每层都放一支笔)
这一章,我们将学习:
- 什么是列表
- 列表在计算机内存中是如何存储的
- 如何创建和使用列表
- 列表的基本操作(索引、切片、长度)
- 列表的常用方法(添加、删除、修改元素)
- 如何遍历列表
- 列表在数学中的应用(统计、排序)
- 元组(Tuple)简介
给家长的小贴士:
- 列表是Python中最常用的数据结构之一
- 可以用生活中的例子类比:购物清单、点名册、书架上的书
- 强调列表的“有序性“和“可变性“
- 本章会引入内存的概念,帮助孩子理解数据在计算机中的存储方式
- 鼓励孩子用列表解决实际问题(如记录朋友的名字)
列表在内存中的存储
在学习列表的操作之前,我们先来了解一个重要的问题:列表在计算机内存中是如何存储的?
什么是内存
还记得我们在第3章学过的“变量盒子“吗?每个变量都存储在计算机的内存(Memory)中。
内存就像一个巨大的储物柜,有很多个小格子(存储单元),每个格子都有一个编号,这个编号叫做地址。
内存示意图:
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ │ │ │ │ │ │ │ │ ...
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ (内存地址)
└────┴────┴────┴────┴────┴────┴────┴────┘
重要特点:
- 每个格子都有唯一的地址编号
- 地址从0开始,依次递增
- 我们可以把数据存储在这些格子里
列表的连续存储
列表在内存中是连续存放的,这意味着列表的元素占据内存中相邻的格子。
示例:创建一个列表 numbers = [10, 20, 30, 40]
内存示意图:
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ │ │ │ │ │ │ │ │
│ 10 │ 20 │ 30 │ 40 │ ... │ │ │ │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
↑ ↑ ↑
地址: 1000 1004 1008
索引: 0 1 2
列表的"索引"就是从开头数的第几个
(这里假设每个数字占4个格子)
要点:
- 列表的元素在内存中挨着存放
- 索引0对应第一个元素,索引1对应第二个元素…
- 内存地址是连续的(比如1000, 1004, 1008…)
为什么列表要连续存储?
优点1:快速访问
- 因为元素是连续存放的,计算机可以通过索引快速计算出元素的内存地址
- 公式:
元素地址 = 列表起始地址 + 索引 × 每个元素的大小 - 这就是为什么
list[2]能立刻找到第三个元素!
优点2:内存利用率高
- 连续存储不会留下“空洞“
- 就像在电影院里,大家挨着坐,不浪费座位
缺点:插入和删除较慢
- 如果要在中间插入一个元素,需要把后面的元素都往后移动
- 就像排队时,中间插一个人,后面的人都要往后挪一步
给家长的小贴士:
- 这个概念比较抽象,可以用“电影院座位“类比
- 连续存储就像大家一起看电影,座位挨着
- 索引就像是“第几排第几座“
- 小学阶段只需要理解“列表是连续存放的“这个概念即可
- 不需要深入理解内存地址计算等细节
列表占用的内存
问题:一个列表占用多少内存?
答案:这取决于两个因素:
- 元素的个数(列表长度)
- 每个元素的大小(数据类型)
示例:
# 创建不同类型的列表
numbers = [1, 2, 3, 4, 5] # 5个整数
names = ["小明", "小红", "小刚"] # 3个字符串
mixed = [1, "你好", 3.14, True] # 4个不同类型
内存占用估算(简化版):
- 整数(int):大约占用28个字节
- 小数(float):大约占用24个字节
- 字符串(str):占用字节数 = 字符数 + 一些额外开销
import sys # 导入sys模块,用于查看内存占用
# 查看一个列表占用的字节数
numbers = [1, 2, 3, 4, 5]
print(f"列表占用内存:{sys.getsizeof(numbers)}字节") # 约120字节
# 查看一个整数占用的字节数
print(f"一个整数占用内存:{sys.getsizeof(1)}字节") # 约28字节
小练习:估算列表 [10, 20, 30, 40, 50] 占用的内存
- 5个整数 × 28字节 = 140字节
- 再加上列表本身的额外开销(大约40字节)
- 总共约180字节
给家长的小贴士:
- sys.getsizeof()函数可以查看Python对象占用的内存
- 这是一个很好的机会让孩子理解“数据占用空间“的概念
- 可以让孩子比较不同列表的内存占用,理解“空间换时间“的权衡
- 强调:不同的计算机系统可能略有差异
认识列表
什么是列表
列表是一个有序的数据集合,可以存储多个数据。列表中的每个数据称为元素(element)。
示例:
# 创建一个列表,存储几种水果
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print(fruits) # 输出整个列表
运行结果:
['苹果', '香蕉', '橙子', '葡萄']
要点:
- 列表用方括号
[]表示 - 元素之间用逗号
,分隔 - 列表可以存储任意类型的数据
- 列表中的元素有顺序(从0开始编号)
创建列表的方法
方法1:直接创建列表
# 创建空列表
empty_list = []
# 创建有元素的列表
numbers = [1, 2, 3, 4, 5]
names = ["小明", "小红", "小刚"]
mixed = [1, "你好", 3.14, True] # 混合类型
方法2:使用list()函数
# 创建空列表
empty_list = list()
# 从字符串创建列表(字符串也是特殊的列表!)
chars = list("Hello") # ['H', 'e', 'l', 'l', 'o']
给家长的小贴士:
- 空列表
[]是创建列表的常用方式- 列表可以混合不同类型的数据(但实际编程中通常放同类型数据)
- 可以用
type()函数验证变量类型- 让孩子试试创建自己的列表(如喜欢的颜色、朋友的名字)
列表的特点
特点1:有序性
# 顺序不同,就是不同的列表
list1 = [1, 2, 3]
list2 = [3, 2, 1]
print(list1 == list2) # False(顺序不同,不相等)
特点2:可变性
# 列表可以修改
fruits = ["苹果", "香蕉", "橙子"]
fruits[0] = "草莓" # 修改第一个元素
print(fruits) # ['草莓', '香蕉', '橙子']
特点3:可重复
# 列表可以有重复元素
numbers = [1, 2, 2, 3, 3, 3]
print(numbers) # [1, 2, 2, 3, 3, 3]
练习1:创建你自己的列表
题目:创建一个列表,存储你最喜欢的5种食物。
👉 点击查看参考答案
# 创建食物列表
favorite_foods = ["披萨", "冰淇淋", "汉堡", "寿司", "巧克力"]
print("我最喜欢的食物:")
print(favorite_foods)
扩展:试试创建其他列表,如:
- 喜欢的颜色
- 想去的地方
- 擅长的运动
访问列表元素
索引(Index)
列表中的每个元素都有一个编号,叫做索引(index)。索引从0开始,不是从1开始!
索引示意图:
列表: ["苹果", "香蕉", "橙子", "葡萄"]
索引: 0 1 2 3
反向索引: -4 -3 -2 -1
内存地址示意:
内存: [地址1] [地址2] [地址3] [地址4]
["苹果"] ["香蕉"] ["橙子"] ["葡萄"]
索引: 0 1 2 3
示例1:正向索引(从0开始)
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print(fruits[0]) # 苹果(第一个元素)
print(fruits[1]) # 香蕉(第二个元素)
print(fruits[2]) # 橙子(第三个元素)
print(fruits[3]) # 葡萄(第四个元素)
示例2:反向索引(从-1开始)
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print(fruits[-1]) # 葡萄(倒数第一个)
print(fruits[-2]) # 橙子(倒数第二个)
print(fruits[-3]) # 香蕉(倒数第三个)
print(fruits[-4]) # 苹果(倒数第四个)
给家长的小贴士:
- 重要:Python的索引从0开始,这是初学者最容易犯错的地方!
- 用“楼层数“类比:地面是0层,1楼是第1层
- 反向索引从-1开始:-1是最后一个,-2是倒数第2个
- 可以画图帮助孩子理解索引和位置的关系
- 强调:索引是相对于列表开头的“偏移量“
索引与内存地址的关系
深入理解:索引实际上就是相对于列表起始位置的“偏移量“
假设列表从内存地址1000开始:
每个元素占用8个字节(假设)
索引0:地址 = 1000 + 0×8 = 1000
索引1:地址 = 1000 + 1×8 = 1008
索引2:地址 = 1000 + 2×8 = 1016
索引3:地址 = 1000 + 3×8 = 1024
这就是为什么通过索引可以快速找到元素!
代码示例:
# 查看列表的内存地址
import sys
numbers = [10, 20, 30, 40]
# 打印列表的内存地址(十六进制)
print(f"列表的内存地址:{id(numbers)}")
# 打印每个元素的索引和值
for i in range(len(numbers)):
print(f"索引{i}:值{numbers[i]}")
给家长的小贴士:
- 这个概念比较深,小学阶段只需要简单了解
- 核心思想:索引是用来“计算“内存位置的
- 这解释了为什么列表访问很快(O(1)时间复杂度)
- 不需要孩子掌握内存地址计算的细节
索引越界(IndexError)
如果访问一个不存在的索引,Python会报错:IndexError(索引错误)。
错误示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 这个列表有4个元素,索引是0, 1, 2, 3
print(fruits[4]) # 错误!索引4不存在!
错误信息:
IndexError: list index out of range
解释:
- 列表有4个元素,索引范围是0到3
- 访问索引4会越界
- 就像你想住5号房间,但宾馆只有4层楼
避免索引越界的方法:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 方法1:使用len()检查索引范围
if len(fruits) > 4:
print(fruits[4])
else:
print("索引4不存在")
# 方法2:使用反向索引(更安全)
print(fruits[-1]) # 最后一个元素
实践1:访问列表元素
题目:给定一个列表,完成以下任务。
# 学生成绩列表
scores = [85, 92, 78, 95, 88]
任务:
- 打印第一个成绩
- 打印最后一个成绩
- 打印中间的成绩(第3个)
- 打印倒数第二个成绩
👉 点击查看答案
# 学生成绩列表
scores = [85, 92, 78, 95, 88]
# 1. 第一个成绩
print(f"第一个成绩:{scores[0]}") # 85
# 2. 最后一个成绩
print(f"最后一个成绩:{scores[-1]}") # 88
# 3. 中间的成绩(第3个)
print(f"第3个成绩:{scores[2]}") # 78
# 4. 倒数第二个成绩
print(f"倒数第二个成绩:{scores[-2]}") # 95
运行结果:
第一个成绩:85
最后一个成绩:88
第3个成绩:78
倒数第二个成绩:95
练习2:索引练习
题目:下面的程序会输出什么?
colors = ["红", "橙", "黄", "绿", "青", "蓝", "紫"]
print(colors[2])
print(colors[-3])
print(colors[0])
print(colors[-1])
👉 点击查看答案
输出:
黄
绿
红
紫
解释:
colors[2]:索引2是第3个元素“黄“colors[-3]:倒数第3个元素“绿“colors[0]:第1个元素“红“colors[-1]:最后1个元素“紫“
切片(Slice)
切片可以获取列表的一部分,创建一个新的列表。
切片语法:list[start:end:step]
start:起始索引(包含)end:结束索引(不包含!)step:步长(可选,默认为1)
基本切片
示例1:获取前几个元素
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 获取前3个元素(索引0, 1, 2)
print(numbers[0:3]) # [0, 1, 2]
# 简写:省略起始索引0
print(numbers[:3]) # [0, 1, 2]
示例2:获取中间的元素
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 获取索引2到6的元素(不包含6)
print(numbers[2:6]) # [2, 3, 4, 5]
示例3:获取后几个元素
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 获取最后3个元素
print(numbers[-3:]) # [7, 8, 9]
# 获取从索引7到最后的元素
print(numbers[7:]) # [7, 8, 9]
示例4:获取整个列表
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 方法1:省略start和end
print(numbers[:]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 方法2:使用完整范围
print(numbers[0:len(numbers)]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
带步长的切片
示例1:每隔几个元素取一个
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 每隔2个取一个(取索引0, 2, 4, 6, 8)
print(numbers[::2]) # [0, 2, 4, 6, 8]
# 每隔3个取一个
print(numbers[::3]) # [0, 3, 6, 9]
示例2:反向切片
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 反向列表(步长为-1)
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
给家长的小贴士:
- 切片的核心是**“包含起始,不包含结束”**
- 用“切蛋糕“类比:从哪里切,到哪里切
- 省略起始表示从头开始,省略结束表示到末尾
- 负数步长会反向取元素
- 让孩子用可视化工具(如切片可视化网站)帮助理解
切片图解
列表: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
索引: 0 1 2 3 4 5 6 7 8 9
切片 [2:6]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
↑ ↑
start end(不包含)
结果: [2, 3, 4, 5]
练习3:切片练习
题目:预测下面的切片结果。
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
# 预测结果
print(letters[2:5])
print(letters[:4])
print(letters[5:])
print(letters[::2])
print(letters[::-1])
👉 点击查看答案
结果:
['C', 'D', 'E']
['A', 'B', 'C', 'D']
['F', 'G', 'H']
['A', 'C', 'E', 'G']
['H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']
解释:
letters[2:5]:索引2到4,即[‘C’, ‘D’, ‘E’]letters[:4]:开头到索引3,即[‘A’, ‘B’, ‘C’, ‘D’]letters[5:]:索引5到末尾,即[‘F’, ‘G’, ‘H’]letters[::2]:每隔一个取一个,即[‘A’, ‘C’, ‘E’, ‘G’]letters[::-1]:反向,即[‘H’, ‘G’, ‘F’, ‘E’, ‘D’, ‘C’, ‘B’, ‘A’]
列表的长度
使用len()函数可以获取列表中元素的个数。
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 获取长度
print(len(fruits)) # 4
# 空列表的长度
empty_list = []
print(len(empty_list)) # 0
为什么长度很重要
场景1:避免索引越界
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 错误:直接访问可能不存在的索引
# print(fruits[10]) # IndexError!
# 正确:先检查长度
if len(fruits) > 10:
print(fruits[10])
else:
print("索引10不存在")
场景2:循环访问所有元素
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 使用range和len循环
for i in range(len(fruits)):
print(f"索引{i}:{fruits[i]}")
输出:
索引0:苹果
索引1:香蕉
索引2:橙子
索引3:葡萄
实践2:使用长度
题目:打印列表的所有元素,格式为“第i个元素是:xxx“。
animals = ["猫", "狗", "兔子", "仓鼠"]
👉 点击查看答案
animals = ["猫", "狗", "兔子", "仓鼠"]
# 使用range和len
for i in range(len(animals)):
print(f"第{i + 1}个元素是:{animals[i]}")
输出:
第1个元素是:猫
第2个元素是:狗
第3个元素是:兔子
第4个元素是:仓鼠
注意:我们用i + 1是因为索引从0开始,但我们要显示“第1个“、“第2个“等(从1开始)。
修改列表元素
列表是可变的(mutable),这意味着我们可以修改、添加或删除元素。
修改单个元素
语法:list[index] = new_value
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 修改第1个元素(索引0)
fruits[0] = "草莓"
print(fruits) # ['草莓', '香蕉', '橙子', '葡萄']
# 修改最后一个元素
fruits[-1] = "西瓜"
print(fruits) # ['草莓', '香蕉', '橙子', '西瓜']
修改多个元素(使用切片)
示例1:用切片修改
numbers = [0, 1, 2, 3, 4, 5]
# 修改索引2到4的元素
numbers[2:5] = [20, 30, 40]
print(numbers) # [0, 1, 20, 30, 40, 5]
示例2:替换不同数量的元素
numbers = [0, 1, 2, 3, 4, 5]
# 用2个元素替换3个元素
numbers[1:4] = [10, 20]
print(numbers) # [0, 10, 20, 4, 5]
# 用4个元素替换2个元素
numbers[1:3] = [100, 200, 300, 400]
print(numbers) # [0, 100, 200, 300, 400, 4, 5]
练习4:修改列表
题目:完成以下任务。
scores = [85, 92, 78, 95, 88]
- 将第一个成绩修改为90
- 将最后一个成绩修改为100
- 将中间三个成绩修改为80, 85, 90
👉 点击查看答案
scores = [85, 92, 78, 95, 88]
# 1. 修改第一个成绩
scores[0] = 90
print(f"第一次修改后:{scores}") # [90, 92, 78, 95, 88]
# 2. 修改最后一个成绩
scores[-1] = 100
print(f"第二次修改后:{scores}") # [90, 92, 78, 95, 100]
# 3. 修改中间三个成绩
scores[1:4] = [80, 85, 90]
print(f"第三次修改后:{scores}") # [90, 80, 85, 90, 100]
列表的常用方法
Python提供了很多列表方法(list methods),帮助我们方便地操作列表。
添加元素
append():在末尾添加元素
语法:list.append(item)
示例:
fruits = ["苹果", "香蕉"]
# 在末尾添加一个元素
fruits.append("橙子")
print(fruits) # ['苹果', '香蕉', '橙子']
fruits.append("葡萄")
print(fruits) # ['苹果', '香蕉', '橙子', '葡萄']
insert():在指定位置插入元素
语法:list.insert(index, item)
示例:
fruits = ["苹果", "香蕉", "葡萄"]
# 在索引1的位置插入"橙子"
fruits.insert(1, "橙子")
print(fruits) # ['苹果', '橙子', '香蕉', '葡萄']
# 在开头插入
fruits.insert(0, "草莓")
print(fruits) # ['草莓', '苹果', '橙子', '香蕉', '葡萄']
extend():合并两个列表
语法:list.extend(other_list)
示例:
fruits = ["苹果", "香蕉"]
more_fruits = ["橙子", "葡萄", "西瓜"]
# 将more_fruits的所有元素添加到fruits
fruits.extend(more_fruits)
print(fruits) # ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
对比append和extend:
list1 = [1, 2]
list2 = [3, 4]
# append:将list2作为一个元素添加
list1.append(list2)
print(list1) # [1, 2, [3, 4]]
# extend:将list2的元素展开添加
list1 = [1, 2]
list1.extend(list2)
print(list1) # [1, 2, 3, 4]
删除元素
del:根据索引删除
语法:del list[index]
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 删除索引1的元素
del fruits[1]
print(fruits) # ['苹果', '橙子', '葡萄']
# 删除第一个元素
del fruits[0]
print(fruits) # ['橙子', '葡萄']
remove():根据值删除
语法:list.remove(value)
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 删除值为"香蕉"的元素
fruits.remove("香蕉")
print(fruits) # ['苹果', '橙子', '葡萄']
注意:如果值不存在,会报错ValueError。
安全的删除方法:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 先检查是否存在
if "西瓜" in fruits:
fruits.remove("西瓜")
else:
print("西瓜不在列表中")
pop():删除并返回元素
语法:list.pop(index)(默认删除最后一个)
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 删除最后一个元素
last_fruit = fruits.pop()
print(last_fruit) # 葡萄
print(fruits) # ['苹果', '香蕉', '橙子']
# 删除指定索引的元素
second_fruit = fruits.pop(1)
print(second_fruit) # 香蕉
print(fruits) # ['苹果', '橙子']
排序
sort():原地排序
语法:list.sort()(默认升序)
示例:
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# 升序排序
numbers.sort()
print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
# 降序排序
numbers.sort(reverse=True)
print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1]
字符串排序:
fruits = ["香蕉", "苹果", "橙子", "葡萄"]
# 按字母顺序排序
fruits.sort()
print(fruits) # ['葡萄', '橙子', '苹果', '香蕉']
sorted():返回新列表
语法:sorted(list)
示例:
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# sorted返回新列表,原列表不变
sorted_numbers = sorted(numbers)
print(sorted_numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
print(numbers) # [3, 1, 4, 1, 5, 9, 2, 6](原列表不变)
反转
reverse():原地反转
numbers = [1, 2, 3, 4, 5]
numbers.reverse()
print(numbers) # [5, 4, 3, 2, 1]
其他常用方法
| 方法 | 作用 | 示例 |
|---|---|---|
len(list) | 返回列表长度 | len([1, 2, 3]) → 3 |
list.count(item) | 统计元素出现次数 | [1, 2, 2, 3].count(2) → 2 |
list.index(item) | 返回元素的索引 | ['a', 'b', 'c'].index('b') → 1 |
list.clear() | 清空列表 | [1, 2, 3].clear() → [] |
item in list | 判断元素是否存在 | 'a' in ['a', 'b'] → True |
item not in list | 判断元素是否不存在 | 'c' not in ['a', 'b'] → True |
给家长的小贴士:
- 列表方法分为“原地修改“和“返回新列表“两种
- append、insert、extend、sort、reverse是原地修改
- sorted返回新列表,原列表不变
- 强调
in和not in的用法,非常实用- 可以制作方法卡片,让孩子随时查阅
实践3:列表方法综合练习
题目:完成以下任务。
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
- 在末尾添加数字8
- 在开头添加数字0
- 删除值为1的第一个元素
- 统计数字1出现的次数
- 判断数字7是否在列表中
- 对列表进行升序排序
👉 点击查看答案
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# 1. 在末尾添加数字8
numbers.append(8)
print(f"添加8后:{numbers}") # [3, 1, 4, 1, 5, 9, 2, 6, 8]
# 2. 在开头添加数字0
numbers.insert(0, 0)
print(f"添加0后:{numbers}") # [0, 3, 1, 4, 1, 5, 9, 2, 6, 8]
# 3. 删除值为1的第一个元素
numbers.remove(1)
print(f"删除1后:{numbers}") # [0, 3, 4, 1, 5, 9, 2, 6, 8]
# 4. 统计数字1出现的次数
count = numbers.count(1)
print(f"数字1出现{count}次") # 数字1出现1次
# 5. 判断数字7是否在列表中
if 7 in numbers:
print("数字7在列表中")
else:
print("数字7不在列表中")
# 6. 对列表进行升序排序
numbers.sort()
print(f"排序后:{numbers}") # [0, 1, 2, 3, 4, 5, 6, 8, 9]
遍历列表
遍历(Traverse)就是依次访问列表中的每个元素。我们有两种主要方式来遍历列表。
方式1:遍历元素(不需要索引)
语法:
for item in list:
# 处理item
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 直接遍历元素
for fruit in fruits:
print(f"我喜欢吃{fruit}")
输出:
我喜欢吃苹果
我喜欢吃香蕉
我喜欢吃橙子
我喜欢吃葡萄
适用场景:
- 只需要访问元素,不需要知道索引
- 对每个元素执行相同的操作
方式2:遍历索引(需要索引)
语法:
for i in range(len(list)):
# 通过list[i]访问元素
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 遍历索引
for i in range(len(fruits)):
print(f"索引{i}:{fruits[i]}")
输出:
索引0:苹果
索引1:香蕉
索引2:橙子
索引3:葡萄
适用场景:
- 需要修改列表元素
- 需要知道元素的索引位置
- 需要同时访问多个列表
方式3:同时获取索引和元素(enumerate)
语法:
for index, item in enumerate(list):
# index是索引,item是元素
示例:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 使用enumerate同时获取索引和元素
for index, fruit in enumerate(fruits):
print(f"索引{index}:{fruit}")
输出:
索引0:苹果
索引1:香蕉
索引2:橙子
索引3:葡萄
enumerate的起始索引参数:
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 从1开始编号
for index, fruit in enumerate(fruits, start=1):
print(f"第{index}个:{fruit}")
输出:
第1个:苹果
第2个:香蕉
第3个:橙子
第4个:葡萄
两种遍历方式的对比
场景1:只需要访问元素
# 推荐:遍历元素
for fruit in fruits:
print(fruit)
场景2:需要修改元素
# 推荐:遍历索引
for i in range(len(scores)):
scores[i] = scores[i] + 5 # 每个成绩加5分
场景3:需要索引和元素
# 推荐:使用enumerate
for i, fruit in enumerate(fruits):
print(f"索引{i}:{fruit}")
给家长的小贴士:
- 重要:遍历时如果需要修改元素,必须用索引方式
- 遍历元素更简洁,但无法修改元素
- enumerate是Python特有的,非常实用
- 可以让孩子对比三种方式,理解它们的区别
- 强调“从需求出发选择遍历方式“
练习5:遍历列表
题目1:计算列表中所有成绩的平均值。
scores = [85, 92, 78, 95, 88]
👉 点击查看答案
scores = [85, 92, 78, 95, 88]
# 方法1:遍历元素
total = 0
for score in scores:
total = total + score
average = total / len(scores)
print(f"平均成绩:{average}") # 平均成绩:87.6
# 方法2:使用sum函数(更简洁)
average = sum(scores) / len(scores)
print(f"平均成绩:{average}") # 平均成绩:87.6
题目2:将列表中所有偶数乘以2。
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
👉 点击查看答案
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 需要修改元素,使用索引遍历
for i in range(len(numbers)):
if numbers[i] % 2 == 0: # 如果是偶数
numbers[i] = numbers[i] * 2
print(numbers) # [1, 4, 3, 8, 5, 12, 7, 16, 9, 20]
题目3:打印列表及其索引(从1开始)。
colors = ["红", "橙", "黄", "绿", "蓝"]
👉 点击查看答案
colors = ["红", "橙", "黄", "绿", "蓝"]
# 使用enumerate,从1开始
for i, color in enumerate(colors, start=1):
print(f"第{i}种颜色:{color}")
输出:
第1种颜色:红
第2种颜色:橙
第3种颜色:黄
第4种颜色:绿
第5种颜色:蓝
数学应用:统计数据
列表在数学中有很多应用,特别是统计相关的问题。让我们用列表来解决一些数学问题!
基本统计量
在数学课上,你学过以下统计量:
- 平均数(Mean):所有数的和除以个数
- 中位数(Median):排序后中间的数
- 众数(Mode):出现次数最多的数
- 最大值(Max):最大的数
- 最小值(Min):最小的数
- 极差(Range):最大值减最小值
应用1:计算平均数
数学定义: $$ \text{平均数} = \frac{\text{所有数的总和}}{\text{数的个数}} $$
Python实现:
# 方法1:手动计算
scores = [85, 92, 78, 95, 88]
total = 0
for score in scores:
total = total + score
average = total / len(scores)
print(f"平均数:{average}") # 平均数:87.6
# 方法2:使用sum函数
average = sum(scores) / len(scores)
print(f"平均数:{average}") # 平均数:87.6
应用2:找出最大值和最小值
Python实现:
scores = [85, 92, 78, 95, 88]
# 使用内置函数
max_score = max(scores)
min_score = min(scores)
print(f"最大值:{max_score}") # 最大值:95
print(f"最小值:{min_score}") # 最小值:78
# 计算极差
range_ = max_score - min_score
print(f"极差:{range_}") # 极差:17
应用3:计算中位数
数学定义:
- 如果有奇数个数,中位数就是中间的数
- 如果有偶数个数,中位数就是中间两个数的平均数
示例:
# 奇数个元素
numbers1 = [1, 3, 5, 7, 9]
# 中位数是5(第3个数)
# 偶数个元素
numbers2 = [1, 3, 5, 7, 9, 11]
# 中位数是(5+7)/2=6(第3和第4个数的平均)
Python实现:
def calculate_median(numbers):
# 先排序
sorted_numbers = sorted(numbers)
n = len(sorted_numbers)
# 奇数个元素
if n % 2 == 1:
median = sorted_numbers[n // 2]
# 偶数个元素
else:
middle1 = sorted_numbers[n // 2 - 1]
middle2 = sorted_numbers[n // 2]
median = (middle1 + middle2) / 2
return median
# 测试奇数个
numbers1 = [1, 3, 5, 7, 9]
print(f"中位数:{calculate_median(numbers1)}") # 中位数:5
# 测试偶数个
numbers2 = [1, 3, 5, 7, 9, 11]
print(f"中位数:{calculate_median(numbers2)}") # 中位数:6.0
应用4:找众数
数学定义:众数是出现次数最多的数。
Python实现:
def find_mode(numbers):
# 统计每个数出现的次数
count_dict = {}
for num in numbers:
if num in count_dict:
count_dict[num] = count_dict[num] + 1
else:
count_dict[num] = 1
# 找出出现次数最多的数
max_count = 0
mode = numbers[0]
for num, count in count_dict.items():
if count > max_count:
max_count = count
mode = num
return mode
# 测试
numbers = [1, 2, 2, 3, 3, 3, 4]
print(f"众数:{find_mode(numbers)}") # 众数:3
给家长的小贴士:
- 这是很好的机会,用编程巩固数学知识
- 可以让孩子手动计算,再用程序验证
- 强调:数学公式和编程实现的对应关系
- 如果孩子还没学过中位数和众数,可以先跳过
- 鼓励孩子用列表解决实际问题(如统计考试成绩)
实践4:数学统计练习
题目:给定一组成绩,完成以下统计。
scores = [85, 92, 78, 95, 88, 65, 72, 58, 90, 82]
任务:
- 计算平均分
- 找出最高分和最低分
- 计算极差
- 统计及格人数(≥60分)
- 将成绩从低到高排序
👉 点击查看答案
scores = [85, 92, 78, 95, 88, 65, 72, 58, 90, 82]
# 1. 计算平均分
average = sum(scores) / len(scores)
print(f"平均分:{average:.1f}") # 平均分:80.5
# 2. 找出最高分和最低分
max_score = max(scores)
min_score = min(scores)
print(f"最高分:{max_score}") # 最高分:95
print(f"最低分:{min_score}") # 最低分:58
# 3. 计算极差
range_ = max_score - min_score
print(f"极差:{range_}") # 极差:37
# 4. 统计及格人数
pass_count = 0
for score in scores:
if score >= 60:
pass_count = pass_count + 1
print(f"及格人数:{pass_count}") # 及格人数:9
# 5. 排序
sorted_scores = sorted(scores)
print(f"排序后:{sorted_scores}")
# [58, 65, 72, 78, 82, 85, 88, 90, 92, 95]
数学应用:数列
列表非常适合表示数列。在数学中,数列是按照一定规律排列的一列数。
等差数列
数学定义:相邻两项的差相等(公差d)。
示例:
2, 5, 8, 11, 14, ...
公差是3(每个数比前一个数大3)
Python生成等差数列:
# 生成前n项等差数列
def arithmetic_sequence(a1, d, n):
"""生成首项为a1,公差为d,共n项的等差数列"""
sequence = []
for i in range(n):
term = a1 + i * d
sequence.append(term)
return sequence
# 示例:首项2,公差3,共10项
seq = arithmetic_sequence(2, 3, 10)
print(seq)
# [2, 5, 8, 11, 14, 17, 20, 23, 26, 29]
等差数列求和:
def sum_arithmetic_sequence(a1, d, n):
"""计算等差数列前n项和"""
# 公式:和 = (首项 + 末项) × 项数 / 2
an = a1 + (n - 1) * d # 末项
total = (a1 + an) * n // 2
return total
# 示例:1+2+3+...+100
total = sum_arithmetic_sequence(1, 1, 100)
print(f"1+2+3+...+100={total}") # 1+2+3+...+100=5050
等比数列
数学定义:相邻两项的比相等(公比q)。
示例:
2, 4, 8, 16, 32, ...
公比是2(每个数是前一个数的2倍)
Python生成等比数列:
def geometric_sequence(a1, q, n):
"""生成首项为a1,公比为q,共n项的等比数列"""
sequence = []
term = a1
for i in range(n):
sequence.append(term)
term = term * q
return sequence
# 示例:首项2,公比2,共10项
seq = geometric_sequence(2, 2, 10)
print(seq)
# [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
斐波那契数列
数学定义:
- 第1项是1
- 第2项是1
- 从第3项开始,每项等于前两项之和
1, 1, 2, 3, 5, 8, 13, 21, ...
Python生成斐波那契数列:
def fibonacci(n):
"""生成前n项斐波那契数列"""
if n <= 0:
return []
elif n == 1:
return [1]
elif n == 2:
return [1, 1]
sequence = [1, 1]
for i in range(2, n):
next_term = sequence[-1] + sequence[-2]
sequence.append(next_term)
return sequence
# 示例:前15项
fib = fibonacci(15)
print(fib)
# [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
练习6:数列练习
题目1:生成从1到100的所有偶数,并计算它们的和。
👉 点击查看答案
# 方法1:使用range
evens = list(range(2, 101, 2)) # 从2开始,每次加2,到100
print(f"偶数列表:{evens}")
total = sum(evens)
print(f"偶数和:{total}") # 偶数和:2550
# 方法2:使用循环
evens = []
for i in range(1, 51):
evens.append(2 * i)
print(f"偶数列表:{evens}")
print(f"偶数和:{sum(evens)}") # 偶数和:2550
题目2:生成2的n次方数列(1, 2, 4, 8, 16, …),共10项。
👉 点击查看答案
# 生成2的n次方数列
powers = []
for i in range(10):
powers.append(2 ** i)
print(f"2的n次方数列:{powers}")
# [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
# 计算总和
total = sum(powers)
print(f"总和:{total}") # 总和:1023
题目3:找出100以内所有能被3整除的数,并统计个数。
👉 点击查看答案
# 方法1:使用range和list
multiples_of_3 = list(range(3, 101, 3))
print(f"能被3整除的数:{multiples_of_3}")
print(f"共{len(multiples_of_3)}个") # 共33个
# 方法2:使用循环
multiples_of_3 = []
for i in range(1, 101):
if i % 3 == 0:
multiples_of_3.append(i)
print(f"能被3整除的数:{multiples_of_3}")
print(f"共{len(multiples_of_3)}个") # 共33个
列表的综合应用
应用1:统计成绩分布
题目:给定一组成绩,统计不同等级的人数。
scores = [85, 92, 78, 95, 88, 65, 72, 58, 90, 82]
等级标准:
- 优秀:≥90分
- 良好:80-89分
- 及格:60-79分
- 不及格:<60分
👉 点击查看答案
scores = [85, 92, 78, 95, 88, 65, 72, 58, 90, 82]
# 统计各等级人数
excellent = 0 # 优秀(>=90)
good = 0 # 良好(80-89)
pass_ = 0 # 及格(60-79)
fail = 0 # 不及格(<60)
for score in scores:
if score >= 90:
excellent = excellent + 1
elif score >= 80:
good = good + 1
elif score >= 60:
pass_ = pass_ + 1
else:
fail = fail + 1
print("===== 成绩分布 =====")
print(f"优秀(≥90):{excellent}人") # 优秀:3人
print(f"良好(80-89):{good}人") # 良好:4人
print(f"及格(60-79):{pass_}人") # 及格:2人
print(f"不及格(<60):{fail}人") # 不及格:1人
运行结果:
===== 成绩分布 =====
优秀(≥90):3人
良好(80-89):4人
及格(60-79):2人
不及格(<60):1人
应用2:找最大值及其索引
题目:找出列表中的最大值及其索引位置。
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
👉 点击查看答案
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# 方法1:使用max和index
max_value = max(numbers)
max_index = numbers.index(max_value)
print(f"最大值:{max_value},索引:{max_index}")
# 输出:最大值:9,索引:5
# 方法2:手动查找(理解算法)
max_value = numbers[0]
max_index = 0
for i in range(1, len(numbers)):
if numbers[i] > max_value:
max_value = numbers[i]
max_index = i
print(f"最大值:{max_value},索引:{max_index}")
# 输出:最大值:9,索引:5
应用3:列表倒序
题目:将列表倒序,不使用reverse方法。
numbers = [1, 2, 3, 4, 5]
👉 点击查看答案
numbers = [1, 2, 3, 4, 5]
# 方法1:创建新列表
reversed_numbers = []
for i in range(len(numbers) - 1, -1, -1): # 从最后一个到第一个
reversed_numbers.append(numbers[i])
print(reversed_numbers) # [5, 4, 3, 2, 1]
# 方法2:交换位置(原地修改)
for i in range(len(numbers) // 2):
# 交换第i个和倒数第i个
temp = numbers[i]
numbers[i] = numbers[len(numbers) - 1 - i]
numbers[len(numbers) - 1 - i] = temp
print(numbers) # [5, 4, 3, 2, 1]
# 方法3:使用切片(最简洁)
print(numbers[::-1]) # [5, 4, 3, 2, 1]
字符串也是特殊的列表
在第3章我们学习了字符串,其实字符串也是一种特殊的列表!
字符串的列表特性
相似之处:
# 字符串可以像列表一样使用索引和切片
text = "Hello"
# 索引
print(text[0]) # H
print(text[-1]) # o
# 切片
print(text[1:4]) # ell
print(text[::-1]) # olleH(反向)
# 长度
print(len(text)) # 5
# 遍历
for char in text:
print(char)
不同之处:
# 字符串是不可变的(immutable)
text = "Hello"
# 错误!不能修改字符串
# text[0] = "h" # TypeError!
# 列表是可变的
numbers = [1, 2, 3]
numbers[0] = 10 # 可以修改
print(numbers) # [10, 2, 3]
字符串和列表的转换
字符串 → 列表(list)
# 将字符串转换为字符列表
text = "Hello"
chars = list(text)
print(chars) # ['H', 'e', 'l', 'l', 'o']
# 分割字符串为单词列表
sentence = "I love Python"
words = sentence.split() # 按空格分割
print(words) # ['I', 'love', 'Python']
# 按指定字符分割
date = "2024-02-14"
parts = date.split("-")
print(parts) # ['2024', '02', '14']
列表 → 字符串(join)
# 将字符列表连接为字符串
chars = ['H', 'e', 'l', 'l', 'o']
text = "".join(chars)
print(text) # Hello
# 用指定字符连接
words = ["I", "love", "Python"]
sentence = " ".join(words)
print(sentence) # I love Python
# 用其他字符连接
parts = ["2024", "02", "14"]
date = "-".join(parts)
print(date) # 2024-02-14
给家长的小贴士:
- 强调字符串和列表的相似性,帮助孩子理解
- 用“珍珠项链“类比:字符串是焊死的,列表是可拆卸的
- split和join是非常实用的方法,重点讲解
- 可以让孩子用split和join处理文本(如句子、日期)
实践5:字符串和列表转换
题目1:统计一个句子中有多少个单词。
sentence = "I love Python programming"
👉 点击查看答案
sentence = "I love Python programming"
# 方法1:使用split
words = sentence.split()
word_count = len(words)
print(f"单词数量:{word_count}") # 单词数量:4
# 方法2:手动统计(计算空格+1)
space_count = 0
for char in sentence:
if char == " ":
space_count = space_count + 1
word_count = space_count + 1
print(f"单词数量:{word_count}") # 单词数量:4
题目2:反转一个字符串。
text = "Hello"
👉 点击查看答案
text = "Hello"
# 方法1:使用切片
reversed_text = text[::-1]
print(reversed_text) # olleH
# 方法2:转换为列表,反转,再连接
chars = list(text)
chars.reverse()
reversed_text = "".join(chars)
print(reversed_text) # olleH
# 方法3:手动构建
reversed_text = ""
for i in range(len(text) - 1, -1, -1):
reversed_text = reversed_text + text[i]
print(reversed_text) # olleH
元组(Tuple)简介
元组(Tuple)是另一种有序的数据结构,它和列表非常相似,但有一个关键区别:元组是不可变的(immutable)。
元组的创建
语法:使用圆括号()代替方括号[]
# 创建元组
empty_tuple = () # 空元组
numbers = (1, 2, 3, 4, 5)
fruits = ("苹果", "香蕉", "橙子")
# 单个元素的元组(注意逗号!)
single = (1,) # 必须有逗号
print(type(single)) # <class 'tuple'>
# 如果没有逗号,就不是元组
not_tuple = (1)
print(type(not_tuple)) # <class 'int'>
元组和列表的对比
| 特性 | 列表(List) | 元组(Tuple) |
|---|---|---|
| 符号 | [] | () |
| 可变性 | 可变 | 不可变 |
| 性能 | 较慢 | 较快 |
| 用途 | 存储需要修改的数据 | 存储固定数据 |
| 方法 | 丰富 | 较少 |
示例:
# 列表:可以修改
list1 = [1, 2, 3]
list1[0] = 10
print(list1) # [10, 2, 3]
# 元组:不能修改
tuple1 = (1, 2, 3)
# tuple1[0] = 10 # TypeError!'tuple' object does not support item assignment
元组的常见用途
用途1:返回多个值
# 函数返回多个值(实际上是返回元组)
def get_user_info():
name = "小明"
age = 10
grade = 5
return name, age, grade # 返回元组
user_info = get_user_info()
print(user_info) # ('小明', 10, 5)
# 解包
name, age, grade = get_user_info()
print(f"姓名:{name},年龄:{age},年级:{grade}")
用途2:保护数据不被修改
# 常量配置
CONFIG = ("localhost", 8080, "admin")
# CONFIG[0] = "192.168.1.1" # 错误!不能修改
用途3:字典的键
# 元组可以作为字典的键(后续章节学习)
coordinates = {(10, 20): "点A", (30, 40): "点B"}
# 列表不能作为字典的键
给家长的小贴士:
- 元组和列表的主要区别是“可变vs不可变“
- 用“相册“类比:元组是洗出来的照片,列表是电子相册
- 强调元组的不可变性,这是它存在的意义
- 元组通常用于“不应该被修改“的数据
常见错误和调试
错误1:索引越界
错误代码:
fruits = ["苹果", "香蕉", "橙子"]
print(fruits[3]) # IndexError!
原因:索引3不存在(有效索引是0, 1, 2)
修正:
fruits = ["苹果", "香蕉", "橙子"]
# 方法1:检查索引
if len(fruits) > 3:
print(fruits[3])
else:
print("索引3不存在")
# 方法2:使用反向索引
print(fruits[-1]) # 最后一个元素
错误2:缩进错误
错误代码:
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit) # IndentationError!
原因:for循环的循环体必须缩进
修正:
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit) # 正确缩进
错误3:修改正在遍历的列表
问题代码:
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # 危险!
print(numbers) # 结果可能不正确
原因:遍历时修改列表会导致索引混乱
修正:
# 方法1:创建新列表
numbers = [1, 2, 3, 4, 5]
odd_numbers = []
for num in numbers:
if num % 2 != 0: # 只保留奇数
odd_numbers.append(num)
numbers = odd_numbers
print(numbers) # [1, 3, 5]
# 方法2:遍历副本
numbers = [1, 2, 3, 4, 5]
for num in numbers[:]: # 遍历副本
if num % 2 == 0:
numbers.remove(num)
print(numbers) # [1, 3, 5]
错误4:混淆append和extend
错误代码:
list1 = [1, 2]
list2 = [3, 4]
list1.append(list2) # 本想合并,结果嵌套了
print(list1) # [1, 2, [3, 4]](不是想要的!)
修正:
list1 = [1, 2]
list2 = [3, 4]
# 方法1:使用extend
list1.extend(list2)
print(list1) # [1, 2, 3, 4]
# 方法2:使用+
list1 = [1, 2]
list2 = [3, 4]
list3 = list1 + list2
print(list3) # [1, 2, 3, 4]
给家长的小贴士:
- 索引越界是最常见的错误,教孩子学会检查长度
- 缩进错误是初学者常犯的,强调Python对缩进的要求
- 遍历时修改列表是高级错误,建议使用新列表
- 鼓励孩子使用print调试法:打印中间结果
章节小结
我们学到了什么
-
列表的概念:
- 列表是有序的数据集合
- 列表用方括号
[]表示 - 列表可以存储任意类型的数据
- 列表是可变的(可以修改)
-
列表在内存中的存储:
- 列表在内存中连续存放
- 索引是相对于起始位置的偏移量
- 通过索引可以快速访问元素
- 列表长度影响内存占用
-
列表的基本操作:
- 创建列表:
[]或list() - 访问元素:使用索引(从0开始)
- 切片:
list[start:end:step] - 获取长度:
len(list)
- 创建列表:
-
列表的方法:
- 添加元素:
append(),insert(),extend() - 删除元素:
del,remove(),pop() - 排序:
sort(),sorted() - 其他:
count(),index(),reverse()
- 添加元素:
-
遍历列表:
- 遍历元素:
for item in list - 遍历索引:
for i in range(len(list)) - 同时获取索引和元素:
enumerate(list)
- 遍历元素:
-
数学应用:
- 统计量:平均数、中位数、众数、最大值、最小值
- 数列:等差数列、等比数列、斐波那契数列
- 数据排序和查找
-
字符串和列表:
- 字符串是特殊的列表
- 字符串不可变,列表可变
- 转换:
list()和"".join()
-
元组:
- 元组是不可变的列表
- 元组用圆括号
()表示 - 元组用于存储固定数据
重要概念对比
| 概念 | 列表 | 元组 | 字符串 |
|---|---|---|---|
| 符号 | [] | () | ""或'' |
| 可变性 | 可变 | 不可变 | 不可变 |
| 索引 | 支持 | 支持 | 支持 |
| 切片 | 支持 | 支持 | 支持 |
| 遍历 | 支持 | 支持 | 支持 |
| 元素类型 | 任意 | 任意 | 仅字符 |
| 内存存储 | 连续 | 连续 | 连续 |
常用操作总结
| 操作 | 语法 | 示例 |
|---|---|---|
| 创建 | []或list() | fruits = ["苹果", "香蕉"] |
| 访问 | list[index] | fruits[0] |
| 切片 | list[start:end] | fruits[1:3] |
| 长度 | len(list) | len(fruits) |
| 添加 | list.append(item) | fruits.append("橙子") |
| 删除 | del list[index] | del fruits[0] |
| 排序 | list.sort() | numbers.sort() |
| 遍历 | for item in list | for fruit in fruits |
编程技巧
-
选择合适的遍历方式:
- 只需要访问元素:遍历元素
- 需要修改元素:遍历索引
- 需要索引和元素:使用enumerate
-
避免常见错误:
- 索引从0开始,不是1
- 切片不包括结束位置
- 遍历时不要直接修改列表
-
善用列表方法:
in和not in判断元素是否存在sum(),max(),min()快速统计split()和join()处理字符串
-
理解内存原理:
- 列表在内存中连续存放
- 索引用于快速计算内存地址
- 列表大小与内存占用相关
下一步
在下一章(第11章),我们将学习字典(Dictionary),这是一种用“键-值“对存储数据的数据结构。字典不像列表那样连续存储,而是使用一种叫做“哈希表“的技术,能快速查找数据!
挑战练习
-
必做:
- 创建一个存储你朋友名字的列表,并打印每个名字
- 给定一个成绩列表,计算平均分、最高分、最低分
- 将一个列表的所有元素乘以2
-
选做:
- 实现一个简单的待办事项列表程序
- 统计一个句子中每个单词出现的次数
- 合并两个列表并去除重复元素
-
数学挑战:
- 实现1+2+3+…+100的求和(用循环)
- 生成前20项斐波那契数列
- 找出一个列表的中位数
- 统计数据的众数
-
综合项目:
- 设计一个学生成绩管理系统(使用列表存储学生信息)
- 实现一个简单的井字棋游戏(使用列表表示棋盘)
- 创建一个单词统计程序(统计文本中的单词频率)
加油!你已经掌握了Python中最常用的数据结构——列表!🎉
列表是程序员的“瑞士军刀“,几乎所有的Python程序都会用到列表。你现在不仅学会了如何使用列表,还理解了它在内存中的存储方式,以及如何用它来解决数学问题!
继续努力,接下来我们将学习字典,它会让你的程序更强大!💪
第11章 数据结构:字典
引言
想象一下,你在学校里有一个储物柜。每个储物柜都有一个编号,你可以在里面放东西。要用储物柜,你需要记住你的柜子号码,这样就能快速找到你的东西。
或者想想你查字典的时候:你想找“苹果“这个词,你会先找拼音“p“,然后在这个字母下面找“ping“,最后找到“苹果“。这个过程就是通过“索引“(拼音)来找到“内容“(解释)。
在Python中,有一种和储物柜很像的数据结构,叫做“字典“(Dictionary)。字典让我们能够用“钥匙“(key)来找到对应的“值“(value),就像用储物柜的号码来找到里面的东西一样。
🎯 本章学习目标:
- 学会使用字典存储“键-值“对数据
- 理解字典和数学中“映射“的关系
- 了解字典为什么查找速度这么快(哈希表)
- 用字典解决实际问题
给家长的小贴士 🧑🏫
生活类比:可以用以下例子帮助孩子理解“键-值“对:
- 电话簿:姓名→电话号码
- 字典查词:拼音→词语解释
- 储物柜:柜号→存放物品
- 身份证号:号码→个人信息
- 快递柜:取件码→快递包裹
数学关联:字典的概念和数学中的“映射“或“函数“非常相似!如果孩子学过函数 y = f(x),可以告诉孩子:
- 键(key)就是自变量 x
- 值(value)就是因变量 y
- 字典就是一组特殊的函数关系
什么是字典
字典是Python中的一种数据结构,它存储的是“键-值“对(key-value pairs)。
键和值的概念
- 键(key):就像储物柜的编号,用来唯一标识一个值
- 值(value):就像储物柜里放的东西,是我们真正想要存储的数据
数学中的“映射“ 📊
在数学课中,你可能学过映射或者函数的概念。比如:
- 如果 x = 1,那么 y = 2
- 如果 x = 2,那么 y = 4
- 如果 x = 3,那么 y = 6
这可以写成函数:y = 2x
在Python的字典中,我们也可以表达类似的关系:
# 创建一个字典
heights = {"小明": 150, "小红": 145, "小华": 152}
# 访问字典中的值
print(heights["小明"]) # 输出: 150
在这个例子中:
- “小明”、“小红”、“小华” 是键(key),就像数学中的 x
- 150、145、152 是值(value),就像数学中的 y
- 整个
{"小明": 150, "小红": 145, "小华": 152}就是一组映射关系
给家长的小贴士 🧑🏫
数学融入:可以和孩子一起做以下练习:
- 让孩子写出班级同学的姓名和身高的对应关系
- 问问孩子:这像不像数学中的“有序数对“?
- 引导孩子理解:(姓名, 身高) 就像 (x, y) 这样的坐标
思考问题:
- 如果两个同学叫同一个名字,会发生什么?(引导学生理解键的唯一性)
- 如果想查询某个同学的身高,需要做什么?(引导学生理解查找的概念)
字典与列表的区别
| 特点 | 列表 | 字典 |
|---|---|---|
| 索引 | 数字索引(0, 1, 2…) | 任意不可变类型的键 |
| 访问 | list[0] | dict["key"] |
| 顺序 | 有序 | 无序(Python 3.7+有序) |
| 用途 | 按顺序存储数据 | 按键值对存储数据 |
给家长的小贴士:可以告诉孩子,列表像是一排编号的盒子,你必须记住号码才能找到东西;而字典像是给每个盒子贴了标签,你可以直接通过标签找到东西。
为什么字典查找这么快?⚡
你可能会问:列表和字典都可以存储数据,为什么字典的查找速度更快呢?
列表的查找方式
想象一下,你要在一本没有索引的书中找某个词。你必须:
- 从第一页开始
- 一页一页地翻
- 直到找到这个词
如果书有100页,你平均要翻50页才能找到!
在Python中,用列表查找也是这样:
# 用列表存储学生信息
students_list = ["小明", "小红", "小华", "小刚", "小李"]
# 查找"小华"
if "小华" in students_list:
print("找到了!")
# Python需要从第一个开始,一个一个比较,直到找到"小华"
字典的查找方式:哈希表 🗂️
字典使用了一种叫做哈希表(Hash Table)的技术,它就像给每个数据都贴了一个“魔法标签“。
什么是哈希函数?
哈希函数就像一个“魔法计算器“,它能:
- 把任意输入(比如“小明“)转换成一个数字(比如 23)
- 相同的输入总是得到相同的数字(“小明“永远是23)
- 不同的输入大概率得到不同的数字
# 简化版的哈希函数(用取余数来模拟)
def simple_hash(key, size):
"""简化版哈希函数:把字符串转成数字,然后取余"""
# 在真实Python中,hash()函数要复杂得多
total = 0
for char in key:
total += ord(char) # 把字符转成数字
return total % size
# 假设我们有10个"盒子"
print(simple_hash("小明", 10)) # 输出: 某个0-9的数字
print(simple_hash("小红", 10)) # 输出: 另一个0-9的数字
哈希表的工作原理
想象你有100个储物柜,编号0-99:
-
添加数据时:
- 把“小明“通过哈希函数计算,得到 23
- 把“小明“的信息放在第23号柜子
- 把“小红“通过哈希函数计算,得到 57
- 把“小红“的信息放在第57号柜子
-
查找数据时:
- 要找“小明“,用哈希函数计算,得到 23
- 直接去第23号柜子拿
- 不需要一个个柜子翻!
数学类比:余数的妙用 ➗
哈希函数的核心思想很像“取余数“运算:
问题:有100个苹果,要分给7个人,每人几个?怎么分配?
# 用取余数来分配
apples = ["苹果1", "苹果2", "苹果3", ..., "苹果100"]
people = 7
for i, apple in enumerate(apples):
person = i % people # 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, ...
print(f"{apple} 给第{person}个人")
哈希函数也是类似的思路:把数据通过计算“分配“到不同的位置。
给家长的小贴士 🧑🏫
讲解方式:
-
用快递柜做类比:
- 快递柜有100个格子
- 你收到取件码“23-5678“
- 你直接去23号柜子,输入5678就能取件
- 不需要一个个柜子试!
-
时间复杂度(适合有编程基础的家长):
- 列表查找:O(n),n是元素个数
- 字典查找:O(1),和元素个数无关
- 如果有100万个数据,列表平均要找50万次,字典只需要1次!
-
实际演示:
import time
# 创建大数据
big_list = list(range(100000))
big_dict = {i: f"value_{i}" for i in range(100000)}
# 测试列表查找
start = time.time()
result = 99999 in big_list
list_time = time.time() - start
# 测试字典查找
start = time.time()
result = 99999 in big_dict
dict_time = time.time() - start
print(f"列表查找时间: {list_time:.6f}秒")
print(f"字典查找时间: {dict_time:.6f}秒")
print(f"字典快了 {list_time / dict_time:.0f} 倍!")
注意事项:
- 哈希表虽然快,但需要更多内存空间
- 不是所有情况都需要字典,数据量小时用列表就够了
- 小学阶段不需要深入理解哈希算法,知道“它能快速定位“即可
创建字典
方法一:直接创建
# 创建一个空字典
empty_dict = {}
# 创建一个有内容的字典
student = {"name": "小明", "age": 12, "grade": 6}
方法二:使用dict()函数
# 使用dict()函数创建
student = dict(name="小明", age=12, grade=6)
print(student)
# 输出: {'name': '小明', 'age': 12, 'grade': 6}
给家长的小贴士:这两种方法创建的字典是一样的,第一种方法更常用,特别是在处理复杂数据结构时。
访问字典中的值
使用键访问值
scores = {"语文": 95, "数学": 98, "英语": 88}
# 访问语文成绩
print(scores["语文"]) # 输出: 95
# 访问数学成绩
print(scores["数学"]) # 输出: 98
处理键不存在的情况
如果我们访问一个不存在的键,程序会报错:
scores = {"语文": 95, "数学": 98, "英语": 88}
# 这行代码会报错!KeyError
print(scores["科学"])
为了避免这种情况,我们有两种方法:
方法1:使用in检查键是否存在
scores = {"语文": 95, "数学": 98, "英语": 88}
subject = "科学"
if subject in scores:
print(scores[subject])
else:
print(f"没有{subject}这门课的成绩")
方法2:使用get()方法
scores = {"语文": 95, "数学": 98, "英语": 88}
# 使用get方法,如果键不存在,返回None
print(scores.get("科学")) # 输出: None
# 使用get方法,如果键不存在,返回默认值
print(scores.get("科学", "没有这门课")) # 输出: 没有这门课
给家长的小贴士:get()方法更安全,建议孩子养成使用get()的习惯,特别是在处理用户输入时。
添加和修改字典元素
添加新的键值对
# 创建一个空字典
phone_book = {}
# 添加新的联系人
phone_book["小明"] = "123-4567"
phone_book["小红"] = "234-5678"
print(phone_book)
# 输出: {'小明': '123-4567', '小红': '234-5678'}
修改现有的值
scores = {"语文": 95, "数学": 98, "英语": 88}
# 修改语文成绩
scores["语文"] = 99
print(scores)
# 输出: {'语文': 99, '数学': 98, '英语': 88}
给家长的小贴士:在Python中,添加新元素和修改现有元素的语法是一样的。如果键不存在,就是添加;如果键已存在,就是修改。
删除字典元素
方法1:使用del语句
scores = {"语文": 95, "数学": 98, "英语": 88}
# 删除语文成绩
del scores["语文"]
print(scores)
# 输出: {'数学': 98, '英语': 88}
方法2:使用pop()方法
scores = {"语文": 95, "数学": 98, "英语": 88}
# 删除并返回数学成绩
math_score = scores.pop("数学")
print(math_score) # 输出: 98
print(scores) # 输出: {'语文': 95, '英语': 88}
方法3:使用popitem()方法
scores = {"语文": 95, "数学": 98, "英语": 88}
# 删除并返回最后一个键值对(Python 3.7+)
last_item = scores.popitem()
print(last_item) # 输出: ('英语', 88)
print(scores) # 输出: {'语文': 95, '数学': 98}
给家长的小贴士:提醒孩子,del语句直接删除,不会返回值;pop()方法会返回被删除的值,可以在需要使用这个值的时候使用。
字典的常用操作
获取所有键、所有值、所有键值对
scores = {"语文": 95, "数学": 98, "英语": 88}
# 获取所有键
print(scores.keys()) # 输出: dict_keys(['语文', '数学', '英语'])
# 获取所有值
print(scores.values()) # 输出: dict_values([95, 98, 88])
# 获取所有键值对
print(scores.items()) # 输出: dict_items([('语文', 95), ('数学', 98), ('英语', 88)])
获取字典的长度
scores = {"语文": 95, "数学": 98, "英语": 88}
print(len(scores)) # 输出: 3
检查键是否存在
scores = {"语文": 95, "数学": 98, "英语": 88}
# 使用in检查
print("语文" in scores) # 输出: True
print("科学" in scores) # 输出: False
# 使用not in检查
print("语文" not in scores) # 输出: False
清空字典
scores = {"语文": 95, "数学": 98, "英语": 88}
# 清空字典
scores.clear()
print(scores) # 输出: {}
给家长的小贴士:keys()、values()、items()返回的是视图对象,不是列表。如果需要列表,可以用list()转换:list(scores.keys())
遍历字典
遍历所有键
scores = {"语文": 95, "数学": 98, "英语": 88}
# 方法1:直接遍历字典(遍历的是键)
for subject in scores:
print(subject)
# 输出:
# 语文
# 数学
# 英语
# 方法2:使用keys()方法(更明确)
for subject in scores.keys():
print(subject)
遍历所有值
scores = {"语文": 95, "数学": 98, "英语": 88}
for score in scores.values():
print(score)
# 输出:
# 95
# 98
# 88
遍历所有键值对
scores = {"语文": 95, "数学": 98, "英语": 88}
# 使用items()方法同时获取键和值
for subject, score in scores.items():
print(f"{subject}: {score}分")
# 输出:
# 语文: 95分
# 数学: 98分
# 英语: 88分
给家长的小贴士:最常用的是items()方法,因为它能同时获取键和值,代码更简洁。
字典的常用方法
update()方法 - 更新字典
# 原字典
scores = {"语文": 95, "数学": 98}
# 新数据
new_scores = {"英语": 88, "数学": 100}
# 用new_scores更新scores
scores.update(new_scores)
print(scores)
# 输出: {'语文': 95, '数学': 100, '英语': 88}
setdefault()方法 - 设置默认值
scores = {"语文": 95, "数学": 98}
# 如果"英语"不存在,设置默认值85
english_score = scores.setdefault("英语", 85)
print(english_score) # 输出: 85
print(scores) # 输出: {'语文': 95, '数学': 98, '英语': 85}
# 如果"数学"已存在,不会修改
math_score = scores.setdefault("数学", 0)
print(math_score) # 输出: 98
print(scores) # 输出: {'语文': 95, '数学': 98, '英语': 85}
fromkeys()方法 - 创建相同值的字典
# 创建一个字典,所有值都是0
subjects = ["语文", "数学", "英语"]
scores = dict.fromkeys(subjects, 0)
print(scores)
# 输出: {'语文': 0, '数学': 0, '英语': 0}
copy()方法 - 复制字典
original = {"语文": 95, "数学": 98}
# 浅复制
copied = original.copy()
# 修改复制的字典
copied["英语"] = 88
print(original) # 输出: {'语文': 95, '数学': 98}
print(copied) # 输出: {'语文': 95, '数学': 98, '英语': 88}
给家长的小贴士:copy()方法很重要,因为它创建了一个独立的副本,不会影响原字典。直接赋值new_dict = old_dict只是创建了一个引用。
字典的键的要求
字典的键必须满足以下要求:
-
键必须是不可变类型:
- 可以是:整数、浮点数、字符串、元组
- 不能是:列表、字典
-
键必须是唯一的:
- 如果有重复的键,后面的值会覆盖前面的值
# 正确的键
dict1 = {1: "one", 2.5: "two point five", "hello": "world", (1, 2): "tuple key"}
# 错误的键(会报错)
# dict2 = {[1, 2]: "list key"} # TypeError: 列表不能作为键
# 重复的键(后面的值会覆盖前面的)
dict3 = {"name": "小明", "name": "小红"}
print(dict3) # 输出: {'name': '小红'}
给家长的小贴士:可以用“门牌号“来类比,门牌号是固定的、唯一的,就像字典的键。如果两个储物柜号码相同,就会造成混乱。
嵌套字典
字典的值可以是任意类型,包括另一个字典。这就是“嵌套字典“。
简单的嵌套字典
# 存储学生信息
student = {
"name": "小明",
"age": 12,
"address": {
"city": "北京",
"district": "朝阳区"
}
}
# 访问嵌套字典
print(student["address"]["city"]) # 输出: 北京
复杂的嵌套字典
# 存储多个学生的信息
students = {
"001": {
"name": "小明",
"age": 12,
"scores": {"语文": 95, "数学": 98}
},
"002": {
"name": "小红",
"age": 11,
"scores": {"语文": 92, "数学": 99}
}
}
# 访问小红的数学成绩
print(students["002"]["scores"]["数学"]) # 输出: 99
字典和列表的嵌套
# 课程表:字典 + 列表的嵌套
schedule = {
"星期一": ["语文", "数学", "英语"],
"星期二": ["数学", "科学", "体育"],
"星期三": ["语文", "美术", "音乐"]
}
# 访问星期二第二节课
print(schedule["星期二"][1]) # 输出: 科学
复杂的嵌套结构
# 更复杂的课程表:多层嵌套
courses = {
"MON": {
"morning": ["数学", "英语", "绘画"],
"afternoon": ["音乐", "体育"]
},
"TUE": {
"morning": ["科学", "数学", "体育"],
"afternoon": ["英语"]
}
}
# 访问星期一上午第二节课
print(courses["MON"]["morning"][1]) # 输出: 英语
# 查看星期一下午课程的类型
print(type(courses["MON"]["afternoon"])) # 输出: <class 'list'>
# 查看星期一上午第二节课的类型
print(type(courses["MON"]["morning"][1])) # 输出: <class 'str'>
给家长的小贴士:嵌套结构理解起来比较困难,建议用“俄罗斯套娃“或“多层盒子“的类比。访问嵌套数据就像一层层打开盒子,每次只打开一层。
字典的排序
按键排序
scores = {"语文": 95, "数学": 98, "英语": 88}
# 按键排序
sorted_keys = sorted(scores.keys())
print(sorted_keys) # 输出: ['数学', '英语', '语文']
# 按排序后的顺序遍历
for subject in sorted_keys:
print(f"{subject}: {scores[subject]}")
# 输出:
# 数学: 98
# 英语: 88
# 语文: 95
按值排序
scores = {"语文": 95, "数学": 98, "英语": 88}
# 按值排序(从低到高)
sorted_items = sorted(scores.items(), key=lambda x: x[1])
print(sorted_items) # 输出: [('英语', 88), ('语文', 95), ('数学', 98)]
# 按值排序(从高到低)
sorted_items = sorted(scores.items(), key=lambda x: x[1], reverse=True)
print(sorted_items) # 输出: [('数学', 98), ('语文', 95), ('英语', 88)]
给家长的小贴士:lambda表达式对孩子来说比较抽象,可以简单地解释为“告诉Python按什么排序“。对于初学者,可以先跳过这个部分。
字典的应用案例
案例1:数学函数计算器 🧮
我们可以用字典来存储数学函数的值:
# 创建一个简单的函数表
function_table = {
1: 2, # f(1) = 2
2: 4, # f(2) = 4
3: 6, # f(3) = 6
4: 8, # f(4) = 8
5: 10 # f(5) = 10
}
# 查询函数值
x = int(input("请输入x的值(1-5): "))
if x in function_table:
y = function_table[x]
print(f"f({x}) = {y}")
else:
print("这个值不在表中")
# 你能猜出这是什么函数吗?
# 答案:f(x) = 2x (乘法函数)
数学挑战:发现规律 📊
# 更复杂的函数表
math_functions = {
"正方形面积": {1: 1, 2: 4, 3: 9, 4: 16, 5: 25},
"正方形周长": {1: 4, 2: 8, 3: 12, 4: 16, 5: 20},
"圆的面积": {1: 3.14, 2: 12.56, 3: 28.26, 4: 50.24, 5: 78.5}
}
# 让用户选择函数
for name in math_functions:
print(f"- {name}")
choice = input("\n请选择一个函数: ")
if choice in math_functions:
print(f"\n{choice}的值:")
for x, y in math_functions[choice].items():
print(f" 当边长/半径 = {x} 时,结果 = {y}")
# 让用户猜规律
print("\n你能发现这些数字的规律吗?")
给家长的小贴士 🧑🏫
数学融入:
-
函数关系:
- 引导孩子观察输入和输出的关系
- 问:“当x增加1时,y增加多少?”
- 这就是学习“变化率“的早期概念
-
找规律:
- 正方形面积:1, 4, 9, 16, 25 → 这些是什么数的平方?
- 正方形周长:4, 8, 12, 16, 20 → 每次增加4
- 引导孩子发现:面积 = 边长²,周长 = 边长 × 4
-
扩展练习:
- 让孩子自己创建一个函数表
- 比如:f(x) = x + 3,f(x) = x × 2 + 1
- 用字典存储前10个值
案例2:制作简单的翻译器
# 英汉词典
dictionary = {
"hello": "你好",
"world": "世界",
"python": "蟒蛇",
"computer": "电脑"
}
# 翻译功能
word = input("请输入要翻译的英文单词: ")
translation = dictionary.get(word.lower(), "词典里没有这个单词")
print(f"翻译结果: {translation}")
案例2:统计字符出现次数
# 统计字符串中每个字符出现的次数
text = "hello world"
# 创建空字典
char_count = {}
# 遍历字符串
for char in text:
if char in char_count:
char_count[char] += 1
else:
char_count[char] = 1
print(char_count)
# 输出: {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
案例3:制作简单的投票系统
# 投票系统
votes = {}
while True:
name = input("请输入要投票的同学的名字(输入'结束'退出): ")
if name == "结束":
break
# 使用get()方法,如果不存在则从0开始计数
votes[name] = votes.get(name, 0) + 1
print(f"{name}的票数: {votes[name]}")
# 输出最终结果
print("\n投票结果:")
for name, count in votes.items():
print(f"{name}: {count}票")
案例4:学生成绩管理系统
# 学生成绩管理系统
students = {}
while True:
print("\n===== 成绩管理系统 =====")
print("1. 添加学生")
print("2. 查询学生")
print("3. 显示所有学生")
print("4. 退出")
choice = input("请选择操作 (1-4): ")
if choice == "1":
# 添加学生
name = input("请输入学生姓名: ")
score = int(input("请输入学生成绩: "))
students[name] = score
print(f"已添加: {name}, 成绩: {score}")
elif choice == "2":
# 查询学生
name = input("请输入要查询的学生姓名: ")
if name in students:
print(f"{name}的成绩是: {students[name]}")
else:
print("没有找到该学生")
elif choice == "3":
# 显示所有学生
if students:
print("\n所有学生成绩:")
for name, score in students.items():
print(f"{name}: {score}分")
else:
print("还没有添加学生")
elif choice == "4":
print("再见!")
break
else:
print("无效的选择,请重新输入")
给家长的小贴士:这些案例都是很好的综合练习,可以让孩子自己尝试实现,然后再和示例代码对比,找出差异。
实践练习
练习1:单位换算器 📏
创建一个单位换算程序,支持长度、重量、温度等单位的换算。
数学知识:
- 1米 = 100厘米
- 1千克 = 1000克
- 摄氏度转华氏度:F = C × 9/5 + 32
查看答案
# 单位换算器
conversions = {
"长度": {"米": 1, "厘米": 0.01, "毫米": 0.001},
"重量": {"千克": 1, "克": 0.001, "吨": 1000},
"温度": {"摄氏度": "C", "华氏度": "F"}
}
print("=== 单位换算器 ===")
print("1. 长度换算")
print("2. 重量换算")
print("3. 温度换算")
choice = input("请选择换算类型 (1-3): ")
if choice == "1":
# 长度换算
value = float(input("请输入数值: "))
unit = input("请输入单位 (米/厘米/毫米): ")
target = input("请输入目标单位 (米/厘米/毫米): ")
if unit in conversions["长度"] and target in conversions["长度"]:
# 先转为米,再转为目标单位
in_meters = value * conversions["长度"][unit]
result = in_meters / conversions["长度"][target]
print(f"{value}{unit} = {result}{target}")
elif choice == "2":
# 重量换算(类似逻辑)
value = float(input("请输入数值: "))
unit = input("请输入单位 (千克/克/吨): ")
target = input("请输入目标单位 (千克/克/吨): ")
if unit in conversions["重量"] and target in conversions["重量"]:
in_kg = value * conversions["重量"][unit]
result = in_kg / conversions["重量"][target]
print(f"{value}{unit} = {result}{target}")
elif choice == "3":
# 温度换算
value = float(input("请输入温度值: "))
unit = input("请输入单位 (摄氏度/华氏度): ")
if unit == "摄氏度":
# C to F: F = C × 9/5 + 32
result = value * 9/5 + 32
print(f"{value}°C = {result:.1f}°F")
elif unit == "华氏度":
# F to C: C = (F - 32) × 5/9
result = (value - 32) * 5/9
print(f"{value}°F = {result:.1f}°C")
数学思考:
- 为什么要用字典存储单位换算率?(键值对的对应关系)
- 温度换算为什么不能用简单的乘法?(引导理解线性函数 y = ax + b)
练习2:罗马数字转换器 ➗⚖️
罗马数字是古罗马人使用的数字系统,比如:I=1, V=5, X=10, L=50, C=100。
创建一个程序,在罗马数字和阿拉伯数字之间转换。
查看答案
# 罗马数字转换器
roman_to_arabic = {
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000
}
print("=== 罗马数字转换器 ===")
print("1. 罗马数字 → 阿拉伯数字")
print("2. 阿拉伯数字 → 罗马数字")
choice = input("请选择 (1-2): ")
if choice == "1":
# 罗马数字转阿拉伯数字
roman = input("请输入罗马数字 (大写,如 XIV): ")
total = 0
prev_value = 0
# 从右到左遍历
for char in reversed(roman):
value = roman_to_arabic[char]
if value < prev_value:
total -= value
else:
total += value
prev_value = value
print(f"{roman} = {total}")
elif choice == "2":
# 简化版:阿拉伯数字转罗马数字(仅限1-10)
arabic_to_roman = {
1: "I", 2: "II", 3: "III", 4: "IV", 5: "V",
6: "VI", 7: "VII", 8: "VIII", 9: "IX", 10: "X"
}
num = int(input("请输入数字 (1-10): "))
if num in arabic_to_roman:
print(f"{num} = {arabic_to_roman[num]}")
else:
print("这个版本只支持1-10的转换")
历史和数学:
- 罗马数字为什么后来被阿拉伯数字取代?(计算方便)
- 罗马数字的“减法原则“:IV = 5-1 = 4,这体现了什么数学思想?
练习3:简单的电话簿
创建一个电话簿程序,支持以下功能:
- 添加联系人(姓名和电话)
- 查询联系人
- 显示所有联系人
- 删除联系人
查看答案
# 电话簿程序
phone_book = {}
while True:
print("\n===== 电话簿 =====")
print("1. 添加联系人")
print("2. 查询联系人")
print("3. 显示所有联系人")
print("4. 删除联系人")
print("5. 退出")
choice = input("请选择操作 (1-5): ")
if choice == "1":
# 添加联系人
name = input("请输入姓名: ")
phone = input("请输入电话: ")
phone_book[name] = phone
print(f"已添加: {name}")
elif choice == "2":
# 查询联系人
name = input("请输入要查询的姓名: ")
if name in phone_book:
print(f"{name}的电话: {phone_book[name]}")
else:
print("没有找到该联系人")
elif choice == "3":
# 显示所有联系人
if phone_book:
print("\n所有联系人:")
for name, phone in phone_book.items():
print(f"{name}: {phone}")
else:
print("电话簿是空的")
elif choice == "4":
# 删除联系人
name = input("请输入要删除的联系人姓名: ")
if name in phone_book:
del phone_book[name]
print(f"已删除: {name}")
else:
print("没有找到该联系人")
elif choice == "5":
print("再见!")
break
else:
print("无效的选择,请重新输入")
练习2:单词统计器
编写一个程序,统计一段文本中每个单词出现的次数。
查看答案
# 单词统计器
text = input("请输入一段文本: ")
# 分割成单词
words = text.split()
# 统计词频
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
# 输出结果
print("\n单词出现次数:")
for word, count in sorted(word_count.items()):
print(f"{word}: {count}次")
练习3:制作课程表
创建一个程序,管理一周的课程表。
查看答案
# 课程表管理
schedule = {}
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五"]
# 初始化课程表
for day in weekdays:
schedule[day] = []
while True:
print("\n===== 课程表管理 =====")
print("1. 添加课程")
print("2. 查看课程表")
print("3. 退出")
choice = input("请选择操作 (1-3): ")
if choice == "1":
# 添加课程
for i, day in enumerate(weekdays):
print(f"{i+1}. {day}")
day_choice = int(input("请选择星期几 (1-5): ")) - 1
course = input("请输入课程名称: ")
schedule[weekdays[day_choice]].append(course)
print(f"已添加: {weekdays[day_choice]} - {course}")
elif choice == "2":
# 查看课程表
print("\n=== 本周课程表 ===")
for day in weekdays:
courses = schedule[day]
if courses:
courses_str = "、".join(courses)
print(f"{day}: {courses_str}")
else:
print(f"{day}: 无课程")
elif choice == "3":
print("再见!")
break
else:
print("无效的选择,请重新输入")
练习4:计算平均成绩
创建一个程序,管理多个学生的成绩,并计算平均分。
查看答案
# 成绩管理系统
students = {}
while True:
print("\n===== 成绩管理 =====")
print("1. 添加学生成绩")
print("2. 查看学生成绩")
print("3. 查看班级平均分")
print("4. 退出")
choice = input("请选择操作 (1-4): ")
if choice == "1":
# 添加学生
name = input("请输入学生姓名: ")
score = float(input("请输入成绩: "))
students[name] = score
print(f"已添加: {name}")
elif choice == "2":
# 查看成绩
if students:
print("\n所有学生成绩:")
for name, score in students.items():
print(f"{name}: {score}分")
else:
print("还没有添加学生")
elif choice == "3":
# 计算平均分
if students:
average = sum(students.values()) / len(students)
print(f"班级平均分: {average:.2f}")
else:
print("还没有添加学生")
elif choice == "4":
print("再见!")
break
else:
print("无效的选择,请重新输入")
练习5:简单的加密解密程序
创建一个简单的凯撒密码加密解密程序。
查看答案
# 凯撒密码加密解密
def create_cipher(shift):
"""创建密码本"""
cipher = {}
for i in range(26):
original = chr(ord('a') + i)
encrypted = chr(ord('a') + (i + shift) % 26)
cipher[original] = encrypted
cipher[original.upper()] = encrypted.upper()
return cipher
def encrypt(text, cipher):
"""加密"""
result = []
for char in text:
if char in cipher:
result.append(cipher[char])
else:
result.append(char)
return ''.join(result)
def decrypt(text, cipher):
"""解密"""
# 创建反向密码本
reverse_cipher = {v: k for k, v in cipher.items()}
return encrypt(text, reverse_cipher)
# 主程序
shift = int(input("请输入偏移量 (1-25): "))
cipher = create_cipher(shift)
while True:
print("\n===== 加密解密系统 =====")
print("1. 加密")
print("2. 解密")
print("3. 退出")
choice = input("请选择操作 (1-3): ")
if choice == "1":
text = input("请输入要加密的文本: ")
encrypted = encrypt(text, cipher)
print(f"加密结果: {encrypted}")
elif choice == "2":
text = input("请输入要解密的文本: ")
decrypted = decrypt(text, cipher)
print(f"解密结果: {decrypted}")
elif choice == "3":
print("再见!")
break
else:
print("无效的选择,请重新输入")
练习6:数学成绩分析 📊
创建一个程序,分析班级数学成绩,计算最高分、最低分、平均分,并统计各分数段的人数。
查看答案
# 数学成绩分析
students = {
"小明": 95,
"小红": 87,
"小华": 92,
"小刚": 78,
"小李": 88,
"小张": 65,
"小王": 90,
"小陈": 82,
"小刘": 76,
"小赵": 94
}
# 计算统计数据
scores = list(students.values())
max_score = max(scores)
min_score = min(scores)
avg_score = sum(scores) / len(scores)
print(f"=== 数学成绩分析 ===")
print(f"最高分: {max_score}")
print(f"最低分: {min_score}")
print(f"平均分: {avg_score:.2f}")
# 按分数段统计
grade_ranges = {
"优秀(90-100)": 0,
"良好(80-89)": 0,
"及格(60-79)": 0,
"不及格(0-59)": 0
}
for score in scores:
if score >= 90:
grade_ranges["优秀(90-100)"] += 1
elif score >= 80:
grade_ranges["良好(80-89)"] += 1
elif score >= 60:
grade_ranges["及格(60-79)"] += 1
else:
grade_ranges["不及格(0-59)"] += 1
print("\n分数段统计:")
for range_name, count in grade_ranges.items():
print(f"{range_name}: {count}人")
# 找出成绩最高和最低的学生
max_student = max(students, key=students.get)
min_student = min(students, key=students.get)
print(f"\n最高分学生: {max_student} ({students[max_student]}分)")
print(f"最低分学生: {min_student} ({students[min_student]}分)")
数学知识点:
- 平均数:所有分数的和 ÷ 人数
- 中位数:如果按分数排序,中间位置的分数
- 众数:出现次数最多的分数
- 极差:最高分 - 最低分
扩展挑战:
- 计算方差(衡量分数的分散程度)
- 画出分数分布的柱状图
- 比较不同班级的成绩
综合应用:人员信息管理系统
结合前面学的知识,我们创建一个完整的人员信息管理系统:
# 人员信息管理系统
people = {}
def add_person():
"""添加人员"""
name = input("请输入姓名: ")
age = input("请输入年龄: ")
phone = input("请输入电话: ")
people[name] = {
"age": age,
"phone": phone
}
print(f"已添加: {name}")
def find_person():
"""查找人员"""
name = input("请输入要查找的姓名: ")
if name in people:
info = people[name]
print(f"姓名: {name}")
print(f"年龄: {info['age']}")
print(f"电话: {info['phone']}")
else:
print("没有找到该人员")
def list_all():
"""列出所有人员"""
if people:
print("\n所有人员信息:")
print("-" * 40)
for name, info in people.items():
print(f"姓名: {name}")
print(f"年龄: {info['age']}")
print(f"电话: {info['phone']}")
print("-" * 40)
else:
print("还没有添加人员")
def delete_person():
"""删除人员"""
name = input("请输入要删除的人员姓名: ")
if name in people:
del people[name]
print(f"已删除: {name}")
else:
print("没有找到该人员")
# 主菜单
while True:
print("\n===== 人员信息管理系统 =====")
print("1. 添加人员")
print("2. 查找人员")
print("3. 列出所有人员")
print("4. 删除人员")
print("5. 退出")
choice = input("请选择操作 (1-5): ")
if choice == "1":
add_person()
elif choice == "2":
find_person()
elif choice == "3":
list_all()
elif choice == "4":
delete_person()
elif choice == "5":
print("再见!")
break
else:
print("无效的选择,请重新输入")
给家长的小贴士:这个综合项目使用了字典的嵌套、增删改查等所有核心概念,是很好的实战练习。
字典和列表的选择
什么时候使用列表?
- 需要按顺序存储数据
- 使用数字索引访问元素
- 数据之间没有明确的“键“关系
- 例如:购物清单、待办事项列表
什么时候使用字典?
- 需要用有意义的名称访问数据
- 数据有明确的“键-值“关系
- 需要快速查找和更新
- 例如:电话簿、成绩表、配置信息
对比示例
# 使用列表存储学生信息(不推荐)
student_list = ["小明", 12, 6, 95] # 难以记住每个位置的含义
# 使用字典存储学生信息(推荐)
student_dict = {
"name": "小明",
"age": 12,
"grade": 6,
"score": 95
} # 每个字段都有明确的含义
给家长的小贴士:选择合适的数据结构是编程的重要能力,鼓励孩子在编写程序前先思考:“用列表还是字典更合适?”
常见错误和调试
错误1:使用不存在的键
scores = {"语文": 95, "数学": 98}
# 错误:直接访问不存在的键
print(scores["英语"]) # KeyError: '英语'
# 正确:使用get()方法
print(scores.get("英语", "没有这门课"))
错误2:使用可变类型作为键
# 错误:列表不能作为键
# my_dict = {[1, 2]: "value"} # TypeError
# 正确:元组可以作为键
my_dict = {(1, 2): "value"}
错误3:遍历字典时修改字典
scores = {"语文": 95, "数学": 98, "英语": 88}
# 错误:遍历时修改字典
for subject in scores:
if scores[subject] < 90:
del scores[subject] # RuntimeError
# 正确:先收集要删除的键,再删除
to_remove = [subject for subject in scores if scores[subject] < 90]
for subject in to_remove:
del scores[subject]
错误4:混淆赋值和copy()
original = {"语文": 95, "数学": 98}
# 错误:这只是创建了一个引用
copied = original
copied["英语"] = 88
print(original) # original也被修改了!
# 正确:使用copy()创建独立副本
copied = original.copy()
copied["英语"] = 88
print(original) # original不受影响
调试技巧
- 打印字典内容:
scores = {"语文": 95, "数学": 98}
print(scores) # 查看完整字典
- 检查键是否存在:
if "数学" in scores:
print("数学成绩存在")
- 使用type()检查类型:
print(type(scores)) # 确认是字典类型
给家长的小贴士:字典的错误通常比较隐蔽,建议在调试时多使用print()语句,逐步检查每一步的执行结果。
性能考虑
字典的查找速度
字典的查找速度非常快(O(1)),而列表的查找速度较慢(O(n))。
# 使用列表查找(慢)
students_list = ["小明", "小红", "小华", "小刚", "小李"]
if "小华" in students_list: # 需要逐个比较
print("找到了")
# 使用字典查找(快)
students_dict = {"小明": 1, "小红": 2, "小华": 3}
if "小华" in students_dict: # 直接找到
print("找到了")
什么时候考虑性能?
- 数据量很大时(比如超过1000个元素)
- 需要频繁查找时
- 对性能要求高的程序
给家长的小贴士:对于小学阶段的学习,性能不是重点,但了解这个知识点有助于培养良好的编程习惯。
字典的高级应用
使用字典作为缓存
# 斐波那契数列(带缓存)
cache = {}
def fib(n):
if n in cache:
return cache[n]
if n <= 1:
result = n
else:
result = fib(n-1) + fib(n-2)
cache[n] = result
return result
print(fib(100)) # 计算很快,因为有缓存
使用字典统计
# 统计单词词频
text = "hello world hello python world"
words = text.split()
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# 输出: {'hello': 2, 'world': 2, 'python': 1}
使用字典分组
# 按成绩分组
students = [
{"name": "小明", "score": 95},
{"name": "小红", "score": 87},
{"name": "小华", "score": 92}
]
# 按分数段分组
groups = {"优秀": [], "良好": [], "及格": []}
for student in students:
score = student["score"]
if score >= 90:
groups["优秀"].append(student["name"])
elif score >= 80:
groups["良好"].append(student["name"])
else:
groups["及格"].append(student["name"])
print(groups)
给家长的小贴士:这些高级应用可能比较复杂,可以让孩子先掌握基础,等有更多编程经验后再学习。
字典 vs 其他数据结构
| 数据结构 | 特点 | 适用场景 |
|---|---|---|
| 列表 | 有序、可重复 | 存储序列数据 |
| 元组 | 有序、不可变 | 固定不变的数据 |
| 集合 | 无序、唯一 | 去重、集合运算 |
| 字典 | 键值对 | 快速查找、关联数据 |
# 列表:购物清单
shopping_list = ["苹果", "香蕉", "橙子"]
# 元组:固定坐标
point = (10, 20)
# 集合:去重
numbers = {1, 2, 3, 2, 1} # {1, 2, 3}
# 字典:成绩表
scores = {"小明": 95, "小红": 98}
给家长的小贴士:让孩子理解不同数据结构的特点和适用场景,有助于选择合适的工具。
章节小结
核心知识点
-
字典的基本概念:
- 字典是键值对的集合
- 键必须是不可变类型且唯一
- 值可以是任意类型
-
字典与数学的关联 📊:
- 字典就像数学中的“映射“关系
- 键(key)相当于自变量 x
- 值(value)相当于因变量 y
- 字典表达了“一对一“的对应关系
-
字典为什么这么快? ⚡:
- 使用了哈希表技术
- 哈希函数把键转换成数字(类似取余数)
- 可以直接定位到存储位置,不需要一个个找
- 列表查找:O(n),字典查找:O(1)
-
字典的基本操作:
- 创建:
{}或dict() - 访问:
dict[key]或dict.get(key) - 添加:
dict[key] = value - 修改:
dict[key] = new_value - 删除:
del dict[key]或dict.pop(key)
- 创建:
-
字典的常用方法:
keys(): 获取所有键values(): 获取所有值items(): 获取所有键值对get(): 安全访问update(): 更新字典clear(): 清空字典
-
遍历字典:
- 遍历键:
for key in dict - 遍历值:
for value in dict.values() - 遍历键值对:
for key, value in dict.items()
- 遍历键:
-
嵌套字典:
- 字典的值可以是另一个字典
- 访问嵌套数据:
dict[key1][key2]
重要概念
- 字典的键必须是不可变类型(字符串、数字、元组)
- 字典的键必须唯一(就像数学函数中每个x只能对应一个y)
- 字典的查找速度很快(O(1)),因为使用了哈希表
- 字典适合存储有关联关系的数据
数学知识回顾 📐
通过本章,你复习了以下数学知识:
-
映射和函数:
- 理解“输入→输出“的对应关系
- 一一对应的概念
-
统计数据分析:
- 平均数、最大值、最小值
- 数据分组统计
-
单位换算:
- 长度、重量、温度换算
- 理解比例关系
-
找规律:
- 观察数列的变化趋势
- 发现函数关系式
计算机知识 💻
通过本章,你了解了以下计算机知识:
-
哈希表:
- 什么是哈希函数
- 为什么字典查找速度快
- 时间复杂度:O(1) vs O(n)
-
数据结构选择:
- 什么时候用列表
- 什么时候用字典
- 权衡速度和内存
挑战练习
挑战1:制作一个简单的游戏配置系统
创建一个游戏配置系统,可以设置和读取游戏参数(如难度、音量、玩家名称等)。
提示
使用字典存储配置信息,每个配置项是一个键值对。
挑战2:制作一个图书管理系统
创建一个图书管理系统,每本书包含:书名、作者、出版社、出版年份、价格等信息。支持添加、查找、删除、列出所有书籍等功能。
提示
使用嵌套字典,书名作为键,书的详细信息作为值。
挑战3:制作一个简单的投票统计系统
创建一个投票统计系统,可以统计多个候选人的得票数,并按票数排序显示结果。
提示
使用字典存储候选人姓名和票数,使用sorted()函数排序。
下一步
恭喜你完成了字典的学习!现在你已经掌握了:
✅ 列表(List)- 按顺序存储数据 ✅ 字典(Dictionary)- 按键值对存储数据
这两种数据结构是Python中最常用的数据存储方式。你已经理解了:
- 字典就像数学中的“映射“关系
- 字典使用哈希表技术,查找速度非常快
- 字典非常适合存储有关联关系的数据
本章与数学的联结 📊
通过字典,你其实已经在用编程的方式理解数学中的函数概念了!
在数学课上,你学过函数 y = f(x),这和字典的 “键→值” 是不是非常相似?
| 数学概念 | Python字典 |
|---|---|
| 自变量 x | 键(key) |
| 因变量 y | 值(value) |
| 函数 f(x) | 字典的映射 |
| 定义域 | 所有的键 |
| 值域 | 所有的值 |
下一章预告 🚀
下一章,我们将学习函数(Function)。
等等,函数不是数学里的概念吗?为什么编程里也有函数?
非常好的问题!编程中的函数和数学中的函数确实有很多相似之处:
- 它们都接收“输入“(参数)
- 它们都进行某种“处理“或“计算“
- 它们都产生“输出“(返回值)
但编程中的函数更强大,它可以:
- 让代码更简洁(不用重复写相同的代码)
- 让代码更清晰(把复杂问题分解成小问题)
- 让代码可重用(写一次,用多次)
你将学会:
- 如何定义自己的函数
- 函数的参数和返回值(就像数学函数的自变量和因变量)
- 如何用函数解决实际问题
继续加油,你正在成为一名优秀的程序员!🎉
第12章 函数
引言
想象一下,你在玩一个电子游戏。游戏中有一些特殊的动作,比如“跳跃“、“攻击”、“防守”。每次你需要做这些动作时,只需要按一个对应的按钮,游戏角色就会执行这个动作。你不需要每次都重新告诉电脑“抬起左腿、向前移动、放下左腿…“——所有这些复杂的步骤都已经被打包到“跳跃“这个按钮里了。
在Python中,也有这样一种机制,让我们可以把一段代码打包起来,给它起个名字,以后就可以通过这个名字重复使用这段代码。这就是函数(Function)。
你已经学过的函数!
其实,你早就在数学课上见过“函数“了!还记得数学里的函数吗?
比如,有一个数学函数:
f(x) = 2x + 1
当我们把x = 3代入这个函数时:
f(3) = 2 × 3 + 1 = 7
当我们把x = 5代入时:
f(5) = 2 × 5 + 1 = 11
你看,数学函数就是这么一个“规则“或“公式“,你给它一个输入值(x),它就按照固定的规则计算,给你一个输出值(结果)。
Python函数和数学函数非常相似!
- 数学函数:接收一个数,按公式计算,返回结果
- Python函数:接收一些数据,执行代码,返回结果
它们都有:
- 一个名字(比如f、g、draw_square)
- 输入(参数)
- 处理过程(计算或代码)
- 输出(返回值)
给家长的小贴士:
- 如果孩子已经学过数学函数,可以用数学函数作为类比,这样孩子会更容易理解Python函数的概念
- 如果孩子还没学过数学函数,可以用“遥控器按钮“、“快捷指令”、“预设程序“等生活中的例子来类比函数
- 重点强调“输入→处理→输出“这个模式,这是所有函数的核心特征
为什么需要函数
问题:重复的代码
在学习循环语句时,我们用turtle画过很多图形。现在让我们画一个正方形:
import turtle
t = turtle.Pen()
# 画一个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
运行这段代码,会在屏幕上画出一个边长为100的正方形。
现在,如果我们要画两个正方形呢?
import turtle
t = turtle.Pen()
# 画第一个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 移动到新位置
t.penup()
t.goto(150, 0)
t.pendown()
# 画第二个正方形
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
你注意到什么问题了吗?画正方形的代码重复了两次!如果我们要画10个正方形,难道要复制粘贴10次吗?
解决方案:使用函数
函数可以帮我们解决这个问题。我们可以把“画正方形“的代码打包成一个函数:
import turtle
t = turtle.Pen()
# 定义一个画正方形的函数
def draw_square():
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 使用函数画第一个正方形
draw_square()
# 移动到新位置
t.penup()
t.goto(150, 0)
t.pendown()
# 使用函数画第二个正方形
draw_square()
turtle.done()
现在代码变得简洁多了!我们只需要调用draw_square()函数,就可以画出一个正方形。
给家长的小贴士:强调函数的两个主要好处:1)避免重复代码;2)让代码更易读、易维护。可以告诉孩子,如果以后想修改正方形的画法,只需要修改函数定义,而不需要修改每一处调用的地方。
函数的基本概念
什么是函数
函数是一个可以重复使用的代码块,它有一个名字,当我们需要使用这段代码时,只需要调用这个名字。
数学函数 vs Python函数
让我们对比一下数学函数和Python函数:
数学函数示例:
f(x) = x² (平方函数)
g(x, y) = x + y (加法函数)
对应的Python函数:
def f(x):
return x * x
def g(x, y):
return x + y
你看,它们的结构几乎一样!
| 数学函数 | Python函数 | 说明 |
|---|---|---|
| f(x) = x² | def f(x): return x * x | 函数名是f,参数是x |
| g(a, b) = a + b | def g(a, b): return a + b | 函数名是g,有两个参数a和b |
| y = f(3) | y = f(3) | 调用函数,传入参数3 |
定义函数的语法
def 函数名(参数1, 参数2, ...):
函数体(要执行的代码)
return 返回值
让我们分解这个语法:
def:这是Python的关键字,告诉计算机“我要定义一个函数了“(就像数学课上说“设f(x) = …“一样)函数名:给函数起的名字,命名规则和变量名一样(数学里常用f、g、h,Python里常用有意义的名字)(参数1, 参数2, ...):圆括号,里面可以放参数(就像数学函数f(x)中的x)::冒号,表示函数定义的开始函数体:缩进的代码块,是函数要执行的内容(就像数学公式中的计算规则)return:返回计算结果(就像数学函数计算出结果)
从数学函数到Python函数
让我们把一些常见的数学函数转换成Python代码:
示例1:绝对值函数
数学中的绝对值函数:
f(x) = |x|
Python实现:
def absolute_value(x):
"""计算x的绝对值(对应数学函数 f(x) = |x|)"""
if x >= 0:
return x
else:
return -x
# 测试
print(absolute_value(5)) # 输出: 5
print(absolute_value(-5)) # 输出: 5
print(absolute_value(0)) # 输出: 0
示例2:简单线性函数
数学函数:
f(x) = 2x + 3
Python实现:
def linear_function(x):
"""计算2x + 3(线性函数)"""
return 2 * x + 3
# 测试
print(linear_function(1)) # 输出: 5 (2×1+3=5)
print(linear_function(5)) # 输出: 13 (2×5+3=13)
print(linear_function(0)) # 输出: 3 (2×0+3=3)
给家长的数学提示:
- 绝对值函数| x |是小学高年级数学的内容,表示一个数到0的距离
- 线性函数 f(x) = ax + b 的形式也很适合作为入门例子
- 可以鼓励孩子用Python验证他们学过的数学计算
一个简单的例子
# 定义一个打招呼的函数
def say_hello():
print("你好!")
print("欢迎来到Python世界!")
print("让我们一起学习编程吧!")
# 调用函数
say_hello()
print("-----分隔线-----")
# 再次调用函数
say_hello()
输出:
你好!
欢迎来到Python世界!
让我们一起学习编程吧!
-----分隔线-----
你好!
欢迎来到Python世界!
让我们一起学习编程吧!
给家长的小贴士:解释函数的“定义“和“调用“是两个不同的步骤。定义函数就像是在编写一本“操作手册“或数学公式,而调用函数就像是按照手册执行操作或代入数值计算。定义函数时,代码不会立即执行,只有调用时才会执行。
函数的参数
问题:函数太死板
现在我们有了一个画正方形的函数:
import turtle
t = turtle.Pen()
def draw_square():
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
# 在不同位置画正方形
draw_square()
t.penup()
t.goto(150, 0)
t.pendown()
draw_square()
turtle.done()
这个函数有一个问题:它只能画边长为100的正方形。如果我们想画不同大小的正方形怎么办?
解决方案:带参数的函数
我们可以给函数添加参数,让函数更灵活:
import turtle
t = turtle.Pen()
def draw_square(size):
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
# 画一个边长为50的正方形
draw_square(50)
# 移动位置
t.penup()
t.goto(100, 0)
t.pendown()
# 画一个边长为100的正方形
draw_square(100)
# 移动位置
t.penup()
t.goto(250, 0)
t.pendown()
# 画一个边长为150的正方形
draw_square(150)
turtle.done()
现在draw_square()函数可以根据传入的参数画出不同大小的正方形了!
什么是参数
参数就像是函数的“输入“,让我们可以向函数传递信息。
数学函数的参数:
f(x) = 2x + 1
↑
参数(自变量)
当我们说f(5)时,5就是传入参数的值。
Python函数的参数:
def double(x): # x是参数(形参)
return 2 * x
result = double(5) # 5是实参
- 参数(Parameter/形参):函数定义时括号里的变量名(就像数学函数中的x)
- 实参(Argument):调用函数时传入的实际值(就像代入x的具体数值)
def draw_square(size): # size是参数(形参)
t.forward(size)
t.left(90)
...
draw_square(100) # 100是实参
数学练习:理解参数
让我们通过数学练习来理解参数的概念:
练习1:理解函数调用
数学函数: f(x) = x²
如果我们计算:
- f(2) = 4
- f(5) = 25
- f(10) = 100
这里2、5、10都是“实参“,x是“参数“(形参)
对应的Python代码:
def square(x): # x是参数
return x * x
print(square(2)) # 输出: 4
print(square(5)) # 输出: 25
print(square(10)) # 输出: 100
练习2:多参数函数
数学函数: f(x, y) = x + y
计算:
- f(3, 5) = 8
- f(10, 20) = 30
对应的Python代码:
def add(x, y):
return x + y
print(add(3, 5)) # 输出: 8
print(add(10, 20)) # 输出: 30
多个参数
函数可以有多个参数,用逗号分隔:
import turtle
t = turtle.Pen()
def draw_rectangle(width, height):
"""画一个矩形"""
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
# 画不同大小的矩形
draw_rectangle(100, 50)
t.penup()
t.goto(150, 0)
t.pendown()
draw_rectangle(50, 100)
turtle.done()
位置参数
当我们调用函数时,实参会按照位置对应到参数:
def greet(name, age):
print(f"你好,我叫{name},今年{age}岁")
# 第一个值对应name,第二个值对应age
greet("小明", 12) # 输出: 你好,我叫小明,今年12岁
# 如果顺序错了,结果也会错
greet(12, "小明") # 输出: 你好,我叫12,今年小明岁(错了!)
给家长的小贴士:可以用“快递包裹“来类比参数。快递单上有“寄件人“、“收件人”、“地址“等字段(参数),填写快递单时需要把具体信息(实参)填入对应的字段。
练习:为函数添加颜色参数
我们可以让画正方形的函数支持颜色选择:
import turtle
t = turtle.Pen()
def draw_colored_square(size, color):
"""画一个指定大小和颜色的正方形"""
t.color(color) # 设置颜色
t.begin_fill() # 开始填充
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.forward(size)
t.left(90)
t.end_fill() # 结束填充
# 画不同颜色的正方形
draw_colored_square(100, "red")
t.penup()
t.goto(120, 0)
t.pendown()
draw_colored_square(100, "blue")
t.penup()
t.goto(240, 0)
t.pendown()
draw_colored_square(100, "green")
turtle.done()
练习:画一排正方形
结合循环,我们可以画一排正方形:
import turtle
t = turtle.Pen()
t.speed(0) # 设置最快速度
def draw_square(size, color):
"""画一个正方形"""
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
# 画一排正方形
colors = ["red", "orange", "yellow", "green", "blue"]
for i in range(5):
draw_square(50, colors[i])
t.penup()
t.forward(70)
t.pendown()
turtle.done()
默认参数
什么需要默认参数
有时候,我们希望函数的某些参数有默认值。这样,调用函数时如果不提供这个参数,就会使用默认值。
import turtle
t = turtle.Pen()
def draw_square(size, color="red"):
"""画正方形,默认颜色是红色"""
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
# 不指定颜色,使用默认的红色
draw_square(100)
t.penup()
t.goto(120, 0)
t.pendown()
# 指定颜色为蓝色
draw_square(100, "blue")
turtle.done()
默认参数的规则
- 默认参数必须在非默认参数之后
- 调用函数时,可以只给部分参数赋值
# 错误的例子
def draw_square(color="red", size): # 错误!默认参数在后面
...
# 正确的例子
def draw_square(size, color="red"): # 正确!
...
# 调用时可以只给第一个参数
draw_square(100) # color使用默认值"red"
给家长的小贴士:可以用“订购商品“来类比默认参数。比如订购pizza时,默认配料是芝士,但你可以选择添加其他配料。
函数的返回值
什么是返回值
数学函数的返回值:
f(x) = x²
f(3) = 9 ← 9就是返回值(因变量)
在数学中,我们把函数计算的结果叫做“函数值“或“因变量“。
Python函数的返回值:
到目前为止,我们的函数都是执行某些操作(画图、打印等)。但有时,我们希望函数能够“返回“一个结果,让我们可以在程序中使用这个结果。这就像数学函数计算出一个数值一样。
# 计算矩形的面积(对应数学函数 A = w × h)
def calculate_area(width, height):
area = width * height
return area # 返回计算结果,就像数学函数得出答案
# 调用函数并获取返回值
result = calculate_area(10, 5)
print(f"矩形的面积是: {result}")
return语句:数学函数的“=“号
在数学函数中,我们用“=“号表示结果:
f(x) = 2x + 1
f(3) = 7 ← 计算结果是7
在Python中,我们用return语句返回结果:
def f(x):
return 2 * x + 1 # 返回计算结果
result = f(3) # result的值是7
可以把return理解为数学中的“等于“——它告诉Python:“这个函数的值是xxx”。
从数学公式到Python函数
让我们把一些常见的数学公式转换成Python函数:
示例1:矩形面积公式
数学公式: A = 长 × 宽
def rectangle_area(length, width):
"""计算矩形面积 A = l × w"""
return length * width
# 测试
print(rectangle_area(10, 5)) # 输出: 50
print(rectangle_area(8, 3)) # 输出: 24
示例2:矩形周长公式
数学公式: P = 2 × (长 + 宽)
def rectangle_perimeter(length, width):
"""计算矩形周长 P = 2(l + w)"""
return 2 * (length + width)
# 测试
print(rectangle_perimeter(10, 5)) # 输出: 30
print(rectangle_perimeter(8, 3)) # 输出: 22
示例3:三角形面积公式(海伦公式)
数学公式: A = √[s(s-a)(s-b)(s-c)] 其中 s = (a+b+c)/2
import math
def triangle_area(a, b, c):
"""用海伦公式计算三角形面积"""
s = (a + b + c) / 2 # 半周长
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
return area
# 测试:边长为3, 4, 5的三角形(直角三角形)
print(triangle_area(3, 4, 5)) # 输出: 6.0 (应该是6,因为3×4÷2=6)
示例4:圆的面积和周长
数学公式:
- 面积: A = πr²
- 周长: C = 2πr
import math
def circle_area(radius):
"""计算圆的面积 A = πr²"""
return math.pi * radius * radius
def circle_circumference(radius):
"""计算圆的周长 C = 2πr"""
return 2 * math.pi * radius
# 测试:半径为5的圆
r = 5
print(f"半径为{r}的圆:")
print(f" 面积: {circle_area(r):.2f}")
print(f" 周长: {circle_circumference(r):.2f}")
给家长的数学提示:
- 这些公式都是小学高年级或初中数学的内容
- 可以让孩子先用数学方法手工计算,再用Python验证
- 海伦公式可能比较难,可以根据孩子的情况决定是否讲解
- 圆周率π用
math.pi表示,这是Python数学库提供的精确值
返回值的使用
返回值可以像普通变量一样使用:
def calculate_rectangle_area(width, height):
return width * height
def calculate_circle_area(radius):
return 3.14 * radius * radius
# 比较两个面积
rectangle = calculate_rectangle_area(10, 5)
circle = calculate_circle_area(5)
print(f"矩形面积: {rectangle}")
print(f"圆形面积: {circle:.2f}")
if rectangle > circle:
print("矩形的面积更大")
else:
print("圆形的面积更大")
多个返回值
函数可以返回多个值:
def calculate(width, height):
"""计算矩形的面积和周长"""
area = width * height
perimeter = 2 * (width + height)
return area, perimeter
# 接收多个返回值
a, p = calculate(10, 5)
print(f"面积: {a}, 周长: {p}")
给家长的小贴士:可以用“自动售货机“来类比返回值。你投入硬币(参数),按下按钮(调用函数),机器会“返回“商品(返回值)。
练习:温度转换函数
def celsius_to_fahrenheit(celsius):
"""将摄氏度转换为华氏度"""
fahrenheit = celsius * 9/5 + 32
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
"""将华氏度转换为摄氏度"""
celsius = (fahrenheit - 32) * 5/9
return celsius
# 测试函数
temp_c = 25
temp_f = celsius_to_fahrenheit(temp_c)
print(f"{temp_c}°C = {temp_f}°F")
temp_f = 77
temp_c = fahrenheit_to_celsius(temp_f)
print(f"{temp_f}°F = {temp_c:.1f}°C")
变量的作用域
局部变量
在函数内部定义的变量叫做局部变量,它们只能在函数内部使用:
def my_function():
local_var = 10 # 局部变量
print(f"函数内部: local_var = {local_var}")
my_function() # 输出: 函数内部: local_var = 10
# 下面这行会报错!
# print(local_var) # NameError: name 'local_var' is not defined
全局变量
在函数外部定义的变量叫做全局变量,它们可以在整个程序中使用:
global_var = 100 # 全局变量
def my_function():
print(f"函数内部可以访问: global_var = {global_var}")
my_function() # 输出: 函数内部可以访问: global_var = 100
print(f"函数外部也可以访问: global_var = {global_var}")
全局变量和局部变量的同名
如果全局变量和局部变量同名,局部变量会“遮蔽“全局变量:
x = 10 # 全局变量
def my_function():
x = 20 # 局部变量,不影响全局变量
print(f"函数内部: x = {x}")
my_function() # 输出: 函数内部: x = 20
print(f"函数外部: x = {x}") # 输出: 函数外部: x = 10
在函数中修改全局变量
如果想在函数中修改全局变量,需要使用global关键字:
x = 10 # 全局变量
def modify_global():
global x # 声明要使用全局变量x
x = 20
print(f"函数内部修改后: x = {x}")
print(f"修改前: x = {x}") # 输出: 修改前: x = 10
modify_global() # 输出: 函数内部修改后: x = 20
print(f"修改后: x = {x}") # 输出: 修改后: x = 20
给家长的小贴士:作用域是一个比较抽象的概念。可以用“家里的房间“来类比:每个房间(函数)都有自己的私人物品(局部变量),但客厅(全局区域)的物品大家都可以用。
函数的文档字符串
什么是文档字符串
文档字符串(Docstring)是用来说明函数功能的注释,放在函数定义的第一行:
def calculate_area(width, height):
"""
计算矩形的面积
参数:
width: 矩形的宽度
height: 矩形的高度
返回:
矩形的面积
"""
return width * height
查看文档字符串
可以使用help()函数查看文档字符串:
def greet(name):
"""向指定的人打招呼"""
print(f"你好, {name}!")
# 查看文档字符串
help(greet)
输出:
Help on function greet in module __main__:
greet(name)
向指定的人打招呼
给家长的小贴士:教导孩子养成写文档字符串的好习惯,这就像给函数写“使用说明书“,以后自己或别人使用这个函数时,就能快速了解它的功能。
函数的高级应用
画花朵图案
让我们用函数画一个美丽的花朵图案:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_petal(size, angle):
"""画一个花瓣"""
for i in range(2):
t.circle(size, angle)
t.left(180 - angle)
def draw_flower(x, y, size, petal_count, color):
"""在指定位置画一朵花"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
# 画花瓣
for i in range(petal_count):
draw_petal(size, 60)
t.left(360 / petal_count)
t.end_fill()
# 画不同的花朵
draw_flower(-100, 100, 50, 6, "red")
draw_flower(100, 100, 40, 8, "yellow")
draw_flower(0, -100, 60, 10, "purple")
turtle.done()
画N角星
编写一个函数,可以画任意角数的星:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_star(x, y, size, points, color, angle=None):
"""
画一个N角星
参数:
x, y: 位置
size: 大小
points: 角的数量
color: 颜色
angle: 旋转角度(可选)
"""
t.penup()
t.goto(x, y)
t.pendown()
if angle is not None:
t.right(angle)
t.color(color)
t.begin_fill()
# 计算角度
if points == 5:
exterior_angle = 144
else:
exterior_angle = 180 - 180 / points
for i in range(points):
t.forward(size)
t.right(exterior_angle)
t.end_fill()
# 画不同的星星
draw_star(-100, 100, 100, 5, "yellow", 0) # 五角星
draw_star(100, 100, 80, 6, "red", 30) # 六角星
draw_star(0, -100, 120, 8, "blue", 45) # 八角星
turtle.done()
递归函数
什么是递归
递归是指函数调用自身。听起来很奇怪,但这是一个非常强大的编程技巧。
递归就像数学归纳法
如果你学过数学归纳法,递归的概念就很相似了:
数学归纳法证明:
- 基准情况:证明当n=1时命题成立
- 归纳假设:假设当n=k时命题成立
- 归纳递推:证明当n=k+1时命题也成立
递归函数:
- 基准情况:最简单的情况,直接返回结果
- 递归调用:调用自身解决更小的问题
- 递归推进:每次调用要朝着基准情况前进
递归的要素
编写递归函数时,必须注意以下几点:
- 必须有退出条件(基准情况)
- 每次调用时,参数要发生变化
- 参数变化要朝着退出条件的方向进行
递归示例1:阶乘
数学定义:
n! = n × (n-1) × (n-2) × ... × 2 × 1
递归定义:
n! = n × (n-1)! (当n > 1时)
1! = 1 (基准情况)
比如:
- 5! = 5 × 4!
- 4! = 4 × 3!
- 3! = 3 × 2!
- 2! = 2 × 1!
- 1! = 1 (基准情况)
Python实现:
def factorial(n):
"""计算n的阶乘 n!"""
# 退出条件(基准情况)
if n == 1:
return 1
# 递归调用
return n * factorial(n - 1)
# 测试
print(factorial(5)) # 输出: 120
print(factorial(4)) # 输出: 24
print(factorial(1)) # 输出: 1
让我们追踪一下factorial(5)的执行过程:
factorial(5)
= 5 * factorial(4)
= 5 * (4 * factorial(3))
= 5 * (4 * (3 * factorial(2)))
= 5 * (4 * (3 * (2 * factorial(1))))
= 5 * (4 * (3 * (2 * 1))) ← 到达基准情况!
= 5 * (4 * (3 * 2))
= 5 * (4 * 6)
= 5 * 24
= 120
递归示例2:求和
数学定义: 计算1到n的和:
S(n) = 1 + 2 + 3 + ... + n
递归定义:
S(n) = n + S(n-1) (当n > 1时)
S(1) = 1 (基准情况)
Python实现:
def sum_to_n(n):
"""递归计算1到n的和"""
# 退出条件
if n == 1:
return 1
# 递归调用
return n + sum_to_n(n - 1)
# 测试
print(sum_to_n(5)) # 输出: 15 (1+2+3+4+5)
print(sum_to_n(10)) # 输出: 55
数学验证: 可以用等差数列求和公式验证:
S(n) = n(n+1)/2
S(10) = 10×11/2 = 55 ✓
Python验证:
def sum_formula(n):
"""用公式计算1到n的和: S = n(n+1)/2"""
return n * (n + 1) // 2
print(sum_formula(10)) # 输出: 55
递归示例3:斐波那契数列
数学背景:
斐波那契数列是一个著名的数学数列,它在自然界中随处可见(比如花朵的花瓣数、蜗牛的壳纹等)。
数列是这样的:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
递归定义:
F(n) = F(n-1) + F(n-2) (当n > 2时)
F(1) = 1 (基准情况)
F(2) = 1 (基准情况)
规律是:每个数都是前两个数之和。
比如:
- F(3) = F(2) + F(1) = 1 + 1 = 2
- F(4) = F(3) + F(2) = 2 + 1 = 3
- F(5) = F(4) + F(3) = 3 + 2 = 5
Python实现:
def fibonacci(n):
"""计算斐波那契数列的第n项"""
# 退出条件
if n == 1 or n == 2:
return 1
# 递归调用
return fibonacci(n - 1) + fibonacci(n - 2)
# 打印前10项
for i in range(1, 11):
print(fibonacci(i), end=" ")
# 输出: 1 1 2 3 5 8 13 21 34 55
数学小知识:
- 斐波那契数列的相邻两项比值会越来越接近“黄金比例“φ ≈ 1.618
- F(n+1)/F(n) ≈ 1.618 (当n很大时)
让我们验证一下:
def fibonacci(n):
if n == 1 or n == 2:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)
# 计算比值
for i in range(5, 16):
ratio = fibonacci(i + 1) / fibonacci(i)
print(f"F({i+1})/F({i}) = {ratio:.6f}")
递归示例:画分形树
import turtle
t = turtle.Pen()
t.speed(0)
t.left(90)
def draw_tree(branch_length, pen_size):
"""画分形树"""
if branch_length < 10:
return
# 设置画笔粗细
t.pensize(pen_size)
# 画树干
t.forward(branch_length)
# 画右边的树枝
t.right(20)
draw_tree(branch_length * 0.7, pen_size * 0.7)
# 画左边的树枝
t.left(40)
draw_tree(branch_length * 0.7, pen_size * 0.7)
# 回到树干
t.right(20)
t.penup()
t.backward(branch_length)
t.pendown()
# 画树
draw_tree(100, 10)
turtle.done()
给家长的小贴士:递归是一个比较难理解的概念。可以用“俄罗斯套娃“或“照镜子“来类比。提醒孩子,递归必须有退出条件,否则会陷入无限循环(就像程序里跑进了一个永远出不去的迷宫)。如果孩子学过数学归纳法,可以用数学归纳法来类比递归的思想。
数学函数练习
让我们通过一些数学练习来巩固函数的概念!
练习1:最大值函数
编写一个函数,找出两个数中的最大值。
数学定义:
max(a, b) = a (如果 a ≥ b)
max(a, b) = b (如果 a < b)
查看答案
def maximum(a, b):
"""返回两个数中的最大值"""
if a >= b:
return a
else:
return b
# 测试
print(maximum(5, 3)) # 输出: 5
print(maximum(2, 8)) # 输出: 8
print(maximum(4, 4)) # 输出: 4
练习2:最小公倍数(LCM)
编写一个函数,计算两个数的最小公倍数。
数学背景: 最小公倍数是能够被这两个数整除的最小的正整数。
比如:
- LCM(4, 6) = 12 (12能被4和6整除)
- LCM(3, 5) = 15 (15能被3和5整除)
公式:
LCM(a, b) = (a × b) / GCD(a, b)
其中GCD是最大公约数。
查看答案
def gcd(a, b):
"""计算最大公约数(欧几里得算法)"""
while b != 0:
a, b = b, a % b
return a
def lcm(a, b):
"""计算最小公倍数"""
return (a * b) // gcd(a, b)
# 测试
print(f"LCM(4, 6) = {lcm(4, 6)}") # 输出: 12
print(f"LCM(3, 5) = {lcm(3, 5)}") # 输出: 15
print(f"LCM(12, 18) = {lcm(12, 18)}") # 输出: 36
练习3:判断素数
编写一个函数,判断一个数是否为素数。
数学背景: 素数是只能被1和它本身整除的大于1的正整数。
比如:2, 3, 5, 7, 11, 13, 17, 19, …
查看答案
def is_prime(n):
"""判断n是否为素数"""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
# 只需要检查到√n
i = 3
while i * i <= n:
if n % i == 0:
return False
i += 2
return True
# 测试
for i in range(1, 21):
if is_prime(i):
print(i, end=" ")
# 输出: 2 3 5 7 11 13 17 19
给家长的数学提示:
- 最大公约数可以用欧几里得算法计算,这是一个经典的算法
- 判断素数时,只需要检查到√n,因为如果n有因数,必然有一个≤√n
- 这些练习可以帮孩子复习数学概念,同时学习Python编程
练习4:摄氏度和华氏度转换
编写两个函数,实现温度单位转换。
数学公式:
- 摄氏度转华氏度: F = C × 9/5 + 32
- 华氏度转摄氏度: C = (F - 32) × 5/9
查看答案
def celsius_to_fahrenheit(c):
"""摄氏度转华氏度: F = C × 9/5 + 32"""
return c * 9/5 + 32
def fahrenheit_to_celsius(f):
"""华氏度转摄氏度: C = (F - 32) × 5/9"""
return (f - 32) * 5/9
# 测试
print(f"25°C = {celsius_to_fahrenheit(25):.1f}°F") # 输出: 77.0°F
print(f"77°F = {fahrenheit_to_celsius(77):.1f}°C") # 输出: 25.0°C
# 常见温度对比
print(f"\n水的冰点: 0°C = {celsius_to_fahrenheit(0)}°F")
print(f"水的沸点: 100°C = {celsius_to_fahrenheit(100)}°F")
print(f"人体体温: 37°C = {celsius_to_fahrenheit(37):.1f}°F")
练习5:计算平均数
编写一个函数,计算列表中所有数的平均数。
数学公式:
平均值 = (所有数的和) / (数的个数)
查看答案
def calculate_average(numbers):
"""计算平均数"""
if len(numbers) == 0:
return 0
return sum(numbers) / len(numbers)
# 测试
scores = [85, 92, 78, 95, 88]
average = calculate_average(scores)
print(f"平均分: {average:.1f}")
# 另一个例子
heights = [1.65, 1.72, 1.68, 1.75, 1.70]
avg_height = calculate_average(heights)
print(f"平均身高: {avg_height:.2f}米")
练习6:幂函数
编写一个递归函数,计算x的n次方。
数学定义:
xⁿ = x × x × ... × x (共n个x相乘)
递归定义:
xⁿ = x × xⁿ⁻¹ (当n > 0时)
x⁰ = 1 (基准情况)
查看答案
def power(x, n):
"""计算x的n次方"""
if n == 0:
return 1
return x * power(x, n - 1)
# 测试
print(f"2³ = {power(2, 3)}") # 输出: 8
print(f"3⁴ = {power(3, 4)}") # 输出: 81
print(f"5⁰ = {power(5, 0)}") # 输出: 1
# 验证:用Python的**运算符
print(f"\n验证:")
print(f"2**10 = {power(2, 10)}") # 输出: 1024
print(f"10**3 = {power(10, 3)}") # 输出: 1000
实践练习
练习1:基本函数
编写一个函数,接收一个名字作为参数,打印出“你好,[名字]!“
查看答案
def greet(name):
print(f"你好,{name}!")
greet("小明")
greet("小红")
练习2:带参数的函数
编写一个函数,接收三个参数:宽、高和颜色,画出一个填充的矩形。
查看答案
import turtle
t = turtle.Pen()
def draw_rectangle(width, height, color):
t.color(color)
t.begin_fill()
for i in range(2):
t.forward(width)
t.left(90)
t.forward(height)
t.left(90)
t.end_fill()
draw_rectangle(100, 50, "red")
练习3:带返回值的函数
编写一个函数,接收一个数字作为参数,返回这个数字的平方。
查看答案
def square(x):
return x * x
result = square(5)
print(result) # 输出: 25
练习4:多个返回值
编写一个函数,接收一个矩形的宽和高,返回矩形的面积和周长。
查看答案
def rectangle_info(width, height):
area = width * height
perimeter = 2 * (width + height)
return area, perimeter
a, p = rectangle_info(10, 5)
print(f"面积: {a}, 周长: {p}")
练习5:默认参数
编写一个函数,画一个正六边形,默认边长为50,默认颜色为蓝色。
查看答案
import turtle
t = turtle.Pen()
def draw_hexagon(size=50, color="blue"):
t.color(color)
t.begin_fill()
for i in range(6):
t.forward(size)
t.left(60)
t.end_fill()
# 使用默认值
draw_hexagon()
t.penup()
t.goto(100, 0)
t.pendown()
# 使用自定义值
draw_hexagon(80, "red")
turtle.done()
练习6:画螺旋图案
编写一个函数,画一个螺旋图案。
查看答案
import turtle
t = turtle.Pen()
t.speed(0)
def draw_spiral(lines, length, angle, increment):
"""画螺旋图案"""
for i in range(lines):
t.forward(length + i * increment)
t.left(angle)
draw_spiral(50, 5, 90, 2)
turtle.done()
练习7:计算器函数
编写一个计算器函数,接收三个参数:第一个数字、操作符、第二个数字,返回计算结果。
查看答案
def calculate(num1, operator, num2):
if operator == "+":
return num1 + num2
elif operator == "-":
return num1 - num2
elif operator == "*":
return num1 * num2
elif operator == "/":
if num2 != 0:
return num1 / num2
else:
return "错误:除数不能为0"
else:
return "错误:不支持的操作符"
# 测试
print(calculate(10, "+", 5)) # 输出: 15
print(calculate(10, "-", 5)) # 输出: 5
print(calculate(10, "*", 5)) # 输出: 50
print(calculate(10, "/", 5)) # 输出: 2.0
练习8:递归求和
编写一个递归函数,计算从1到n的和。
查看答案
def sum_to_n(n):
"""递归计算1到n的和"""
# 退出条件
if n == 1:
return 1
# 递归调用
return n + sum_to_n(n - 1)
print(sum_to_n(5)) # 输出: 15 (1+2+3+4+5)
print(sum_to_n(10)) # 输出: 55
练习9:递归幂运算
编写一个递归函数,计算x的n次方。
查看答案
def power(x, n):
"""递归计算x的n次方"""
# 退出条件
if n == 0:
return 1
# 递归调用
return x * power(x, n - 1)
print(power(2, 3)) # 输出: 8 (2*2*2)
print(power(3, 4)) # 输出: 81 (3*3*3*3)
练习10:画多彩图案
编写一个函数,画一个多彩的圆形图案。
查看答案
import turtle
t = turtle.Pen()
t.speed(0)
turtle.bgcolor("black")
colors = ["red", "yellow", "blue", "green", "orange", "purple"]
def draw_colorful_circle(size, colors):
"""画多彩圆形图案"""
for i in range(len(colors)):
t.color(colors[i])
t.begin_fill()
t.circle(size)
t.end_fill()
t.left(360 / len(colors))
draw_colorful_circle(100, colors)
turtle.done()
综合项目:图形绘制系统
结合所学的知识,创建一个图形绘制系统:
import turtle
t = turtle.Pen()
t.speed(0)
def draw_square(size, color, x=0, y=0):
"""画正方形"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(4):
t.forward(size)
t.left(90)
t.end_fill()
def draw_triangle(size, color, x=0, y=0):
"""画三角形"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(3):
t.forward(size)
t.left(120)
t.end_fill()
def draw_circle(radius, color, x=0, y=0):
"""画圆形"""
t.penup()
t.goto(x, y - radius)
t.pendown()
t.color(color)
t.begin_fill()
t.circle(radius)
t.end_fill()
def draw_star(size, color, x=0, y=0):
"""画五角星"""
t.penup()
t.goto(x, y)
t.pendown()
t.color(color)
t.begin_fill()
for i in range(5):
t.forward(size)
t.right(144)
t.end_fill()
# 使用函数绘制图案
def draw_house():
"""画房子"""
# 房子主体
draw_square(100, "brown", -50, -50)
# 屋顶
draw_triangle(120, "red", -60, 50)
# 门
draw_square(30, "yellow", -15, -50)
# 窗户
draw_square(20, "lightblue", -40, -20)
draw_square(20, "lightblue", 20, -20)
def draw_flower_garden():
"""画花园"""
flowers = [
(-100, -100, "red"),
(-50, -120, "yellow"),
(0, -100, "purple"),
(50, -120, "pink"),
(100, -100, "orange")
]
for x, y, color in flowers:
draw_star(20, color, x, y)
def draw_scene():
"""画完整场景"""
# 画天空
draw_circle(50, "yellow", -150, 150) # 太阳
# 画房子
draw_house()
# 画花园
draw_flower_garden()
# 绘制场景
draw_scene()
turtle.done()
章节小结
核心知识点
-
函数的基本概念:
- 函数是可重复使用的代码块
- Python函数和数学函数非常相似
- 都有:名字、参数、处理过程、返回值
- 定义函数使用
def关键字,调用函数使用函数名和括号
-
数学函数 vs Python函数:
- 数学函数: f(x) = x²
- Python函数: def f(x): return x * x
- 参数就像数学函数的自变量
- 返回值就像数学函数的因变量/函数值
-
函数的参数:
- 参数让函数更灵活
- 可以有多个参数
- 可以设置默认参数值
- 实参按位置对应到参数(像代入数学函数的数值)
-
函数的返回值:
- 使用
return语句返回值(类似数学函数计算结果) - 返回值可以在程序中使用
- 可以返回多个值
- 可以把数学公式转换成Python函数
- 使用
-
变量的作用域:
- 局部变量:函数内部定义,只在函数内有效
- 全局变量:函数外部定义,在整个程序有效
- 使用
global关键字修改全局变量
-
递归函数:
- 函数调用自身(类似数学归纳法)
- 必须有退出条件(基准情况)
- 每次调用参数要变化
- 常见应用:阶乘、斐波那契数列、求和
-
文档字符串:
- 用来说明函数功能
- 使用
help()查看
数学知识回顾
本章涉及的重要数学概念:
- 函数概念:输入→处理→输出
- 绝对值: |x|
- 线性函数: f(x) = ax + b
- 几何公式:矩形面积/周长、圆面积/周长、三角形面积
- 阶乘: n! = n × (n-1) × … × 1
- 等差数列求和: S(n) = n(n+1)/2
- 斐波那契数列: F(n) = F(n-1) + F(n-2)
- 最大公约数和最小公倍数
- 素数判断
- 温度转换公式
重要概念
- 函数提高了代码的复用性
- 函数让代码更易读、易维护
- 参数是函数的输入(像数学函数的自变量)
- 返回值是函数的输出(像数学函数的因变量)
- 递归必须有退出条件(基准情况)
- Python函数是数学函数在编程中的实现
- 可以用Python验证和探索数学概念
常见错误和调试
错误1:忘记定义函数
# 错误:直接调用未定义的函数
draw_square()
# 正确:先定义,再调用
def draw_square():
...
draw_square()
错误2:参数数量不匹配
def greet(name, age):
print(f"我叫{name},{age}岁")
# 错误:参数数量不对
greet("小明") # TypeError: greet() missing 1 required positional argument
# 正确:提供所有参数
greet("小明", 12)
错误3:混淆定义和调用
# 错误:忘记括号
def greet():
print("你好")
greet # 这只是函数名,不会调用
# 正确:使用括号调用
greet() # 这才是调用函数
错误4:递归没有退出条件
# 错误:没有退出条件,会导致无限递归
def count_down(n):
print(n)
count_down(n - 1)
count_down(5) # 最终会报错:RecursionError
# 正确:添加退出条件
def count_down(n):
print(n)
if n > 1: # 退出条件
count_down(n - 1)
调试技巧
- 打印调试:
def my_function(x):
print(f"函数收到参数: {x}") # 检查参数
result = x * 2
print(f"函数计算结果: {result}") # 检查结果
return result
- 检查返回值:
result = my_function(5)
print(f"返回值是: {result}")
- 使用
type()检查类型:
print(type(result)) # 确认返回值类型
给家长的小贴士:函数的错误通常比较隐蔽,建议在调试时多使用print()语句,逐步检查函数的执行过程。
挑战练习
挑战1:改进画图函数
改进前面的图形绘制系统,添加更多图形(如菱形、六边形等),并让函数支持边框颜色和填充颜色分开设置。
提示
可以添加参数,如fill_color和border_color。
挑战2:编写成绩等级函数
编写一个函数,接收分数作为参数,返回等级(A/B/C/D/F)。
提示
使用条件语句判断分数范围。
挑战3:递归画图
编写一个递归函数,画一个更复杂的分形图案(如谢尔宾斯基三角形)。
提示
可以画三个小三角形,每个在大三角形的顶点处。
下一步
恭喜你完成了函数的学习!现在你已经掌握了:
✅ 变量和数据类型 ✅ 条件语句和循环语句 ✅ 列表和字典 ✅ 函数和递归 ✅ 用Python实现数学函数
数学与编程的联系
通过这一章,你发现了Python函数和数学函数有很多相似之处:
-
函数结构:
- 数学: f(x) = 2x + 1
- Python: def f(x): return 2*x + 1
-
参数和返回值:
- 参数就像数学函数的自变量
- 返回值就像数学函数的因变量
-
函数的应用:
- 数学:描述数量关系和变化规律
- Python:实现计算逻辑和数据处理
用Python学习数学
现在你可以用Python来:
- 验证数学计算
- 探索数学规律(比如斐波那契数列)
- 实现数学公式
- 可视化数学概念
继续探索:
- 尝试用Python实现更多数学公式
- 探索数列、函数图像等数学概念
- 用编程解决数学问题
这些是Python编程的核心基础知识。下一章,我们将学习库(Library),这将让我们的程序变得更加强大。
库就像是Python的“工具箱“,里面装满了别人已经写好的功能,我们可以直接使用,而不需要自己从头开始写。比如:
math库:提供各种数学函数(三角函数、对数等)random库:生成随机数turtle库:画图
这将大大扩展我们的编程能力!
继续加油,你正在成为一名优秀的程序员!🎉
库 - 编程的百宝箱 🎁
引言
想象一下,如果你玩乐高积木时,每个零件都要自己亲手制造,那该多累啊!幸运的是,乐高公司已经为你准备好了成千上万种积木零件:车轮、窗户、门、人偶等。你只需要从零件盒里拿出需要的零件,就能拼搭出城堡、汽车、飞机等各种各样的作品!
Python的“库“(Library)就像这个乐高零件盒。里面装满了别人已经写好的、经过测试的代码,我们可以直接拿来使用,而不需要从零开始编写每一个功能。这正是编程的精髓之一:站在巨人的肩膀上,用更少的代码做更多的事情!
给家长的小贴士 💡
- 为什么需要库? 就像我们不需要自己制造铅笔、橡皮一样,编程也不需要从零开始写所有功能。库让编程变得高效、有趣且专业化。
- 本章目标 让孩子了解库的概念,学会使用几个常用的库,并理解如何查找和学习新的库。
- 编程思想 通过学习库,培养孩子的“代码复用“思维——理解为什么重复造轮子是低效的,而善用已有工具是聪明的做法。
- 实践建议 每个库都有趣味性强的例子,鼓励孩子亲手运行代码并修改参数,观察效果变化。
什么是库?
在Python中,库是一组相关功能的集合。有些库是Python自带的(标准库),有些需要额外安装(第三方库)。
生活类比:工具箱的智慧 🔧
库的概念在生活中随处可见:
- 工具箱 → 里面有锤子、螺丝刀、扳手等,你不需要自己制造这些工具
- 材料包 → 做手工时,纸、胶水、剪刀等材料都准备好了
- 乐高积木 → 各种预制的零件,可以直接拼搭作品
- 调料架 → 做菜时,盐、糖、酱油等调料都已准备好
编程中的库也是一样的道理! 别人已经把常用功能写好了,我们只需要“导入“就能使用。
# 这就像从工具箱里拿出"随机数生成器"这个工具
import random
# 然后直接使用它
number = random.randint(1, 100)
编程思想:代码复用 ♻️
在编程中,有一个重要的原则叫做DRY(Don’t Repeat Yourself,不要重复自己)。库就是这个原则的最佳实践:
- 避免重复劳动 → 不用每次都写相同的功能
- 提高效率 → 把时间花在创造新功能上
- 减少错误 → 使用经过测试的代码,比自己写更可靠
- 便于维护 → 库会持续更新和改进
给家长的小贴士 💡
- 模块化思维 库体现了“模块化“的编程思想——把复杂问题分解成可复用的小模块。这种思维方式不仅能应用于编程,也能应用于解决日常问题。
- 分工协作 现实中的大型软件是由成百上千的程序员协作开发的,每个人负责不同的模块(库),最后组合成完整的系统。这就像建造大厦,不同工种的人负责不同的工作。
- 教学建议 可以和孩子讨论生活中的“复用“例子,比如:预制菜、模板、复印等,帮助孩子理解“复用“的价值。
使用库的基本步骤
使用库通常需要两个步骤:
- 导入库 - 告诉Python我们要使用哪个库
- 调用功能 - 使用库提供的函数或对象
# 导入库
import random
# 使用库中的功能
print(random.randint(1, 100))
导入库的几种方式
# 方式1: 导入整个库(推荐给初学者)
import random
print(random.randint(1, 100))
# 方式2: 给库起一个简短的别名
import random as r
print(r.randint(1, 100))
# 方式3: 只导入库中的某个函数
from random import randint
print(randint(1, 100))
# 方式4: 导入库的所有内容(不推荐,容易造成名称冲突)
from random import *
print(randint(1, 100))
给家长的小贴士 💡
- 导入方式的选择 对于初学者,推荐使用方式1(导入整个库),因为这样代码可读性更好,能清楚知道每个函数来自哪个库。
- 命名冲突 方式4容易导致函数名冲突,不建议孩子使用。举例说明:如果两个库都有叫
read()的函数,就会产生混淆。 - 可读性优先 在学习阶段,代码清晰易懂比简洁更重要。鼓励孩子写出容易理解的代码。
库与计算机系统的关系 💻
系统库 vs 第三方库
Python的库可以分为两大类:
1. 标准库(系统库)
这些是Python自带的库,安装Python后就可以直接使用:
- random - 生成随机数
- time - 时间和计时
- json - JSON数据格式
- math - 数学函数(正弦、余弦、平方根等)
- os - 操作系统功能(文件、目录等)
类比: 就像手机出厂时预装的应用程序(计算器、日历、时钟等)。
2. 第三方库
这些是由社区开发者编写的库,需要额外安装:
- pyttsx3 - 文字转语音
- pygame - 游戏开发
- turtle - 图形绘制(有些Python发行版自带)
- pandas - 数据分析
- requests - 网络请求
类比: 就像从应用商店下载的额外应用程序(游戏、社交软件等)。
库与计算机硬件的协作
当我们使用库时,实际上是在指挥计算机的各个部件协同工作:
┌─────────────────────────────────────┐
│ 你的程序 │
│ import random │
│ number = random.randint(1, 100) │
└────────────┬────────────────────────┘
│ 调用
↓
┌─────────────────────────────────────┐
│ Random库(代码) │
│ 包含生成随机数的算法 │
└────────────┬────────────────────────┘
│ 使用
↓
┌─────────┬───┴────┬─────────┬───────┐
│ CPU │ 内存 │ 时钟 │ 系统时间│
│ 执行算法│ 存储数据│ 提供种子│ 随机源 │
└─────────┴────────┴─────────┴───────┘
给家长的小贴士 💡
- “随机“的本质 可以告诉孩子,计算机中的“随机数“其实不是真正随机的,而是根据一个“种子”(通常是当前时间)通过数学公式计算出来的。这就像“如果知道种子,就能预测结果“,所以叫“伪随机数“。
- 硬件协作 每个库的函数最终都会转换成CPU指令,指挥硬件工作。让孩子理解“代码→CPU指令→硬件执行“这个流程。
- 系统资源 有些库会消耗系统资源(内存、CPU时间),比如图形库需要显卡支持。这是很好的“成本意识“教育机会。
库的“生态系统“ 🌿
Python有庞大的库生态系统,这得益于:
- 开源社区 → 全世界的程序员共同贡献代码
- 包管理工具 → pip工具让安装库变得简单
- 文档和教程 → 每个库都有详细的使用说明
- 持续更新 → 库会不断改进和修复bug
这就像一个巨大的“工具共享社区“,每个人都可以使用别人的工具,也可以贡献自己的工具!
给家长的小贴士 💡
- 开源精神 可以向孩子介绍“开源“的概念——代码共享、互相帮助、共同进步。这是现代软件行业的重要文化。
- 社区协作 大型项目通常由世界各地的人协作开发,通过互联网共享代码。这能培养孩子的全球视野和协作意识。
- 学习资源 教会孩子如何搜索和利用社区资源(文档、论坛、教程)是重要的自学能力。
Random库 - 生成随机数 🎲
Random库可以帮我们生成随机数,这对于制作游戏、模拟实验等都很有用。
生成随机整数
randint(a, b)函数可以生成a到b之间的随机整数(包含a和b)。
import random
# 生成1到100之间的随机数
secret_number = random.randint(1, 100)
print(f"神秘数字是: {secret_number}")
# 生成1到6之间的随机数(模拟掷骰子)
dice = random.randint(1, 6)
print(f"骰子点数: {dice}")
# 生成1到10之间的随机数
lucky = random.randint(1, 10)
print(f"幸运数字: {lucky}")
运行示例:
神秘数字是: 73
骰子点数: 4
幸运数字: 7
从列表中随机选择
choice()函数可以从一个列表中随机选择一个元素。
import random
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
# 随机选择一个水果
fruit = random.choice(fruits)
print(f"今天吃: {fruit}")
# 随机选择3次
print("\n幸运抽奖:")
for i in range(3):
prize = random.choice(fruits)
print(f"第{i+1}次: {prize}")
运行示例:
今天吃: 葡萄
幸运抽奖:
第1次: 西瓜
第2次: 苹果
第3次: 橙子
数学练习:概率实验 📊
我们可以用random库来做数学中的概率实验!
import random
print("=== 抛硬币实验 ===")
heads = 0 # 正面次数
tails = 0 # 反面次数
total = 1000 # 抛1000次
for i in range(total):
# 随机选择0或1,0代表正面,1代表反面
result = random.randint(0, 1)
if result == 0:
heads += 1
else:
tails += 1
print(f"抛硬币{total}次的结果:")
print(f"正面(0): {heads}次, 比例: {heads/total*100:.1f}%")
print(f"反面(1): {tails}次, 比例: {tails/total*100:.1f}%")
print(f"\n理论上,正面和反面应该各占50%")
print(f"实验结果与理论的差异: {abs(heads - tails)/total*100:.1f}%")
运行示例:
=== 抛硬币实验 ===
抛硬币1000次的结果:
正面(0): 503次, 比例: 50.3%
反面(1): 497次, 比例: 49.7%
理论上,正面和反面应该各占50%
实验结果与理论的差异: 0.6%
给家长的小贴士 💡
- 概率与统计 这个实验很好地展示了“大数定律“:当试验次数足够多时,实验结果会趋近于理论概率。
- 数学联系 可以和孩子讨论:为什么是1000次而不是10次?实验次数越多,结果越接近50%。
- 扩展思考 可以让孩子修改程序,尝试掷骰子实验,看看每个数字出现的概率是否接近1/6。
打乱列表顺序
shuffle()函数可以随机打乱列表中元素的顺序。
import random
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
print("原始顺序:", cards)
# 打乱顺序
random.shuffle(cards)
print("打乱后:", cards)
# 再次打乱
random.shuffle(cards)
print("再次打乱:", cards)
综合练习:猜数字游戏
import random
# 电脑随机生成一个1-100的数字
secret = random.randint(1, 100)
attempts = 0
print("=== 猜数字游戏 ===")
print("我已经想好了一个1到100之间的数字,你能在几次内猜中?")
while True:
guess = int(input("请输入你的猜测(1-100): "))
attempts += 1
if guess == secret:
print(f"🎉 恭喜你!第{attempts}次猜对了!")
break
elif guess < secret:
print("太小了,再大一点!")
else:
print("太大了,再小一点!")
给家长的小贴士 💡
- 随机数的概念 向孩子解释“随机“意味着每次运行结果可能不同,就像掷骰子一样。
- 游戏化学习 猜数字游戏是练习循环和条件的绝佳例子,孩子会很有兴趣。
- 调试技巧 可以让孩子打印出secret_number,先理解程序逻辑,再玩正式游戏。
练习1
练习1: 石头剪刀布游戏
编写一个石头剪刀布游戏:
- 电脑随机选择(石头、剪刀、布)
- 玩家输入选择
- 比较并显示结果
提示: 用random.choice()和if-elif语句
参考答案
import random
options = ["石头", "剪刀", "布"]
while True:
# 电脑随机选择
computer = random.choice(options)
# 玩家选择
player = input("请选择(石头/剪刀/布)或输入q退出: ")
if player == "q":
break
if player not in options:
print("无效的选择!")
continue
print(f"电脑出: {computer}")
print(f"你出: {player}")
# 判断胜负
if player == computer:
print("平局!")
elif (player == "石头" and computer == "剪刀") or \
(player == "剪刀" and computer == "布") or \
(player == "布" and computer == "石头"):
print("你赢了! 🎉")
else:
print("电脑赢了! 😢")
print()
Time库 - 时间和计时 ⏰
Time库让我们能够处理时间相关的操作,比如暂停程序、计时、获取当前时间等。
暂停程序
sleep()函数可以让程序暂停指定的秒数。
import time
print("开始倒计时!")
print("3...")
time.sleep(1)
print("2...")
time.sleep(1)
print("1...")
time.sleep(1)
print("发射! 🚀")
print("\n模拟下载文件...")
for i in range(1, 6):
print(f"下载中... {i*20}%")
time.sleep(0.5)
print("下载完成!")
获取当前时间
time()函数返回当前时间的时间戳(从1970年1月1日开始的秒数)。
import time
# 获取当前时间戳
current_time = time.time()
print(f"当前时间戳: {current_time}")
# 转换为可读格式
readable_time = time.ctime(current_time)
print(f"可读时间: {readable_time}")
运行示例:
当前时间戳: 1736871234.5678901
可读时间: Mon Jan 15 14:32:14 2025
数学联系:时间计算 🧮
时间计算是很好的数学练习!
import time
# 记录开始时间
start = time.time()
# 做一些计算(比如计算1到10000的和)
total = 0
for i in range(1, 10001):
total += i
# 记录结束时间
end = time.time()
# 计算耗时
elapsed = end - start
print(f"1到10000的和: {total}")
print(f"计算耗时: {elapsed:.6f}秒")
# 数学问题:如果计算1到100000的和,需要多久?
print("\n让我们试试计算1到100000的和...")
start = time.time()
total = 0
for i in range(1, 100001):
total += i
end = time.time()
elapsed = end - start
print(f"计算耗时: {elapsed:.6f}秒")
# 思考题:耗时增加了大约多少倍?
print("\n思考:计算量增加了10倍,耗时增加了多少倍?")
计时器
perf_counter()函数可以用来精确计时,常用于测量程序运行时间。
import time
# 开始计时
start = time.perf_counter()
# 模拟一些工作
print("开始计算...")
sum_result = 0
for i in range(1, 100000001):
sum_result += i
# 结束计时
end = time.perf_counter()
# 计算耗时
elapsed = end - start
print(f"1到1亿求和结果: {sum_result}")
print(f"耗时: {elapsed:.2f}秒")
# 数学问题:CPU每秒能执行多少次加法?
operations = 100000000 / elapsed
print(f"\nCPU每秒大约执行了 {operations:.0f} 次加法运算")
运行示例:
开始计算...
1到1亿求和结果: 5000000050000000
耗时: 4.23秒
CPU每秒大约执行了 23640662 次加法运算
给家长的小贴士 💡
- CPU性能概念 通过计时,让孩子理解CPU的速度——每秒能执行几千万次简单运算!这能培养对计算机性能的直观认识。
- 时间戳的概念 向孩子解释时间戳就像给每一刻都编了一个号码,方便计算机计算时间差。
- 实际应用 计时功能可以用于测试程序效率,让孩子理解“优化“的概念——同样的功能,代码写得更好,运行更快。
综合练习:速度测试游戏
import time
import random
print("=== 打字速度测试 ===")
print("我会显示一个随机单词,你需要尽快输入它!")
words = ["python", "computer", "programming", "keyboard", "mouse", "screen"]
word = random.choice(words)
print(f"\n请输入: {word}")
# 开始计时
start = time.perf_counter()
user_input = input()
# 结束计时
end = time.perf_counter()
elapsed = end - start
if user_input == word:
print(f"✓ 正确!耗时: {elapsed:.2f}秒")
if elapsed < 1:
print("速度: ⚡⚡⚡ 超级快!")
elif elapsed < 2:
print("速度: ⚡⚡ 很快!")
elif elapsed < 3:
print("速度: ⚡ 还可以!")
else:
print("速度: 🐢 需要练习哦!")
else:
print("✗ 输入错误!")
练习2
练习2: 反应时间测试
编写一个测试反应时间的程序:
- 程序随机等待2-5秒
- 显示“现在按回车键!“
- 计算用户按回车键的反应时间
提示: 用random.randint()和time.perf_counter()
参考答案
import time
import random
print("=== 反应时间测试 ===")
print("当你看到'现在按回车键!'时,尽快按回车!")
input("准备好了吗?按回车开始...")
# 随机等待2-5秒
wait_time = random.randint(2, 5)
time.sleep(wait_time)
# 记录开始时间
start = time.perf_counter()
# 等待用户按下回车
input("现在按回车键!")
# 记录结束时间
end = time.perf_counter()
# 计算反应时间
reaction = end - start
print(f"\n你的反应时间: {reaction:.3f}秒")
if reaction < 0.3:
print("神一般的反应! ⚡⚡⚡")
elif reaction < 0.5:
print("很快! ⚡⚡")
elif reaction < 0.7:
print("正常水平 ⚡")
else:
print("有点慢...再接再厉! 🐢")
Turtle库 - 图形绘制(复习与扩展) 🐢
我们在第6章已经学习了Turtle库的基础,这里我们复习并学习一些高级功能。
填充颜色
begin_fill()和end_fill()函数可以让 turtle填充封闭图形的颜色。
import turtle
t = turtle.Turtle()
t.speed(1)
# 设置画笔颜色和填充颜色
# color()可以同时设置两个颜色
t.color("red", "yellow") # 画笔红色,填充黄色
# 开始填充
t.begin_fill()
# 画一个五角星
for _ in range(5):
t.forward(200)
t.right(144)
# 结束填充
t.end_fill()
turtle.mainloop()
数学练习:多角星的几何计算 📐
画多角星需要计算角度,这是很好的几何练习!
import turtle
t = turtle.Turtle()
t.speed(0)
# 画一个50角星
t.color("red", "yellow")
t.begin_fill()
for _ in range(50):
t.forward(200)
t.left(170) # 每次转170度
t.end_fill()
turtle.mainloop()
数学思考题:
- 如果画n角星,每次应该转多少度?
- 提示:360度 × (n-2) / n 是正n边形的内角
- 星形的角度是:180 - (360 / n)
几何知识复习
import turtle
def draw_polygon(t, sides, size):
"""画正多边形"""
# 计算外角
angle = 360 / sides
print(f"画{sides}边形,每次转{angle}度")
for _ in range(sides):
t.forward(size)
t.right(angle)
t = turtle.Turtle()
t.speed(1)
# 画各种多边形
draw_polygon(t, 3, 100) # 三角形
t.penup()
t.goto(150, 0)
t.pendown()
draw_polygon(t, 4, 100) # 正方形
t.penup()
t.goto(-150, 0)
t.pendown()
draw_polygon(t, 5, 100) # 五边形
t.penup()
t.goto(0, -150)
t.pendown()
draw_polygon(t, 6, 100) # 六边形
t.penup()
t.goto(0, 150)
t.pendown()
draw_polygon(t, 8, 80) # 八边形
turtle.mainloop()
给家长的小贴士 💡
- 几何与编程 这是将编程与数学几何完美结合的例子!鼓励孩子计算不同多边形的角度。
- 数学公式复习:
- 三角形内角和 = 180度
- 四边形内角和 = 360度
- n边形内角和 = (n-2) × 180度
- 正n边形每个外角 = 360度 / n
- 探索精神 鼓励孩子尝试不同的参数,观察图形的变化,这是科学探索的精神!
在画布上写字
write()函数可以在画布上写字。
import turtle
import time
t = turtle.Turtle()
t.speed(1)
# 设置画笔大小和颜色
t.pensize(5)
t.pencolor("yellow")
t.fillcolor("red")
# 画一个五边形
t.begin_fill()
for _ in range(5):
t.forward(200)
t.right(144)
t.end_fill()
# 等待2秒
time.sleep(2)
# 抬起画笔,移动到指定位置
t.penup()
t.goto(-150, -120)
# 设置颜色并写字
t.color("violet")
t.write("Done!", font=('Arial', 40, 'normal'))
turtle.mainloop()
综合练习: 彩虹五角星
import turtle
t = turtle.Turtle()
t.speed(0)
# 定义彩虹颜色
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
# 画多个五角星
for i in range(36):
t.color(colors[i % 6]) # 循环使用颜色
t.begin_fill()
for _ in range(5):
t.forward(100)
t.right(144)
t.end_fill()
t.right(10) # 每次旋转10度
turtle.mainloop()
给家长的小贴士 💡
- 复习与巩固 这个部分是对第6章内容的复习,如果孩子已经很熟悉,可以快速跳过。
- 颜色循环
colors[i % 6]这个表达式是一个重要的技巧,向孩子解释取余运算的作用。 - 创意扩展 鼓励孩子修改参数(角度、步长、颜色),创造自己的图形艺术。
练习3
练习3: 花朵图案
使用Turtle画一朵花:
- 画多个花瓣(用椭圆或曲线)
- 每个花瓣旋转一定角度
- 中心填充黄色,花瓣用粉色
参考答案
import turtle
t = turtle.Turtle()
t.speed(0)
# 画花瓣
for _ in range(12):
t.color("pink", "pink")
t.begin_fill()
# 画一个椭圆花瓣
for _ in range(2):
t.circle(50, 90)
t.circle(10, 90)
t.end_fill()
t.right(30) # 旋转30度
# 画花心
t.penup()
t.goto(0, -20)
t.pendown()
t.color("yellow", "yellow")
t.begin_fill()
t.circle(20)
t.end_fill()
turtle.mainloop()
文件操作库 - 数据的持久化 💾
文件操作让我们可以读取和保存数据,这样程序关闭后数据不会丢失。
为什么需要文件?
想象一下,如果你写的日记每次合上本子后,字迹就消失了,那该多糟糕!文件就是计算机的“日记本“,让数据可以永久保存。
# 没有文件:数据在内存中,程序关闭就丢失
score = 100 # 程序关闭后,这个数据就不见了
# 有了文件:数据保存在硬盘上,程序关闭后数据还在
f = open("score.txt", "w")
f.write("100")
f.close()
# 即使关闭程序,数据仍然保存在文件中
文件与计算机硬件 🖥️
┌─────────────────────────────────────┐
│ 你的程序 │
│ 读取/保存数据 │
└────────────┬────────────────────────┘
│
↓
┌─────────────────────────────────────┐
│ 文件系统 │
│ 管理文件的存储和组织 │
└────────────┬────────────────────────┘
│
↓
┌─────────────────────────────────────┐
│ 硬盘存储 │
│ 永久保存数据(磁道、扇区) │
└─────────────────────────────────────┘
给家长的小贴士 💡
- 内存 vs 硬盘 可以这样解释:
- 内存 = 书桌 → 工作时放东西,速度快但断电后数据消失
- 硬盘 = 文件柜 → 长期存储,速度慢但断电后数据还在
- 持久化 向孩子解释“持久化“就是“让数据长期保存“的意思。
- 文件编码 简单提一下文件是用0和1存储的,不同的编码方式(如UTF-8)决定如何表示字符。
打开和读取文件
open()函数用于打开文件,“r“表示只读模式。
# 打开文件
f = open("story.txt", "r")
# 读取全部内容
content = f.read()
print("文件内容:")
print(content)
# 关闭文件
f.close()
写入文件
“w“表示写入模式(会覆盖原有内容),“a“表示追加模式(在末尾添加)。
# 写入模式(覆盖)
f = open("diary.txt", "w")
f.write("2025年1月15日 天气: 晴\n")
f.write("今天我学会了Python的文件操作!\n")
f.close()
# 追加模式
f = open("diary.txt", "a")
f.write("感觉很有成就感! 😊\n")
f.close()
# 读取并显示
f = open("diary.txt", "r")
print(f.read())
f.close()
修改文件
# 打开文件进行读写("r+")
f = open("note.txt", "r+")
# 读取内容
content = f.read()
print("原始内容:")
print(content)
# 移动到文件开头
f.seek(0)
# 清空文件
f.truncate()
# 写入新内容
f.write("更新后的内容\n")
f.write("这是一行新文字\n")
# 关闭文件
f.close()
# 再次读取验证
f = open("note.txt", "r")
print("\n更新后内容:")
print(f.read())
f.close()
逐行读取
# 打开文件
f = open("students.txt", "r")
# 逐行读取
print("=== 学生名单 ===")
line_number = 1
for line in f:
# 去除行尾的换行符
name = line.strip()
print(f"{line_number}. {name}")
line_number += 1
f.close()
数学应用:成绩统计 📊
# 假设我们有一个成绩文件
# 创建示例文件
f = open("scores.txt", "w")
f.write("85\n")
f.write("92\n")
f.write("78\n")
f.write("95\n")
f.write("88\n")
f.close()
# 读取并统计
f = open("scores.txt", "r")
scores = []
for line in f:
score = int(line.strip())
scores.append(score)
f.close()
# 计算统计数据
total = sum(scores)
count = len(scores)
average = total / count
highest = max(scores)
lowest = min(scores)
print(f"成绩统计:")
print(f"总人数: {count}")
print(f"总分: {total}")
print(f"平均分: {average:.1f}")
print(f"最高分: {highest}")
print(f"最低分: {lowest}")
给家长的小贴士 💡
- 文件路径 默认情况下,文件会在当前目录创建。可以教孩子使用绝对路径。
- 文件编码 如果遇到中文乱码,可以在open()时指定
encoding="utf-8"。 - 关闭文件 强调f.close()的重要性,就像用完水龙头要关水一样。
- 更好的写法 可以介绍
with语句,它会自动关闭文件:
# 推荐的写法:自动关闭文件
with open("data.txt", "r") as f:
content = f.read()
# 文件会自动关闭,即使发生错误也是如此
练习4
练习4: 成绩记录本
编写一个成绩记录程序:
- 可以输入科目和成绩
- 保存到文件
- 可以查看所有历史记录
参考答案
print("=== 成绩记录本 ===")
while True:
print("\n1. 记录成绩")
print("2. 查看历史")
print("3. 退出")
choice = input("请选择(1-3): ")
if choice == "1":
subject = input("科目: ")
score = input("成绩: ")
# 追加到文件
f = open("scores.txt", "a")
f.write(f"{subject}: {score}\n")
f.close()
print("✓ 已保存!")
elif choice == "2":
try:
f = open("scores.txt", "r")
print("\n=== 历史成绩 ===")
print(f.read())
f.close()
except FileNotFoundError:
print("还没有任何记录!")
elif choice == "3":
break
JSON库 - 数据交换格式 📋
JSON是一种常用的数据格式,Python的json库可以读写JSON文件。
什么是JSON?
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。
{
"name": "小明",
"age": 10,
"hobbies": ["篮球", "编程", "音乐"]
}
生活类比:
- JSON就像乐高组装说明书 → 用统一格式描述如何组装
- 就像简历模板 → 用统一格式记录个人信息
- 就像配置表 → 记录软件的各种设置
JSON与数据结构 📊
JSON完美对应Python的数据结构:
# Python字典 → JSON对象
person = {
"name": "小明",
"age": 10
}
# Python列表 → JSON数组
hobbies = ["篮球", "编程", "音乐"]
# Python字符串/数字/布尔值 → JSON对应类型
name = "小明"
age = 10
is_student = True
读取JSON文件
import json
# 读取JSON文件
f = open("student.json", "r")
student = json.load(f)
f.close()
# 使用数据
print(f"姓名: {student['name']}")
print(f"年龄: {student['age']}")
print("爱好:")
for hobby in student['hobbies']:
print(f" - {hobby}")
写入JSON文件
import json
# 准备数据
student = {
"name": "小红",
"age": 11,
"grade": "五年级",
"hobbies": ["画画", "跳舞", "阅读"]
}
# 写入JSON文件
f = open("student.json", "w")
# indent=2 表示缩进2个空格,让格式更美观
json.dump(student, f, indent=2, ensure_ascii=False)
f.close()
print("JSON文件已创建!")
修改JSON文件
import json
# 读取JSON文件
f = open("data.json", "r+")
data = json.load(f)
# 修改数据
data['age'] = 12
data['hobbies'].append("游泳")
# 移动到文件开头
f.seek(0)
# 清空文件
f.truncate()
# 写入修改后的数据
json.dump(data, f, indent=2, ensure_ascii=False)
f.close()
print("数据已更新!")
数学应用:成绩统计系统 📈
import json
# 保存班级成绩
class_data = {
"class_name": "五年级1班",
"students": [
{"name": "小明", "scores": {"数学": 95, "语文": 88, "英语": 92}},
{"name": "小红", "scores": {"数学": 89, "语文": 95, "英语": 90}},
{"name": "小刚", "scores": {"数学": 92, "语文": 85, "英语": 88}}
]
}
# 保存到文件
f = open("class_scores.json", "w", encoding="utf-8")
json.dump(class_data, f, indent=2, ensure_ascii=False)
f.close()
# 读取并统计
f = open("class_scores.json", "r", encoding="utf-8")
data = json.load(f)
f.close()
print(f"班级: {data['class_name']}")
print(f"学生人数: {len(data['students'])}")
# 计算班级平均分
math_total = 0
chinese_total = 0
english_total = 0
for student in data['students']:
scores = student['scores']
math_total += scores['数学']
chinese_total += scores['语文']
english_total += scores['英语']
count = len(data['students'])
print(f"\n班级平均分:")
print(f"数学: {math_total/count:.1f}")
print(f"语文: {chinese_total/count:.1f}")
print(f"英语: {english_total/count:.1f}")
给家长的小贴士 💡
- JSON的优势 JSON格式易读、通用,很多网站和API都使用JSON格式交换数据。
- ensure_ascii=False 这个参数让中文字符正常显示,而不是显示成Unicode编码。
- 应用场景 可以用JSON保存游戏进度、配置文件等。
- 数据结构映射 这是一个很好的机会,向孩子展示现实中的数据如何用编程结构来表示。
练习5
练习5: 个人信息管理
编写一个个人信息管理系统:
- 可以查看信息
- 可以修改姓名
- 可以添加爱好
- 保存到JSON文件
参考答案
import json
import os
filename = "my_info.json"
# 检查文件是否存在
if os.path.exists(filename):
f = open(filename, "r")
info = json.load(f)
f.close()
print("找到已有信息!")
else:
info = {}
print("创建新档案...")
while True:
print("\n=== 个人信息管理 ===")
print("1. 查看信息")
print("2. 修改姓名")
print("3. 添加爱好")
print("4. 保存并退出")
choice = input("请选择(1-4): ")
if choice == "1":
print("\n当前信息:")
for key, value in info.items():
print(f"{key}: {value}")
elif choice == "2":
name = input("请输入姓名: ")
info['name'] = name
print("✓ 姓名已更新!")
elif choice == "3":
hobby = input("请输入新爱好: ")
if 'hobbies' not in info:
info['hobbies'] = []
info['hobbies'].append(hobby)
print("✓ 爱好已添加!")
elif choice == "4":
f = open(filename, "w")
json.dump(info, f, indent=2, ensure_ascii=False)
f.close()
print("✓ 信息已保存!再见!")
break
自己开发库 - 模块化编程 🧩
我们不仅可以使用别人写的库,还可以自己创建库!把常用的功能打包成库,可以让代码更简洁、更易维护。
为什么要自己写库?
代码复用的思想:
# 没有库:每次都要重复写相同的代码
def calculate_rectangle_area(length, width):
return length * width
def calculate_rectangle_perimeter(length, width):
return 2 * (length + width)
# 在多个程序中重复复制这些代码... 😞
# 有了库:写一次,到处使用
import my_tools
area = my_tools.calculate_rectangle_area(10, 5) # 😊
好处:
- ✅ 不用重复写代码
- ✅ 代码更简洁
- ✅ 更新时只改一个地方
- ✅ 可以分享给别人使用
创建自己的库
创建一个名为my_tools.py的文件:
# my_tools.py - 我的工具库
def calculate_rectangle_area(length, width):
"""计算长方形面积"""
return length * width
def calculate_rectangle_perimeter(length, width):
"""计算长方形周长"""
return 2 * (length + width)
def say_hello(name):
"""打招呼函数"""
return f"你好, {name}!"
def get_grade(score):
"""根据分数返回等级"""
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
使用自己的库
在另一个程序中导入并使用:
# main.py
import my_tools
# 使用库中的函数
length = 10
width = 5
area = my_tools.calculate_rectangle_area(length, width)
perimeter = my_tools.calculate_rectangle_perimeter(length, width)
print(f"长方形面积: {area}")
print(f"长方形周长: {perimeter}")
# 问候
greeting = my_tools.say_hello("小明")
print(greeting)
# 成绩等级
score = 85
grade = my_tools.get_grade(score)
print(f"分数{score}对应的等级是: {grade}")
数学工具库示例 🧮
创建一个math_tools.py文件:
# math_tools.py - 数学工具库
def calculate_average(numbers):
"""计算平均数"""
if len(numbers) == 0:
return 0
return sum(numbers) / len(numbers)
def calculate_median(numbers):
"""计算中位数"""
if len(numbers) == 0:
return 0
sorted_numbers = sorted(numbers)
n = len(sorted_numbers)
middle = n // 2
if n % 2 == 0:
# 偶数个元素,取中间两个的平均值
return (sorted_numbers[middle-1] + sorted_numbers[middle]) / 2
else:
# 奇数个元素,取中间的值
return sorted_numbers[middle]
def is_prime(n):
"""判断是否为质数"""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(n**0.5) + 1, 2):
if n % i == 0:
return False
return True
def calculate_factorial(n):
"""计算阶乘"""
if n < 0:
return None
if n == 0 or n == 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
使用这个数学工具库:
import math_tools
# 测试平均数
scores = [85, 92, 78, 95, 88]
avg = math_tools.calculate_average(scores)
print(f"平均分: {avg}")
# 测试中位数
median = math_tools.calculate_median(scores)
print(f"中位数: {median}")
# 测试质数判断
print(f"17是质数吗? {math_tools.is_prime(17)}")
print(f"18是质数吗? {math_tools.is_prime(18)}")
# 测试阶乘
print(f"5的阶乘: {math_tools.calculate_factorial(5)}")
综合练习: 图形工具库
创建一个drawing_tools.py文件:
# drawing_tools.py - 绘图工具库
import turtle
def draw_square(t, size):
"""画正方形"""
for _ in range(4):
t.forward(size)
t.right(90)
def draw_triangle(t, size):
"""画三角形"""
for _ in range(3):
t.forward(size)
t.right(120)
def draw_polygon(t, sides, size):
"""画多边形"""
angle = 360 / sides
for _ in range(sides):
t.forward(size)
t.right(angle)
def draw_star(t, size, points):
"""画星星"""
angle = 180 - (180 / points)
for _ in range(points):
t.forward(size)
t.right(angle)
使用这个库:
import turtle
import drawing_tools
t = turtle.Turtle()
t.speed(0)
# 使用库中的函数画图
drawing_tools.draw_square(t, 100)
t.penup()
t.goto(150, 0)
t.pendown()
drawing_tools.draw_triangle(t, 100)
t.penup()
t.goto(-150, 0)
t.pendown()
drawing_tools.draw_polygon(t, 6, 80) # 六边形
t.penup()
t.goto(0, -150)
t.pendown()
drawing_tools.draw_star(t, 100, 5) # 五角星
turtle.mainloop()
给家长的小贴士 💡
- 模块化思维 教孩子把常用的功能整理成库,培养模块化的思维。
- 文件组织 建议创建一个专门的文件夹存放自定义库。
- 文档注释 在函数中使用三引号注释,说明函数的用途。
- 函数命名 鼓励孩子使用清晰的函数名,让别人一看就知道函数是做什么的。
- 编程规范 这是培养良好编程习惯的好机会,比如:
- 一个函数只做一件事
- 函数名要描述性
- 添加注释说明
练习6
练习6: 语音工具库
创建一个语音工具库speech_tools.py,包含以下函数:
- speak_text(text) - 读出文字
- speak_number(number) - 读出数字
- speak_list(items) - 读出列表中的每一项
然后编写一个程序使用这个库。
参考答案
speech_tools.py:
import pyttsx3
def speak_text(text):
"""读出文字"""
engine = pyttsx3.init()
engine.setProperty('rate', 150)
engine.say(text)
engine.runAndWait()
def speak_number(number):
"""读出数字"""
engine = pyttsx3.init()
engine.setProperty('rate', 150)
engine.say(f"数字是 {number}")
engine.runAndWait()
def speak_list(items):
"""读出列表中的每一项"""
engine = pyttsx3.init()
engine.setProperty('rate', 150)
for item in items:
engine.say(item)
engine.runAndWait()
使用示例:
import speech_tools
# 读文字
speech_tools.speak_text("你好,欢迎使用语音工具库")
# 读数字
speech_tools.speak_number(42)
# 读列表
fruits = ["苹果", "香蕉", "橙子"]
speech_tools.speak_list(fruits)
自学库 - 探索更多可能 🔍
Python有海量的第三方库,我们可以根据需要学习使用新的库。
如何查找和安装库
- 查找库 访问 https://pypi.org 搜索需要的库
- 安装库 使用
pip3 install 库名安装 - 学习使用 阅读库的文档和示例代码
学会阅读文档 📖
这是程序员最重要的技能之一!
文档通常包含:
- 安装说明 → 如何安装库
- 快速开始 → 最简单的使用示例
- API参考 → 所有函数的详细说明
- 示例代码 → 完整的使用案例
- 常见问题 → FAQ
阅读文档的技巧:
- 先看“快速开始“,跑通最简单的例子
- 再看示例代码,理解如何使用
- 遇到问题时查API参考
- 最后查看FAQ或搜索问题
给家长的小贴士 💡
- 自学能力 学会查找和使用新库是重要的编程技能。
- 文档阅读 教孩子如何阅读库的文档,找到需要的函数。
- 试错精神 鼓励孩子多尝试,不怕犯错,从错误中学习。
- 搜索引擎 教会孩子如何有效地搜索问题,比如:
- “python 库名 教程”
- “python 库名 example”
- “python how to 使用某个功能”
- 社区资源 介绍一些学习资源:
- Stack Overflow - 问答社区
- GitHub - 查看开源项目
- B站/YouTube - 视频教程
实践挑战:探索新库
这里给你一个挑战:自己找一个可以播放音乐的Python库,学习它的接口,编写一个简单的音乐播放器。
推荐库:
- pygame - 强大的多媒体库
- playsound - 简单的音频播放
- pydub - 音频处理库
示例步骤:
- 使用
pip3 install pygame安装 - 在网上搜索“pygame music player example“
- 学习基本的播放功能
- 编写自己的播放器程序
学习过程记录:
[ ] 1. 安装库
[ ] 2. 查看官方文档
[ ] 3. 运行示例代码
[ ] 4. 理解代码原理
[ ] 5. 修改和扩展功能
[ ] 6. 完成自己的项目
常见错误和调试 🔧
错误1: ModuleNotFoundError
import nonexistent_module
错误信息: ModuleNotFoundError: No module named 'nonexistent_module'
原因: 库不存在或未安装
解决方法:
- 检查库名是否拼写正确
- 使用
pip3 install 库名安装库
错误2: 导入路径错误
import my_tools # 假设my_tools.py不在当前目录
错误信息: ModuleNotFoundError: No module named 'my_tools'
原因: Python找不到自定义库文件
解决方法:
- 确保库文件和程序在同一目录
- 或将库文件放在Python能找到的目录中
错误3: 文件未关闭
f = open("data.txt", "r")
content = f.read()
# 忘记 f.close()
问题: 文件可能被锁定,其他程序无法访问
解决方法: 使用with语句自动关闭文件
with open("data.txt", "r") as f:
content = f.read()
# 文件会自动关闭
调试技巧
- 打印导入的库
import random
print(random) # 检查是否成功导入
- 查看库的内容
import random
print(dir(random)) # 查看库中的所有函数
- 查看函数帮助
import random
help(random.randint) # 查看函数说明
章节小结
核心知识点回顾
-
库的概念 🎁
- 库是预先写好的代码集合,可以直接使用
- 就像工具箱、乐高积木、材料包
- 体现了“代码复用“和“模块化“的编程思想
-
导入库 📥
- 使用
import语句导入库 - 有多种导入方式,推荐初学者使用
import 库名
- 使用
-
常用库 🛠️
- random - 生成随机数
- time - 时间和计时
- turtle - 图形绘制
- json - JSON数据格式
-
文件操作 💾
- 读取和写入文件
- 文件是数据的持久化存储
- 理解内存和硬盘的区别
-
库与计算机系统 💻
- 标准库 vs 第三方库
- 库与硬件的协作关系
- 开源社区和代码共享精神
-
自定义库 🧩
- 可以自己创建库
- 提高代码复用性
- 培养模块化思维
-
自学能力 🔍
- 如何查找和安装新库
- 如何阅读文档
- 从错误中学习
能力检查表 ✅
完成本章学习后,你应该能够:
- 理解库的概念和作用
- 正确导入和使用库
- 使用random库生成随机数
- 使用time库进行计时和暂停
- 使用turtle库绘制图形
- 进行基本的文件操作
- 读写JSON文件
- 创建和使用自定义库
- 理解库与计算机硬件的关系
- 会查找和学习新的库
编程思想总结 💡
通过学习库,我们掌握了重要的编程思想:
- 代码复用 → 不要重复造轮子,善用已有工具
- 模块化 → 把复杂问题分解成可复用的小模块
- 分工协作 → 大型项目由多人分工完成,各自负责不同的库
- 开源精神 → 代码共享,互相帮助,共同进步
- 持续学习 → 技术在不断进步,要学会查找和探索新工具
数学知识点回顾 📚
本章融入的数学知识:
- 概率统计 → 抛硬币实验、随机数分布
- 几何计算 → 多边形角度、图形绘制
- 数据分析 → 平均数、中位数、方差
- 时间计算 → 时间戳、时间差
- 函数概念 → 数学函数 vs 编程函数
计算机知识回顾 💻
本章融入的计算机知识:
- 内存 vs 硬盘 → 临时存储 vs 永久存储
- 文件系统 → 文件的组织和管理
- CPU性能 → 通过计时理解运算速度
- 随机数原理 → 种子和伪随机数
- 开源生态 → 社区协作和代码共享
下一章预告 ➡️
本章我们学习了如何使用各种库来扩展程序的功能,理解了代码复用和模块化的重要思想。
下一章,我们将综合运用所学知识,开发一个命令行程序,实现一个实用的课表查询系统!我们将深入学习:
- 如何设计一个完整的程序
- 如何处理复杂的用户交互
- 如何组织和管理大量数据
- 文件系统在程序中的应用
挑战练习 🎯
-
抽奖系统 🎰 使用random库创建一个抽奖系统,可以输入参与者名单,随机抽取幸运儿。
- 提示:用列表存储名单,用random.choice()抽取
-
语音闹钟 ⏰ 结合time和pyttsx3库,创建一个定时播报提醒的程序。
- 提示:用time.sleep()等待,用pyttsx3播报
-
图形计算器 🖥️ 使用turtle库创建一个图形化的计算器界面。
- 提示:用turtle画按钮,处理用户输入
-
数据管理器 📊 使用JSON文件创建一个个人数据管理系统,可以增删改查数据。
- 提示:用字典存储数据,用json.dump/load保存读取
-
创意项目 ⭐ 自学一个新的Python库,用它创建一个有趣的项目!
- 推荐方向:
- ** Arcade** - 游戏开发库
- ** Pillow** - 图像处理库
- requests - 网络请求库
- ** Beautiful Soup** - 网页爬虫库
- 推荐方向:
恭喜你完成了第13章的学习! 🎉
你已经掌握了使用库这一重要技能,这会让你的编程之旅更加高效和有趣!继续保持好奇心和探索精神,下一章见! 👋
CommandLine程序
引言
同学们,你们有没有想过,我们每天在学校上课时,如果能有一个“电子小助手“,随时告诉我们今天有什么课,那该多好啊?
在前面几章中,我们已经学习了很多Python知识:
- 第2章学会了输入和输出
- 第5章学会了布尔值判断
- 第7章学会了条件语句
- 第8章学会了循环语句
- 第10章学会了列表
- 第11章学会了字典
- 第12章学会了函数
- 第13章学会了各种库的使用
现在,是时候把这些知识都运用起来,开发一个真正的实用程序了!
我们将开发一个智能课表查询系统,它可以:
- 📅 查询某天的课程
- ➕ 添加新的课程
- ✏️ 修改已有课程
- ❌ 删除不要的课程
- 📁 自动保存到文件,下次打开还能用
- 🗣️ 理解各种说法(周一/星期一/礼拜一都可以)
- 🕐 支持上午下午的区分
- 📆 支持直接输入日期(如“10月15日“)
这个程序将会像我们平时和机器人聊天一样自然,这就是**命令行程序(CommandLine Program)**的魅力!
什么是命令行程序?
命令行程序是一种通过文字命令和计算机交互的程序。没有漂亮的按钮和窗口,所有的操作都通过输入命令来完成。
🖥️ 计算机小知识:命令行的历史
你知道吗?在很久以前(1970-1980年代),计算机没有图形界面,没有鼠标,没有漂亮的窗口!
那时的程序员只能通过命令行(Command Line) 和计算机交流:
- 屏幕是黑底的,只有白色的文字
- 没有鼠标,只能用键盘输入命令
- 每个命令都要准确记忆和准确拼写
为什么那时候没有图形界面呢?
- 计算机的CPU速度慢,处理不动复杂的图形
- 内存很小,存不下那么多图片和界面
- 硬盘很小,存不了那么多数据
所以命令行程序是计算机发展早期的重要交互方式!即使现在有了图形界面,命令行仍然被程序员广泛使用,因为它:
- ✅ 运行速度快(不需要处理图形)
- ✅ 占用资源少(不需要加载图片)
- ✅ 灵活强大(可以组合各种命令)
命令行程序 vs 图形界面程序
| 特点 | 命令行程序 | 图形界面程序 |
|---|---|---|
| 交互方式 | 输入文字命令 | 点击按钮、菜单 |
| 外观 | 黑色背景,白色文字 | 有图片、按钮、窗口 |
| 学习难度 | 需要记住命令 | 直观,容易上手 |
| 灵活性 | 非常灵活 | 功能固定 |
| 运行速度 | 快 | 相对慢 |
| CPU占用 | 低 | 高 |
| 内存占用 | 少 | 多 |
| 例子 | 我们的课表系统 | 游戏、手机APP |
生活中的命令行程序
其实你早就用过命令行程序了!
例子1: 和聊天机器人对话
你: 今天天气怎么样?
机器人: 今天北京晴,温度15-25度
你: 明天呢?
机器人: 明天多云,温度18-28度
例子2: 智能音箱
你: 小爱同学,播放音乐
音箱: 好的,正在播放你喜欢的歌
你: 下一首
音箱: 正在切换到下一首
这些都和命令行程序类似:你用文字告诉它要做什么,它用文字回应你!
Python中的命令行程序
在Python中,我们主要使用以下函数来实现命令行程序:
input()- 获取用户的输入print()- 显示信息给用户条件语句- 根据用户的输入判断要做什么循环语句- 让程序持续运行,多次接收命令字典/列表- 存储数据(如课表)文件操作- 保存数据到文件时间库- 处理日期和时间正则表达式- 理解各种说法(周一/星期一/礼拜一)
第一步:最简单的课表查询系统
让我们从最简单的开始:只能查询,不能修改,程序退出后数据就丢失了。
程序1:固定课表查询
# 最简单的课表查询程序
# 使用字典存储课表信息
# 定义课表字典
schedule = {
"周一": "语文、数学、英语",
"周二": "数学、语文、体育",
"周三": "英语、科学、美术",
"周四": "音乐、数学、语文",
"周五": "体育、英语、班会"
}
# 欢迎信息
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("支持查询: 周一 到 周日")
print("输入 '退出' 结束程序")
print("=" * 40)
# 主循环
while True:
# 获取用户输入
day = input("\n请输入要查询的星期: ")
# 判断是否要退出
if day == "退出":
print("谢谢使用,再见!")
break
# 查询课表
if day in schedule:
print(f"\n{day}的课程是: {schedule[day]}")
else:
print(f"\n抱歉,{day}没有课,好好休息吧!")
运行示例:
========================================
欢迎使用课表查询系统
========================================
支持查询: 周一 到 周日
输入 '退出' 结束程序
========================================
请输入要查询的星期: 周一
周一的课程是: 语文、数学、英语
请输入要查询的星期: 周六
抱歉,周六没有课,好好休息吧!
请输入要查询的星期: 退出
谢谢使用,再见!
给家长的小贴士
教学重点:
- 字典的键值对:
schedule[day]通过星期几(键)找到课程(值) in操作符:if day in schedule判断这个键是否存在while True循环: 让程序持续运行,直到用户输入“退出“break语句: 跳出循环,结束程序
常见问题:
-
问: 为什么用字典不用列表?
-
答: 字典可以通过“周一“直接找到课程,列表需要遍历查找,字典更方便!
-
问:
while True不是会永远循环吗? -
答: 是的,但我们在循环中用
break跳出来,所以不会永远运行
扩展思考:
- 如果课程有很多节,用字符串存储不方便怎么办?(提示:用列表)
- 如何让程序同时识别“周一“、“星期一”、“礼拜一”?
练习1:完善基本课表查询
请完成以下任务:
任务: 修改上面的程序,让它:
- 用列表存储每天的课程(因为可能有多节课)
- 增加周末的课程(周六、周日)
🔍 查看答案
# 用列表存储每天的课程
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [], # 空列表表示没有课
"周日": [] # 空列表表示没有课
}
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("支持查询: 周一 到 周日")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
day = input("\n请输入要查询的星期: ")
if day == "退出":
print("谢谢使用,再见!")
break
if day in schedule:
courses = schedule[day]
if courses: # 列表不为空
print(f"\n{day}的课程有: {', '.join(courses)}")
else: # 列表为空
print(f"\n{day}没有课,好好休息吧!")
else:
print(f"\n输入错误,请输入周一到周日之间!")
改进说明:
- 每天的课程用列表存储:
["语文", "数学", "英语"] - 用
if courses:判断列表是否为空 - 用
', '.join(courses)把列表变成字符串,用逗号分隔
第二步:理解同义词(周一/星期一/礼拜一)
用户可能会说:
- “周一”
- “星期一”
- “礼拜一”
- “周1”
这些都表示同一天!我们需要让程序理解它们是同一个意思。
方法1:用多个键指向同一个值
# 用多个键指向同一个列表
courses_monday = ["语文", "数学", "英语"]
schedule = {
"周一": courses_monday,
"星期一": courses_monday,
"礼拜一": courses_monday,
"周1": courses_monday,
"1": courses_monday,
# ... 其他天的课程
}
print("支持的输入: 周一/星期一/礼拜一/周1/1")
while True:
day = input("\n请输入要查询的星期: ")
if day == "退出":
break
if day in schedule:
courses = schedule[day]
if courses:
print(f"课程有: {', '.join(courses)}")
else:
print("今天没有课!")
else:
print("输入错误,请重新输入!")
优点: 简单易懂 缺点: 要写很多重复的内容
方法2:用函数转换输入(推荐)
更好的方法是:把用户的各种说法,统一转换成标准格式(如“周一“)。
# 创建一个同义词映射表
synonyms = {
# 星期一的同义词
"周一": "周一", "星期一": "周一", "礼拜一": "周一",
"周1": "周一", "星期1": "周一", "礼拜1": "周一", "1": "周一",
# 星期二
"周二": "周二", "星期二": "周二", "礼拜二": "周二",
"周2": "周二", "星期2": "周二", "礼拜2": "周二", "2": "周二",
# 星期三
"周三": "周三", "星期三": "周三", "礼拜三": "周三",
"周3": "周三", "星期3": "周三", "礼拜3": "周三", "3": "周三",
# 星期四
"周四": "周四", "星期四": "周四", "礼拜四": "周四",
"周4": "周四", "星期4": "周四", "礼拜4": "周四", "4": "周四",
# 星期五
"周五": "周五", "星期五": "周五", "礼拜五": "周五",
"周5": "周五", "星期5": "周五", "礼拜5": "周五", "5": "周五",
# 星期六
"周六": "周六", "星期六": "周六", "礼拜六": "周六",
"周6": "周六", "星期6": "周六", "礼拜6": "周六", "6": "周六",
# 星期日
"周日": "周日", "星期日": "周日", "礼拜日": "周日", "礼拜天": "周日", "星期天": "周日",
"周7": "周日", "星期7": "周日", "礼拜7": "周日", "7": "周日", "周0": "周日",
}
# 定义课表(只有标准格式)
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("支持多种说法: 周一/星期一/礼拜一/周1/1")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
day_input = input("\n请输入要查询的星期: ")
if day_input == "退出":
print("谢谢使用,再见!")
break
# 转换用户输入
if day_input in synonyms:
day = synonyms[day_input] # 转换成标准格式
courses = schedule[day]
if courses:
print(f"\n{day}的课程有: {', '.join(courses)}")
else:
print(f"\n{day}没有课,好好休息吧!")
else:
print("\n输入错误,请重新输入!")
运行示例:
请输入要查询的星期: 礼拜一
周一的课程有: 语文, 数学, 英语
请输入要查询的星期: 星期5
周五的课程有: 体育, 英语, 班会
请输入要查询的星期: 8
输入错误,请重新输入!
给家长的小贴士
教学重点:
- 同义词映射: 用
synonyms字典把各种说法映射到标准格式 - 分离数据和逻辑:
schedule只存储标准格式,不存储所有同义词 - 查表转换:
day = synonyms[day_input]把用户输入转换成标准格式
优点:
- 代码更清晰,易于维护
- 增加新的同义词很容易
- 课表数据不冗余
扩展思考:
- 如果用户输入“星斯一“(错别字),怎么办?(提示:可以用模糊匹配或提示正确写法)
- 如何让程序记住用户最常用的说法,下次优先显示?
练习2:增加更多同义词
任务: 修改上面的程序,增加以下同义词的支持:
- “monday”, “Mon”, “mon” (英文)
- “星期天” (和“星期日“都指周日)
🔍 查看答案
# 同义词映射表
synonyms = {
# 星期一
"周一": "周一", "星期一": "周一", "礼拜一": "周一",
"周1": "周一", "星期1": "周一", "礼拜1": "周一", "1": "周一",
"monday": "周一", "mon": "周一", "Mon": "周一",
# 星期二
"周二": "周二", "星期二": "周二", "礼拜二": "周二",
"周2": "周二", "星期2": "周二", "礼拜2": "周二", "2": "周二",
"tuesday": "周二", "tue": "周二", "Tue": "周二",
# ... (星期三到星期五类似)
# 星期日
"周日": "周日", "星期日": "周日", "星期天": "周日",
"礼拜日": "周日", "礼拜天": "周日",
"周7": "周日", "星期7": "周日", "礼拜7": "周日", "7": "周日", "周0": "周日",
"sunday": "周日", "sun": "周日", "Sun": "周日",
}
# 定义课表
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("支持中文/英文: 周一/星期一/monday/mon")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
day_input = input("\n请输入要查询的星期: ").lower() # 转换成小写
if day_input == "退出":
print("谢谢使用,再见!")
break
if day_input in synonyms:
day = synonyms[day_input]
courses = schedule[day]
if courses:
print(f"\n{day}的课程有: {', '.join(courses)}")
else:
print(f"\n{day}没有课,好好休息吧!")
else:
print("\n输入错误,请重新输入!")
改进说明:
- 在
synonyms中增加英文同义词 - 使用
.lower()把用户输入转换成小写,这样“Monday“和“monday“都能识别 - 增加了“星期天“的同义词
第三步:支持上午和下午
学校的课表通常会区分上午和下午,让我们来实现这个功能。
⏰ 数学小知识:时间计算
在编写课表程序时,我们会用到很多时间计算的知识!
小学数学知识点:时间单位换算
1小时 = 60分钟
1分钟 = 60秒
半天 = 4节课 (每节40-45分钟)
实际应用:
- 如果上午8:00开始上课,每节课40分钟,课间休息10分钟
- 第1节课: 8:00 - 8:40
- 第2节课: 8:50 - 9:30 (课间休息10分钟)
- 第3节课: 9:40 - 10:20
- 第4节课: 10:30 - 11:10
你能算出:
- 上午4节课一共多少分钟?(40 × 4 = 160分钟)
- 160分钟 = 多少小时多少分钟?(2小时40分钟)
- 如果下午也是4节课,全天一共多少分钟?(320分钟 = 5小时20分钟)
这些时间计算在我们的课表程序中都会用到!
程序3:带时间信息的课表系统
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 上午下午的同义词
time_synonyms = {
"上午": "上午", "am": "上午", "早上": "上午", "早晨": "上午",
"下午": "下午", "pm": "下午", "午后": "下午",
}
# 定义课表(嵌套字典: 星期 -> 时间段 -> 课程列表)
schedule = {
"周一": {
"上午": ["语文", "数学", "英语"],
"下午": ["体育", "音乐"]
},
"周二": {
"上午": ["数学", "语文", "英语"],
"下午": ["科学", "美术"]
},
"周三": {
"上午": ["英语", "数学", "语文"],
"下午": ["体育", "班会"]
},
"周四": {
"上午": ["音乐", "语文", "数学"],
"下午": ["美术", "科学"]
},
"周五": {
"上午": ["体育", "英语", "语文"],
"下午": ["综合实践"]
},
"周六": {"上午": [], "下午": []},
"周日": {"上午": [], "下午": []}
}
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("查询方式:")
print("1. 输入 '周一' - 查询周一全天课程")
print("2. 输入 '周一上午' 或 '周一 am' - 查询周上午课程")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入要查询的: ")
if user_input == "退出":
print("谢谢使用,再见!")
break
# 尝试解析用户输入
found = False # 标记是否找到匹配
# 先尝试匹配"星期+时间"的组合(如"周一上午")
for day_syn, day_std in synonyms.items():
for time_syn, time_std in time_synonyms.items():
# 检查是否包含"星期+时间"或"时间+星期"
if day_syn in user_input and time_syn in user_input:
# 找到了匹配
courses = schedule[day_std][time_std]
if courses:
print(f"\n{day_std}{time_std}的课程有: {', '.join(courses)}")
else:
print(f"\n{day_std}{time_std}没有课,好好休息!")
found = True
break
if found:
break
# 如果没有找到"星期+时间",尝试只匹配"星期"
if not found:
for day_syn, day_std in synonyms.items():
if day_syn in user_input or user_input == day_syn:
day_schedule = schedule[day_std]
morning_courses = day_schedule["上午"]
afternoon_courses = day_schedule["下午"]
print(f"\n{day_std}的课程安排:")
print(f" 上午: {', '.join(morning_courses) if morning_courses else '无课'}")
print(f" 下午: {', '.join(afternoon_courses) if afternoon_courses else '无课'}")
found = True
break
if not found:
print("\n输入错误,请重新输入!")
运行示例:
请输入要查询的: 周一上午
周一上午的课程有: 语文, 数学, 英语
请输入要查询的: 星期二下午
星期二下午的课程有: 科学, 美术
请输入要查询的: 周三
周三的课程安排:
上午: 英语, 数学, 语文
下午: 体育, 班会
请输入要查询的: 礼拜五am
周五上午的课程有: 体育, 英语, 语文
给家长的小贴士
教学重点:
- 嵌套字典:
schedule[day][time]先通过星期找到上午/下午的字典,再通过时间找到课程列表 - 两层循环: 外层循环遍历所有星期的同义词,内层循环遍历所有时间的同义词
in操作符:if day_syn in user_input检查用户输入是否包含某个关键词break语句: 找到匹配后跳出循环,避免重复查找found标志: 跟踪是否找到匹配,如果没有找到则提示输入错误
数据结构图示:
schedule (字典)
├── "周一" (字典)
│ ├── "上午" → ["语文", "数学", "英语"]
│ └── "下午" → ["体育", "音乐"]
├── "周二" (字典)
│ ├── "上午" → ["数学", "语文", "英语"]
│ └── "下午" → ["科学", "美术"]
└── ...
常见问题:
- 问: 为什么不用
if day_syn in user_input and time_syn in user_input:? - 答: 因为用户可能输入“上午周一“或“周一上午“,所以两种顺序都要判断
优化建议:
- 上面的代码效率不高,因为要遍历所有同义词
- 可以优化:先提取用户输入中的关键词,再匹配
练习3:支持“第几节课“的查询
任务: 修改上面的程序,支持以下查询:
- “周一第1节” → 查询周一第1节课
- “周二第2节” → 查询周二第2节课
🔍 查看答案
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 定义课表(按节次存储)
schedule = {
"周一": ["语文", "数学", "英语", "体育", "音乐"],
"周二": ["数学", "语文", "英语", "科学", "美术"],
"周三": ["英语", "数学", "语文", "体育", "班会"],
"周四": ["音乐", "语文", "数学", "美术", "科学"],
"周五": ["体育", "英语", "语文", "综合实践", "阅读"],
"周六": [],
"周日": []
}
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("查询方式:")
print("1. 输入 '周一' - 查询周一全天课程")
print("2. 输入 '周一第1节' 或 '周一1' - 查询周一第1节")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入要查询的: ")
if user_input == "退出":
print("谢谢使用,再见!")
break
found = False
# 先尝试匹配"星期+第几节"
for day_syn, day_std in synonyms.items():
# 检查是否包含这个星期
if day_syn in user_input or user_input == day_syn:
# 尝试提取"第几节"
if "第" in user_input and "节" in user_input:
# 提取数字
for i in range(1, 10): # 假设最多9节课
if f"第{i}节" in user_input or f"{i}" == user_input.strip()[-1]:
courses = schedule[day_std]
if i <= len(courses):
print(f"\n{day_std}第{i}节课是: {courses[i-1]}")
else:
print(f"\n{day_std}第{i}节没有课!")
found = True
break
else:
# 只查询星期,显示全天课程
courses = schedule[day_std]
if courses:
print(f"\n{day_std}的课程有:")
for i, course in enumerate(courses, 1):
print(f" 第{i}节: {course}")
else:
print(f"\n{day_std}没有课,好好休息!")
found = True
break
if not found:
print("\n输入错误,请重新输入!")
运行示例:
请输入要查询的: 周一第1节
周一第1节课是: 语文
请输入要查询的: 周二第3节
周二第3节课是: 英语
请输入要查询的: 周三
周三的课程有:
第1节: 英语
第2节: 数学
第3节: 语文
第4节: 体育
第5节: 班会
改进说明:
- 把课表改成列表,每个元素代表一节课
- 用
enumerate(courses, 1)遍历列表,同时获取节次和课程 - 用
courses[i-1]获取第i节课(索引从0开始,所以是i-1)
练习3.5:时间计算挑战 🧮
现在让我们用编程来练习数学中的时间计算!
任务: 编写一个程序,计算上课的总时长
# 每节课的时间信息(分钟)
class_duration = 40 # 每节课40分钟
break_duration = 10 # 课间休息10分钟
# 每天的课程安排
daily_schedule = {
"周一": {"上午": 4, "下午": 3}, # 周一上午4节,下午3节
"周二": {"上午": 4, "下午": 3},
"周三": {"上午": 4, "下午": 3},
"周四": {"上午": 4, "下午": 3},
"周五": {"上午": 4, "下午": 2},
}
print("=" * 40)
print(" 课程时间计算器")
print("=" * 40)
# 计算某天的上课总时长
day = input("请输入要计算的星期(如'周一'): ")
if day in daily_schedule:
morning_classes = daily_schedule[day]["上午"]
afternoon_classes = daily_schedule[day]["下午"]
total_classes = morning_classes + afternoon_classes
# 计算上课总时长(分钟)
total_minutes = total_classes * class_duration
# 计算在校总时长(包括课间休息)
total_breaks = (morning_classes - 1) + (afternoon_classes - 1) + 1 # 上午课间+下午课间+午休
total_with_breaks = total_minutes + total_breaks * break_duration + 60 # +60分钟午休
# 转换成小时和分钟
hours = total_minutes // 60
minutes = total_minutes % 60
print(f"\n{day}的课程安排:")
print(f" 上午: {morning_classes}节课")
print(f" 下午: {afternoon_classes}节课")
print(f" 总共: {total_classes}节课")
print(f"\n上课总时长: {total_minutes}分钟 = {hours}小时{minutes}分钟")
print(f"在校时长(含课间): {total_with_breaks}分钟")
else:
print("输入错误,请重新输入!")
运行示例:
请输入要计算的星期(如'周一'): 周一
周一的课程安排:
上午: 4节课
下午: 3节课
总共: 7节课
上课总时长: 280分钟 = 4小时40分钟
在校时长(含课间): 420分钟
🧮 数学练习:
-
基础题: 如果每节课45分钟,课间休息10分钟,计算周一在校总时长?
- 提示: 7节课 × 45分钟 = ?
-
进阶题: 一周5天,每天平均6节课,一周总共上多少分钟课?
- 提示: 5天 × 6节课 × 40分钟 = ?
- 答案: 1200分钟 = 20小时!
-
挑战题: 如果你每天早上7:30到校,下午4:30放学,你在学校多少小时?
- 提示: 下午4:30 = 16:30
- 计算: 16:30 - 7:30 = ?
🔍 查看答案
# 答案1: 每节课45分钟
class_duration = 45
total_minutes = 7 * 45 # 315分钟
hours = 315 // 60 # 5小时
minutes = 315 % 60 # 15分钟
print(f"周一上课总时长: {hours}小时{minutes}分钟") # 5小时15分钟
# 答案2: 一周总时长
weekly_minutes = 5 * 6 * 40 # 1200分钟
weekly_hours = 1200 // 60 # 20小时
print(f"一周上课总时长: {weekly_hours}小时") # 20小时
# 答案3: 在校时长计算
# 16:30 - 7:30 = 9小时
print("在校时长: 9小时")
第四步:支持日期查询(10月15日是星期几?)
现在我们要实现一个更高级的功能:用户输入“10月15日“,程序自动判断是星期几,然后查询课表!
这需要用到时间库(time库或datetime库)。
程序4:支持日期查询
import datetime # 导入时间库
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 定义课表
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
# 定义一个函数:根据日期判断星期几
def get_weekday(date_string):
"""
根据日期字符串(如"10月15日"或"10-15")判断星期几
返回"周一"、"周二"等
"""
# 获取当前年份
current_year = datetime.datetime.now().year
# 尝试解析日期
try:
# 方式1: "10月15日" → "10-15"
date_string = date_string.replace("月", "-").replace("日", "").replace(" ", "")
# 方式2: "10/15"
if "/" in date_string:
month, day = date_string.split("/")
# 方式3: "10-15"
elif "-" in date_string:
month, day = date_string.split("-")
else:
return None # 无法解析
# 转换成整数
month = int(month)
day = int(day)
# 创建日期对象
date_obj = datetime.date(current_year, month, day)
# 获取星期几(0=周一, 6=周日)
weekday = date_obj.weekday()
# 转换成中文
weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
return weekdays[weekday]
except:
return None # 解析失败
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("查询方式:")
print("1. 输入 '周一' - 查询周一课程")
print("2. 输入 '10月15日' 或 '10-15' - 自动判断星期几并查询")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入要查询的: ")
if user_input == "退出":
print("谢谢使用,再见!")
break
found = False
# 先尝试匹配星期
for day_syn, day_std in synonyms.items():
if day_syn in user_input or user_input == day_syn:
courses = schedule[day_std]
if courses:
print(f"\n{day_std}的课程有: {', '.join(courses)}")
else:
print(f"\n{day_std}没有课,好好休息!")
found = True
break
# 如果没有匹配到星期,尝试解析为日期
if not found:
weekday = get_weekday(user_input)
if weekday:
courses = schedule[weekday]
print(f"\n{user_input} 是 {weekday}")
if courses:
print(f"课程有: {', '.join(courses)}")
else:
print(f"今天没有课,好好休息!")
found = True
if not found:
print("\n输入错误,请重新输入!")
运行示例:
请输入要查询的: 10月15日
10月15日 是 周二
课程有: 数学, 语文, 体育
请输入要查询的: 10-20
10-20 是 周日
今天没有课,好好休息!
请输入要查询的: 周五
周五的课程有: 体育, 英语, 班会
给家长的小贴士
教学重点:
datetime库: Python内置的时间处理库datetime.date(year, month, day): 创建一个日期对象.weekday()方法: 返回星期几(0=周一, 6=周日)- 字符串操作:
.replace()替换字符,.split()分割字符串 - 异常处理:
try-except捕获错误,避免程序崩溃
🖥️ 计算机知识延伸:
1. 时间戳(Timestamp)
- 计算机内部用时间戳表示时间:从1970年1月1日0时0分0秒到现在的秒数
- 例如: 2025年10月15日的时间戳可能是
1728950400 - 为什么要用时间戳? 方便计算时间差!
2. UTC时间和本地时间
- UTC时间: 世界标准时间(格林威治时间)
- 本地时间: 你所在时区的时间(如北京时间 = UTC+8)
- 计算机通常存储UTC时间,显示时转换成本地时间
3. 时区问题
- 如果你的用户在不同国家,需要考虑时区差异
- 例如: 北京时间是晚上8点,伦敦时间是中午12点
家长如何辅导:
- 🔍 观察生活: 和孩子一起观察生活中的时间表示(钟表、日历、手机时间)
- 🧮 数学联系: 用时间计算复习小学数学的时间单位换算
- 🌍 地理联系: 通过时区学习地理知识(不同国家的时差)
- 💻 技术联系: 了解计算机如何存储和处理时间数据
datetime 库详解:
import datetime
# 获取当前日期
today = datetime.date.today()
print(today) # 2025-10-15
# 创建指定日期
date_obj = datetime.date(2025, 10, 15)
print(date_obj) # 2025-10-15
# 获取星期几
weekday = date_obj.weekday()
print(weekday) # 1 (表示周二)
# 获取年、月、日
print(date_obj.year) # 2025
print(date_obj.month) # 10
print(date_obj.day) # 15
常见问题:
- 问: 为什么
weekday()返回0-6,不是1-7? - 答: 这是计算机的惯例,0表示周一,6表示周日
- 问:
try-except是什么? - 答: try尝试执行代码,如果出错就执行except中的代码,避免程序崩溃
扩展思考:
- 如何支持“明天“、“后天”、“下周三”?(提示:计算日期偏移)
- 如何跨年查询?(提示:解析年份)
练习4:支持“明天“和“后天“
任务: 修改上面的程序,支持以下查询:
- “明天” → 查询明天的课程
- “后天” → 查询后天的课程
- “昨天” → 查询昨天的课程
🔍 查看答案
import datetime
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 定义课表
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
# 定义一个函数:根据日期判断星期几
def get_weekday(date_obj):
"""根据日期对象返回星期几"""
weekday = date_obj.weekday()
weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
return weekdays[weekday]
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("查询方式:")
print("1. 输入 '周一' - 查询周一课程")
print("2. 输入 '10月15日' - 查询指定日期的课程")
print("3. 输入 '明天'、'后天'、'昨天' - 查询相对日期的课程")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入要查询的: ")
if user_input == "退出":
print("谢谢使用,再见!")
break
found = False
# 先尝试匹配星期
for day_syn, day_std in synonyms.items():
if day_syn in user_input or user_input == day_syn:
courses = schedule[day_std]
if courses:
print(f"\n{day_std}的课程有: {', '.join(courses)}")
else:
print(f"\n{day_std}没有课,好好休息!")
found = True
break
# 如果没有匹配到星期,尝试特殊关键词
if not found:
# 获取今天的日期
today = datetime.date.today()
# 判断"明天"、"后天"、"昨天"
if user_input == "明天":
tomorrow = today + datetime.timedelta(days=1)
weekday = get_weekday(tomorrow)
courses = schedule[weekday]
print(f"\n明天是 {weekday}")
print(f"课程有: {', '.join(courses) if courses else '无课'}")
found = True
elif user_input == "后天":
day_after_tomorrow = today + datetime.timedelta(days=2)
weekday = get_weekday(day_after_tomorrow)
courses = schedule[weekday]
print(f"\n后天是 {weekday}")
print(f"课程有: {', '.join(courses) if courses else '无课'}")
found = True
elif user_input == "昨天":
yesterday = today - datetime.timedelta(days=1)
weekday = get_weekday(yesterday)
courses = schedule[weekday]
print(f"\n昨天是 {weekday}")
print(f"课程有: {', '.join(courses) if courses else '无课'}")
found = True
else:
# 尝试解析为日期
try:
current_year = today.year
date_string = user_input.replace("月", "-").replace("日", "").replace(" ", "")
if "/" in date_string:
month, day = date_string.split("/")
elif "-" in date_string:
month, day = date_string.split("-")
else:
raise ValueError("无法解析日期")
month = int(month)
day = int(day)
date_obj = datetime.date(current_year, month, day)
weekday = get_weekday(date_obj)
courses = schedule[weekday]
print(f"\n{user_input} 是 {weekday}")
print(f"课程有: {', '.join(courses) if courses else '无课'}")
found = True
except:
pass # 解析失败,继续检查其他情况
if not found:
print("\n输入错误,请重新输入!")
运行示例:
请输入要查询的: 明天
明天是 周三
课程有: 英语, 科学, 美术
请输入要查询的: 后天
后天是 周四
课程有: 音乐, 数学, 语文
请输入要查询的: 昨天
昨天是 周一
课程有: 语文, 数学, 英语
改进说明:
- 使用
datetime.timedelta(days=1)表示时间差(1天) today + timedelta(days=1)→ 明天today - timedelta(days=1)→ 昨天today + timedelta(days=2)→ 后天
第五步:添加课程、修改课程、删除课程
现在我们的课表系统只能查询,接下来要增加增删改功能!
程序5:完整的课表管理系统
import datetime
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 定义课表
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
# 定义一个函数:根据用户输入找到星期几
def find_weekday(user_input):
"""根据用户输入返回星期几(标准格式)"""
for day_syn, day_std in synonyms.items():
if day_syn in user_input or user_input == day_syn:
return day_std
return None # 没找到
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("命令列表:")
print("1. 查询: '周一' 或 '10月15日'")
print("2. 添加: '添加 周一 体育' - 在周一添加体育课")
print("3. 修改: '修改 周一第1节 英语' - 把周一第1节改成英语")
print("4. 删除: '删除 周一第3节' - 删除周一第3节课")
print("5. 显示全部: '显示' 或 '全部'")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入命令: ").strip()
if user_input == "退出":
print("谢谢使用,再见!")
break
# ========== 查询功能 ==========
# 先尝试匹配星期
weekday = find_weekday(user_input)
if weekday and not user_input.startswith(("添加", "修改", "删除")):
courses = schedule[weekday]
if courses:
print(f"\n{weekday}的课程有:")
for i, course in enumerate(courses, 1):
print(f" 第{i}节: {course}")
else:
print(f"\n{weekday}没有课,好好休息!")
continue
# ========== 显示全部课表 ==========
if user_input in ["显示", "全部", "课表"]:
print("\n" + "=" * 40)
print(" 完整课表")
print("=" * 40)
for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]:
courses = schedule[day]
if courses:
print(f"{day}: {', '.join(courses)}")
else:
print(f"{day}: 无课")
print("=" * 40)
continue
# ========== 添加课程 ==========
if user_input.startswith("添加"):
# 提取信息: "添加 周一 体育"
parts = user_input[3:].strip().split() # 去掉"添加",然后按空格分割
if len(parts) >= 2:
# 第一部分是星期,第二部分是课程
weekday_input = parts[0]
course = parts[1]
weekday = find_weekday(weekday_input)
if weekday:
schedule[weekday].append(course) # 添加到列表末尾
print(f"\n✓ 已在{weekday}添加课程: {course}")
else:
print("\n✗ 星期输入错误!")
else:
print("\n✗ 格式错误! 正确格式: 添加 周一 体育")
continue
# ========== 修改课程 ==========
if user_input.startswith("修改"):
# 提取信息: "修改 周一第1节 英语"
content = user_input[3:].strip() # 去掉"修改"
found = False
# 尝试找到星期和节次
for day_syn, day_std in synonyms.items():
if day_syn in content:
# 尝试提取"第X节"
for i in range(1, 10):
if f"第{i}节" in content:
# 提取新课程名称
# 例如: "周一第1节 英语"
course_start = content.find(f"第{i}节") + len(f"第{i}节")
new_course = content[course_start:].strip()
# 修改课程
if i <= len(schedule[day_std]):
old_course = schedule[day_std][i-1]
schedule[day_std][i-1] = new_course
print(f"\n✓ 已把{day_std}第{i}节从'{old_course}'修改为'{new_course}'")
else:
print(f"\n✗ {day_std}第{i}节不存在!")
found = True
break
if found:
break
if not found:
print("\n✗ 格式错误! 正确格式: 修改 周一第1节 英语")
continue
# ========== 删除课程 ==========
if user_input.startswith("删除"):
# 提取信息: "删除 周一第3节"
content = user_input[3:].strip() # 去掉"删除"
found = False
# 尝试找到星期和节次
for day_syn, day_std in synonyms.items():
if day_syn in content:
# 尝试提取"第X节"
for i in range(1, 10):
if f"第{i}节" in content:
# 删除课程
if i <= len(schedule[day_std]):
deleted_course = schedule[day_std].pop(i-1)
print(f"\n✓ 已删除{day_std}第{i}节: {deleted_course}")
else:
print(f"\n✗ {day_std}第{i}节不存在!")
found = True
break
if found:
break
if not found:
print("\n✗ 格式错误! 正确格式: 删除 周一第3节")
continue
# 如果都不匹配,提示错误
print("\n✗ 无法识别的命令,请重新输入!")
运行示例:
请输入命令: 添加 周一 体育
✓ 已在周一添加课程: 体育
请输入命令: 添加 周二 音乐
✓ 已在周二添加课程: 音乐
请输入命令: 修改 周一第1节 英语
✓ 已把周一第1节从'语文'修改为'英语'
请输入命令: 删除 周三第2节
✓ 已删除周三第2节: 科学
请输入命令: 显示
========================================
完整课表
========================================
周一: 英语, 数学, 英语, 体育
周二: 数学, 语文, 体育, 音乐
周三: 英语, 美术
周四: 音乐, 数学, 语文
周五: 体育, 英语, 班会
周六: 无课
周日: 无课
========================================
给家长的小贴士
教学重点:
.startswith()方法: 判断字符串是否以某个词开头.split()方法: 按空格分割字符串.append()方法: 在列表末尾添加元素.pop(index)方法: 删除指定索引的元素continue语句: 跳过本次循环,进入下一次循环- 字符串切片:
user_input[3:]去掉前3个字符
命令解析技巧:
# "添加 周一 体育"
command = user_input[:2] # "添加"
content = user_input[2:] # " 周一 体育"
weekday = content.split()[0] # "周一"
course = content.split()[1] # "体育"
常见错误:
- 错误: 忘记用
.strip()去掉首尾空格 - 后果:
"添加"和"添加 "会被判断为不同的命令 - 解决:
user_input.strip()
练习5:完善增删改功能
任务: 修改上面的程序,增加以下功能:
- 清空课程: “清空 周一” → 清空周一的所有课程
- 插入课程: “插入 周一第2节 美术” → 在周一第2节位置插入美术课
- 课程统计: “统计” → 显示每周共多少节课
🔍 查看答案
# 在上面的程序基础上,增加以下功能:
# ========== 清空课程 ==========
if user_input.startswith("清空"):
content = user_input[2:].strip()
weekday = find_weekday(content)
if weekday:
count = len(schedule[weekday])
schedule[weekday] = [] # 清空列表
print(f"\n✓ 已清空{weekday}的所有课程 (共{count}节)")
else:
print("\n✗ 星期输入错误!")
continue
# ========== 插入课程 ==========
if user_input.startswith("插入"):
content = user_input[2:].strip()
found = False
for day_syn, day_std in synonyms.items():
if day_syn in content:
for i in range(1, 10):
if f"第{i}节" in content:
# 提取课程名称
course_start = content.find(f"第{i}节") + len(f"第{i}节")
new_course = content[course_start:].strip()
# 插入课程
if i <= len(schedule[day_std]) + 1:
schedule[day_std].insert(i-1, new_course)
print(f"\n✓ 已在{day_std}第{i}节插入: {new_course}")
else:
print(f"\n✗ 节次超出范围!")
found = True
break
if found:
break
if not found:
print("\n✗ 格式错误! 正确格式: 插入 周一第2节 美术")
continue
# ========== 课程统计 ==========
if user_input in ["统计", "总数"]:
total = 0
print("\n" + "=" * 40)
print(" 课程统计")
print("=" * 40)
for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]:
count = len(schedule[day])
total += count
print(f"{day}: {count}节课")
print("=" * 40)
print(f"每周共 {total} 节课")
print("=" * 40)
continue
运行示例:
请输入命令: 清空 周六
✓ 已清空周六的所有课程 (共0节)
请输入命令: 插入 周二第2节 计算机
✓ 已在周二第2节插入: 计算机
请输入命令: 统计
========================================
课程统计
========================================
周一: 4节课
周二: 4节课
周三: 2节课
周四: 3节课
周五: 3节课
周六: 0节课
周日: 0节课
========================================
每周共 16 节课
========================================
第六步:保存到文件(数据持久化)
现在程序有个大问题:关闭程序后,所有修改都会丢失!我们需要把课表保存到文件,下次打开时还能用。
💾 计算机小知识:文件系统和硬盘
什么是文件系统?
文件系统是计算机组织和管理文件的方式。你可以把它想象成一个超级大的文件柜:
- 📁 文件夹(目录):像文件柜的抽屉,用来分类存放文件
- 📄 文件:像文件柜里的文件,存放具体的内容(文字、图片、程序等)
- 🔍 路径:文件的地址,告诉计算机去哪里找这个文件
文件存在哪里?
文件保存在计算机的硬盘(Hard Disk) 或 固态硬盘(SSD) 中:
┌─────────────────────────────────┐
│ 你的电脑 │
│ ┌──────────┐ ┌──────────┐ │
│ │ 内存 │ │ 硬盘 │ │
│ │ (RAM) │ │ (HDD/SSD)│ │
│ │ │ │ │ │
│ │ 程序运行 │ │ 文件存储 │ │
│ │ 时的数据 │ │ 永久数据 │ │
│ └──────────┘ └──────────┘ │
│ ↑ ↑ │
│ 断电丢失 断电保留 │
└─────────────────────────────────┘
内存 vs 硬盘的区别:
| 特点 | 内存(RAM) | 硬盘(HDD/SSD) |
|---|---|---|
| 速度 | 非常快 | 慢一些 |
| 容量 | 相对小 | 很大 |
| 数据保留 | 断电后丢失 | 断电后保留 |
| 用途 | 运行程序 | 存储文件 |
| 价格 | 较贵 | 较便宜 |
为什么需要保存到文件?
当我们运行Python程序时:
- 程序和数据(如课表)都存储在内存中
- 如果不保存到文件,关闭程序后数据就会丢失
- 保存到文件后,数据存储在硬盘中,下次打开还能用
JSON是什么?
JSON是一种数据格式,就像一个“快递箱“,可以把Python的字典、列表打包,存到文件里:
# Python字典
schedule = {"周一": ["语文", "数学"]}
↓ 转换成JSON字符串
'{"周一": ["语文", "数学"]}'
↓ 保存到硬盘文件
schedule.json (硬盘上的文件)
程序6:支持文件保存和加载
import datetime
import json # 导入JSON库,用于保存数据
# 同义词映射表
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 定义文件名
FILENAME = "schedule.json"
# 定义课表(默认数据)
default_schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
# 定义一个函数:加载课表
def load_schedule():
"""从文件加载课表,如果文件不存在则使用默认课表"""
try:
with open(FILENAME, "r", encoding="utf-8") as f:
data = f.read()
schedule = json.loads(data)
print(f"\n✓ 已从 {FILENAME} 加载课表")
return schedule
except FileNotFoundError:
print(f"\n✗ 文件 {FILENAME} 不存在,使用默认课表")
return default_schedule.copy() # 复制一份,避免修改原数据
except Exception as e:
print(f"\n✗ 加载失败: {e}")
return default_schedule.copy()
# 定义一个函数:保存课表
def save_schedule(schedule):
"""把课表保存到文件"""
try:
data = json.dumps(schedule, ensure_ascii=False, indent=2)
with open(FILENAME, "w", encoding="utf-8") as f:
f.write(data)
print(f"\n✓ 课表已保存到 {FILENAME}")
except Exception as e:
print(f"\n✗ 保存失败: {e}")
# 定义一个函数:根据用户输入找到星期几
def find_weekday(user_input):
"""根据用户输入返回星期几(标准格式)"""
for day_syn, day_std in synonyms.items():
if day_syn in user_input or user_input == day_syn:
return day_std
return None # 没找到
# 加载课表
schedule = load_schedule()
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("命令列表:")
print("1. 查询: '周一' 或 '10月15日'")
print("2. 添加: '添加 周一 体育' - 在周一添加体育课")
print("3. 修改: '修改 周一第1节 英语' - 把周一第1节改成英语")
print("4. 删除: '删除 周一第3节' - 删除周一第3节课")
print("5. 显示: '显示' 或 '全部'")
print("6. 保存: '保存' - 保存课表到文件")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入命令: ").strip()
if user_input == "退出":
# 退出前自动保存
save_schedule(schedule)
print("谢谢使用,再见!")
break
# ========== 查询功能 ==========
weekday = find_weekday(user_input)
if weekday and not user_input.startswith(("添加", "修改", "删除", "清空", "插入")):
courses = schedule[weekday]
if courses:
print(f"\n{weekday}的课程有:")
for i, course in enumerate(courses, 1):
print(f" 第{i}节: {course}")
else:
print(f"\n{weekday}没有课,好好休息!")
continue
# ========== 显示全部课表 ==========
if user_input in ["显示", "全部", "课表"]:
print("\n" + "=" * 40)
print(" 完整课表")
print("=" * 40)
for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]:
courses = schedule[day]
if courses:
print(f"{day}: {', '.join(courses)}")
else:
print(f"{day}: 无课")
print("=" * 40)
continue
# ========== 保存课表 ==========
if user_input in ["保存", "save"]:
save_schedule(schedule)
continue
# ========== 添加课程 ==========
if user_input.startswith("添加"):
parts = user_input[3:].strip().split()
if len(parts) >= 2:
weekday_input = parts[0]
course = parts[1]
weekday = find_weekday(weekday_input)
if weekday:
schedule[weekday].append(course)
print(f"\n✓ 已在{weekday}添加课程: {course}")
else:
print("\n✗ 星期输入错误!")
else:
print("\n✗ 格式错误! 正确格式: 添加 周一 体育")
continue
# ========== 修改课程 ==========
if user_input.startswith("修改"):
content = user_input[3:].strip()
found = False
for day_syn, day_std in synonyms.items():
if day_syn in content:
for i in range(1, 10):
if f"第{i}节" in content:
course_start = content.find(f"第{i}节") + len(f"第{i}节")
new_course = content[course_start:].strip()
if i <= len(schedule[day_std]):
old_course = schedule[day_std][i-1]
schedule[day_std][i-1] = new_course
print(f"\n✓ 已把{day_std}第{i}节从'{old_course}'修改为'{new_course}'")
else:
print(f"\n✗ {day_std}第{i}节不存在!")
found = True
break
if found:
break
if not found:
print("\n✗ 格式错误! 正确格式: 修改 周一第1节 英语")
continue
# ========== 删除课程 ==========
if user_input.startswith("删除"):
content = user_input[3:].strip()
found = False
for day_syn, day_std in synonyms.items():
if day_syn in content:
for i in range(1, 10):
if f"第{i}节" in content:
if i <= len(schedule[day_std]):
deleted_course = schedule[day_std].pop(i-1)
print(f"\n✓ 已删除{day_std}第{i}节: {deleted_course}")
else:
print(f"\n✗ {day_std}第{i}节不存在!")
found = True
break
if found:
break
if not found:
print("\n✗ 格式错误! 正确格式: 删除 周一第3节")
continue
# 如果都不匹配,提示错误
print("\n✗ 无法识别的命令,请重新输入!")
运行示例:
✓ 已从 schedule.json 加载课表
请输入命令: 添加 周二 计算机
✓ 已在周二添加课程: 计算机
请输入命令: 保存
✓ 课表已保存到 schedule.json
请输入命令: 退出
✓ 课表已保存到 schedule.json
谢谢使用,再见!
保存的文件内容 (schedule.json):
{
"周一": [
"语文",
"数学",
"英语"
],
"周二": [
"数学",
"语文",
"体育",
"计算机"
],
"周三": [
"英语",
"科学",
"美术"
],
"周四": [
"音乐",
"数学",
"语文"
],
"周五": [
"体育",
"英语",
"班会"
],
"周六": [],
"周日": []
}
给家长的小贴士
教学重点:
json库: 用于在文件中存储字典和列表json.dumps(): 把Python对象转换成JSON字符串json.loads(): 把JSON字符串转换成Python对象- 文件操作:
open()打开文件,f.read()读取,f.write()写入 - 异常处理:
try-except捕获文件操作错误
💾 计算机知识延伸:
1. 文件的编码(UTF-8)
- 计算机存储文件时需要把字符转换成二进制(0和1)
- UTF-8是一种通用的字符编码标准,支持中文、英文、日文等
- 如果不用UTF-8,中文可能会乱码!
2. 文本文件 vs 二进制文件
- 文本文件: 用字符编码存储,可以直接阅读(如.txt、.json、.md)
- 二进制文件: 用二进制存储,需要专门软件打开(如.jpg、.mp3、.exe)
3. 文件路径
- 相对路径: 相对于当前程序的位置(如
schedule.json) - 绝对路径: 从根目录开始的完整路径(如
C:\Users\张三\schedule.json)
4. 文件读写模式
"r": 只读模式(文件必须存在)"w": 写入模式(会覆盖原文件!)"a": 追加模式(在文件末尾添加)"r+": 读写模式
家长如何辅导:
- 📂 观察文件: 打开
schedule.json文件,让孩子看到JSON格式的结构 - 🔍 对比数据: 修改程序中的课表,保存后观察文件变化
- 💡 讨论存储: 为什么需要把数据保存到文件?关机后数据还在吗?
- 🛡️ 安全意识: 讲解为什么“写入模式“会覆盖原文件,培养数据安全意识
扩展活动:
- 用记事本打开
schedule.json,手动修改课程名称,再运行程序看效果 - 删除
schedule.json文件,看程序如何处理(会使用默认课表) - 把
schedule.json复制一份,体验“备份“的概念
json 库详解:
import json
# Python字典
data = {
"name": "小明",
"age": 10,
"courses": ["语文", "数学", "英语"]
}
# 转换成JSON字符串
json_string = json.dumps(data, ensure_ascii=False, indent=2)
print(json_string)
# 输出:
# {
# "name": "小明",
# "age": 10,
# "courses": ["语文", "数学", "英语"]
# }
# 从JSON字符串转换回Python字典
data2 = json.loads(json_string)
print(data2["name"]) # 小明
文件操作详解:
# 写入文件
with open("schedule.json", "w", encoding="utf-8") as f:
f.write(json_string)
# 读取文件
with open("schedule.json", "r", encoding="utf-8") as f:
content = f.read()
data = json.loads(content)
常见问题:
- 问: 为什么要用
encoding="utf-8"? - 答: 支持中文,避免乱码
- 问:
with open(...)和f = open(); ...; f.close()有什么区别? - 答:
with会自动关闭文件,更安全
第七步:使用正则表达式(高级功能)
现在我们的程序有个问题:用户必须严格按照格式输入命令,比如:
- ✅ “添加 周一 体育”
- ❌ “添加周一体育” (缺少空格)
- ❌ “在周一添加体育课” (格式不对)
**正则表达式(Regular Expression)**可以帮我们灵活地解析用户输入!
什么是正则表达式?
正则表达式是一种匹配字符串的模式。它可以:
- ✅ 灵活匹配各种格式的输入
- ✅ 提取字符串中的关键信息
- ✅ 验证输入格式是否正确
举个例子:
import re
# 匹配"周一"、"星期一"、"礼拜一"
pattern = r"(周一|星期一|礼拜一)"
text = "今天是星期一"
result = re.search(pattern, text)
if result:
print("找到匹配:", result.group()) # 星期一
程序7:使用正则表达式解析命令
import datetime
import json
import re # 导入正则表达式库
# 同义词映射表(保持不变)
synonyms = {
"周一": "周一", "星期一": "周一", "礼拜一": "周一", "周1": "周一", "1": "周一",
"周二": "周二", "星期二": "周二", "礼拜二": "周二", "周2": "周二", "2": "周二",
"周三": "周三", "星期三": "周三", "礼拜三": "周三", "周3": "周三", "3": "周三",
"周四": "周四", "星期四": "周四", "礼拜四": "周四", "周4": "周四", "4": "周四",
"周五": "周五", "星期五": "周五", "礼拜五": "周五", "周5": "周五", "5": "周五",
"周六": "周六", "星期六": "周六", "礼拜六": "周六", "周6": "周六", "6": "周六",
"周日": "周日", "星期日": "周日", "星期天": "周日", "周7": "周日", "7": "周日", "0": "周日",
}
# 文件名
FILENAME = "schedule.json"
# 默认课表
default_schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"],
"周三": ["英语", "科学", "美术"],
"周四": ["音乐", "数学", "语文"],
"周五": ["体育", "英语", "班会"],
"周六": [],
"周日": []
}
# 加载和保存函数(保持不变)
def load_schedule():
try:
with open(FILENAME, "r", encoding="utf-8") as f:
data = f.read()
schedule = json.loads(data)
print(f"\n✓ 已从 {FILENAME} 加载课表")
return schedule
except:
print(f"\n✓ 使用默认课表")
return default_schedule.copy()
def save_schedule(schedule):
try:
data = json.dumps(schedule, ensure_ascii=False, indent=2)
with open(FILENAME, "w", encoding="utf-8") as f:
f.write(data)
print(f"\n✓ 课表已保存")
except Exception as e:
print(f"\n✗ 保存失败: {e}")
# 新函数:使用正则表达式解析命令
def parse_command(user_input):
"""
使用正则表达式解析用户命令
返回: (命令类型, 星期, 节次, 课程名称)
"""
# 定义正则表达式模式
patterns = {
"查询": r"(周一|周二|周三|周四|周五|周六|周日|星期一|星期二|星期三|星期四|星期五|星期六|星期日|礼拜一|礼拜二|礼拜三|礼拜四|礼拜五|礼拜六|礼拜日)",
"添加": r"添加.*?(周一|周二|周三|周四|周五|周六|周日|星期一|星期二|星期三|星期四|星期五|星期六|星期日|礼拜一|礼拜二|礼拜三|礼拜四|礼拜五|礼拜六|礼拜日)\s*(.*)",
"修改": r"修改.*?(周一|周二|周三|周四|周五|周六|周日|星期一|星期二|星期三|星期四|星期五|星期六|星期日|礼拜一|礼拜二|礼拜三|礼拜四|礼拜五|礼拜六|礼拜日).?第(\d+)节\s*(.*)",
"删除": r"删除.*?(周一|周二|周三|周四|周五|周六|周日|星期一|星期二|星期三|星期四|星期五|星期六|星期日|礼拜一|礼拜二|礼拜三|礼拜四|礼拜五|礼拜六|礼拜日).?第(\d+)节",
}
# 尝试匹配每个模式
for cmd_type, pattern in patterns.items():
match = re.search(pattern, user_input)
if match:
groups = match.groups()
if cmd_type == "查询":
return ("查询", groups[0], None, None)
elif cmd_type == "添加":
return ("添加", groups[0], None, groups[1].strip())
elif cmd_type == "修改":
return ("修改", groups[0], int(groups[1]), groups[2].strip())
elif cmd_type == "删除":
return ("删除", groups[0], int(groups[1]), None)
return (None, None, None, None) # 没匹配到
# 加载课表
schedule = load_schedule()
print("=" * 40)
print(" 欢迎使用课表查询系统")
print("=" * 40)
print("命令列表(更灵活的输入方式):")
print("1. 查询: '周一' / '今天是周几' / '查询周一'")
print("2. 添加: '添加周一体育' / '在周一添加体育课'")
print("3. 修改: '修改周一第1节英语' / '把周一第1节改成英语'")
print("4. 删除: '删除周一第3节' / '把周一第3节删了'")
print("5. 显示: '显示' / '全部课表'")
print("6. 保存: '保存'")
print("输入 '退出' 结束程序")
print("=" * 40)
while True:
user_input = input("\n请输入命令: ").strip()
if user_input == "退出":
save_schedule(schedule)
print("谢谢使用,再见!")
break
# 显示全部课表
if user_input in ["显示", "全部", "课表", "全部课表"]:
print("\n" + "=" * 40)
print(" 完整课表")
print("=" * 40)
for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]:
courses = schedule[day]
if courses:
print(f"{day}: {', '.join(courses)}")
else:
print(f"{day}: 无课")
print("=" * 40)
continue
# 保存课表
if user_input in ["保存", "save"]:
save_schedule(schedule)
continue
# 使用正则表达式解析命令
cmd_type, day_input, period, course = parse_command(user_input)
# 转换星期成标准格式
if day_input and day_input in synonyms:
day_std = synonyms[day_input]
else:
day_std = None
# 执行命令
if cmd_type == "查询" and day_std:
courses = schedule[day_std]
if courses:
print(f"\n{day_std}的课程有:")
for i, c in enumerate(courses, 1):
print(f" 第{i}节: {c}")
else:
print(f"\n{day_std}没有课,好好休息!")
elif cmd_type == "添加" and day_std and course:
schedule[day_std].append(course)
print(f"\n✓ 已在{day_std}添加课程: {course}")
elif cmd_type == "修改" and day_std and period and course:
if period <= len(schedule[day_std]):
old_course = schedule[day_std][period-1]
schedule[day_std][period-1] = course
print(f"\n✓ 已把{day_std}第{period}节从'{old_course}'修改为'{course}'")
else:
print(f"\n✗ {day_std}第{period}节不存在!")
elif cmd_type == "删除" and day_std and period:
if period <= len(schedule[day_std]):
deleted_course = schedule[day_std].pop(period-1)
print(f"\n✓ 已删除{day_std}第{period}节: {deleted_course}")
else:
print(f"\n✗ {day_std}第{period}节不存在!")
else:
print("\n✗ 无法识别的命令,请重新输入!")
运行示例:
请输入命令: 查询周一
周一的课程有:
第1节: 语文
第2节: 数学
第3节: 英语
请输入命令: 在周二添加计算机课
✓ 已在周二添加课程: 计算机课
请输入命令: 把周三第2节改成体育
✓ 已把周三第2节从'科学'修改为'体育'
请输入命令: 删除周四第3节课
✓ 已删除周四第3节: 语文
请输入命令: 今天是周几
无法识别的命令,请重新输入!
给家长的小贴士
教学重点:
re库: Python的正则表达式库re.search(): 在字符串中搜索模式.groups(): 获取匹配的分组- 正则表达式语法:
.*?匹配任意字符(非贪婪)(a|b)匹配a或b\d+匹配一个或多个数字\s*匹配零个或多个空格
正则表达式详解:
import re
# 示例1: 提取星期和课程
pattern = r"添加.*?(周一|周二).*?(.*)"
text = "在周一添加体育课"
match = re.search(pattern, text)
if match:
day = match.group(1) # 周一
course = match.group(2) # 体育课
print(day, course)
# 示例2: 提取节次
pattern = r"第(\d+)节"
text = "修改周一第3节英语"
match = re.search(pattern, text)
if match:
period = int(match.group(1)) # 3
print(period)
优点:
- ✅ 用户可以用各种说法表达同一意思
- ✅ 代码更简洁,不需要很多
if判断 - ✅ 易于扩展新的命令格式
缺点:
- ❌ 正则表达式语法复杂,难以学习
- ❌ 调试困难
综合项目:完整的智能课表系统
现在让我们把所有功能整合起来,做一个完整的课表系统!
完整功能列表
- ✅ 查询课程(支持多种说法)
- ✅ 添加/修改/删除课程
- ✅ 支持上午/下午区分
- ✅ 支持日期查询(10月15日)
- ✅ 支持相对日期(明天、后天)
- ✅ 自动保存到文件
- ✅ 正则表达式解析命令
- 🆕 课程提醒功能
- 🆕 课程搜索功能
- 🆕 数据备份功能
挑战练习
请尝试在现有程序基础上,增加以下功能:
挑战1:课程搜索
目标: 用户输入“搜索体育“,显示所有包含“体育“的课程
💡 提示
if user_input.startswith("搜索"):
keyword = user_input[3:].strip()
print(f"\n搜索 '{keyword}':")
found = False
for day in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]:
courses = schedule[day]
for i, course in enumerate(courses, 1):
if keyword in course:
print(f" {day}第{i}节: {course}")
found = True
if not found:
print(f" 没找到包含'{keyword}'的课程")
挑战2:课程提醒
目标: 每次查询时,如果今天的课程很多(>5节),提醒用户“今天课程较重,注意休息!“
💡 提示
# 在查询功能中增加:
if len(courses) > 5:
print(f"\n⚠️ 提醒: 今天课程较多({len(courses)}节),注意休息!")
挑战3:数据备份
目标: 增加“备份“命令,把当前课表复制到 schedule_backup.json
💡 提示
if user_input in ["备份", "backup"]:
backup_filename = "schedule_backup.json"
data = json.dumps(schedule, ensure_ascii=False, indent=2)
with open(backup_filename, "w", encoding="utf-8") as f:
f.write(data)
print(f"\n✓ 已备份到 {backup_filename}")
本章小结
核心知识点回顾
- 命令行程序: 通过文字命令和计算机交互的程序
- 字典应用: 用嵌套字典存储复杂数据(课表)
- 同义词映射: 用字典把各种说法统一成标准格式
- 时间处理: 使用
datetime库处理日期和时间 - 文件操作: 使用
json库保存和加载数据 - 正则表达式: 灵活解析用户输入
- 函数封装: 把重复的代码封装成函数
🖥️ 计算机知识回顾
本章我们学到了重要的计算机体系结构知识:
-
命令行历史
- 早期计算机使用命令行交互(1970-1980年代)
- 命令行占用CPU和内存资源少,运行速度快
- 图形界面占用资源多,但更直观易用
-
文件系统
- 文件系统是计算机组织文件的方式
- 文件夹(目录)用于分类管理文件
- 路径告诉计算机去哪里找文件
-
内存 vs 硬盘
- 内存(RAM): 速度快,断电后数据丢失,用于运行程序
- 硬盘(HDD/SSD): 速度较慢,断电后数据保留,用于存储文件
- 数据需要保存到文件才能持久化
-
数据编码
- UTF-8: 通用字符编码,支持中文等多种语言
- JSON: 轻量级数据交换格式,易于人阅读和编写
- 文本文件 vs 二进制文件
-
时间表示
- 时间戳: 计算机用从1970年1月1日到现在的秒数表示时间
- UTC vs 本地时间: 世界标准时间 vs 你所在时区的时间
- 时区差异: 不同国家的时间差异
🧮 数学知识回顾
本章用到了重要的数学知识:
-
时间单位换算
- 1小时 = 60分钟
- 1分钟 = 60秒
- 时间加减法计算
-
四则运算应用
- 计算上课总时长: 节数 × 分钟数
- 时间单位转换: 分钟 → 小时和分钟
- 整除和取余:
//和%
-
实际应用问题
- 计算在校时长(包括课间)
- 计算一周总课时
- 时间段计算(7:30 - 16:30)
能力检查表
编程能力:
- 能够使用字典存储课表数据
- 能够处理用户的多种说法(同义词)
- 能够使用
datetime库判断星期几 - 能够使用
json库保存和加载数据 - 能够使用正则表达式解析命令
- 能够设计一个完整的命令行程序
计算机知识:
- 理解命令行程序的历史和特点
- 理解文件系统的基本概念
- 理解内存和硬盘的区别
- 理解数据编码(UTF-8、JSON)
- 理解时间戳和时区
数学能力:
- 能够进行时间单位换算
- 能够计算上课时长
- 能够解决实际的时间问题
常见错误和调试
| 错误类型 | 原因 | 解决方法 |
|---|---|---|
KeyError: '周一' | 字典中不存在这个键 | 用 in 检查键是否存在 |
IndexError: list index out of range | 列表索引超出范围 | 检查 i <= len(list) |
FileNotFoundError | 文件不存在 | 用 try-except 捕获异常 |
JSONDecodeError | JSON格式错误 | 检查JSON格式是否正确 |
| 正则表达式不匹配 | 模式书写错误 | 使用在线工具测试正则表达式 |
调试技巧
-
打印中间结果:
print(f"解析结果: cmd={cmd_type}, day={day_std}, period={period}") -
简化问题:
- 先实现简单版本,再逐步增加功能
- 每增加一个功能,测试一次
-
使用在线工具:
- 正则表达式测试: https://regex101.com/
- JSON格式化: https://www.json.cn/
挑战练习
练习1:课程时间表
任务: 在课表中增加每节课的时间,如:
"周一": {
"1": {"课程": "语文", "时间": "8:00-8:45"},
"2": {"课程": "数学", "时间": "8:55-9:40"},
...
}
练习2:课程备注
任务: 为每节课增加备注字段,如:
"周一": [
{"课程": "语文", "备注": "带作文本"},
{"课程": "数学", "备注": "带计算器"},
...
]
练习3:多课表管理
任务: 支持多个课表(如上半学期、下半学期),用户可以切换:
命令: 切换到上半学期
命令: 切换到下半学期
练习4:课表分享
任务: 增加“导出“功能,把课表导出为:
- 文本格式(
.txt) - Markdown格式(
.md) - HTML格式(
.html)
练习5:图形化界面
任务: 使用 tkinter 库(第16章会学)为课表系统添加图形界面!
下一章预告
本章我们开发了一个功能完整的命令行程序,综合运用了:
- 字典和列表
- 条件和循环
- 文件操作
- 时间处理
- 正则表达式
下一章(第15章),我们将学习报表程序,使用 pyecharts 库生成各种图表(柱状图、折线图、饼图),让数据可视化!
准备好进入数据可视化的世界了吗? 🎨📊
第15章 报表程序 - 让数据说话
引言:从数字到图表
想象一下,如果你是一名老师,手里有一份学生的考试成绩单,上面只有密密麻麻的数字:
小明: 语文85 数学92 英语78
小红: 语文90 数学88 英语95
小刚: 语文78 数学85 英语82
...
你能快速看出:
- 哪个科目最难?
- 每个学生的强项是什么?
- 全班的平均成绩如何?
如果把这些数字画成图表,比如柱状图或折线图,答案就会一目了然!这就是数据可视化的作用——把枯燥的数字变成直观的图形,让数据“说话“。
什么是报表程序?
报表程序就是用来收集、处理和展示数据的程序。在我们的日常生活中:
- 天气预报:用折线图显示未来一周的气温变化
- 股票软件:用K线图显示股票价格波动
- 运动APP:用饼图显示你今天的运动时间分配
- 游戏排行榜:用柱状图显示玩家积分排名
这些程序都有一个共同点:把数据变成图表,让人更容易理解数据背后的信息。
为什么学习报表程序?
学习制作报表程序,你将掌握:
- 数据处理能力:学会整理和分析数据
- 可视化思维:学会用图形表达信息
- 实用工具:能制作出真正有用的程序
比如,你可以:
- 制作班级成绩分析报告
- 记录自己的零花钱使用情况
- 统计家里的电费水费变化
- 分析自己喜欢的游戏数据
本章学习路线
本章将教你如何使用pyecharts库制作各种图表,同时融入数学统计知识:
第1步: 安装和配置pyecharts库
↓
第2步: 复习数学统计知识(平均数、中位数、众数)
↓
第3步: 柱状图 - 比较不同类别的数据
↓
第4步: 折线图 - 显示数据的变化趋势
↓
第5步: 饼图 - 显示各部分占整体的比例
↓
第6步: 综合项目 - 制作完整的数据报表
👨🏫 给家长的小贴士
- 数据可视化是现代信息时代的重要技能
- 图表能培养孩子的抽象思维能力
- 本章重点融入小学数学统计知识:平均数、中位数、众数、数据分组
- 建议选择孩子感兴趣的数据(如游戏数据、运动数据)作为练习素材
- 鼓励孩子用图表解决实际问题(如班级统计、家庭记账)
- 数学知识点提醒:
- 平均数 = 总数 ÷ 个数
- 中位数:数据从大到小排列,中间位置的数
- 众数:出现次数最多的数
- 方差:数据波动大小的衡量(本章会简单介绍)
15.1 认识pyecharts库
15.1.1 什么是pyecharts?
pyecharts是一个专门用于生成图表的Python库。它的名字可以拆解为:
- py: Python的缩写
- echarts: 百度开源的一个强大图表工具
- s: 表示这是echarts的Python版本
为什么要使用pyecharts?
- 功能强大: 支持几十种图表类型
- 美观漂亮: 生成的图表配色和样式都很专业
- 易于使用: 只需要几行代码就能生成图表
- 交互式: 生成的图表支持鼠标悬停、点击缩放等操作
15.1.2 安装pyecharts
在开始使用pyecharts之前,需要先安装它。还记得我们在第13章学过的pip工具吗?
步骤1: 打开命令行窗口
Windows系统:
- 按Win+R键
- 输入
cmd - 按回车键
Mac系统:
- 按Command+空格键
- 输入“终端“
- 按回车键
步骤2: 安装pyecharts
在命令行窗口中输入以下命令:
pip install pyecharts
你会看到类似这样的输出:
Collecting pyecharts
Downloading pyecharts-2.0.4-py3-none-any.whl (...)
Installing collected packages: pyecharts
Successfully installed pyecharts-2.0.4
步骤3: 验证安装
安装完成后,在Python中输入以下代码测试:
from pyecharts.charts import Bar
print("pyecharts安装成功!")
如果输出“pyecharts安装成功!“说明安装成功了!
步骤4: (可选)安装图片快照功能
如果你想直接把图表保存为图片格式,需要安装额外的插件:
pip install pyecharts_snapshot
这个功能可以把HTML格式的图表转换为PNG或JPG图片。
给家长的小贴士
- pip安装失败: 可能是因为网络问题,可以尝试使用国内镜像源:
pip install pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple- 权限问题: 如果提示权限不足,在Windows上以管理员身份运行命令行,Mac上使用sudo
- 版本问题: pyecharts有v1和v2两个版本,本书使用v2版本
- 离线安装: 如果网络不好,可以下载whl文件后本地安装
常见问题解答
Q: 为什么要安装这么大的库? A: pyecharts包含了大量的图表模板和样式文件,所以比较大。但这些文件让我们能做出更专业的图表。
Q: 安装失败怎么办? A: 1) 检查网络连接 2) 尝试升级pip:
python -m pip install --upgrade pip3) 使用国内镜像源Q: 每次使用都要重新安装吗? A: 不需要!安装一次后,以后在任何Python程序中都可以使用。
15.1.3 pyecharts的基本使用流程
使用pyecharts生成图表一般分为5个步骤:
# 步骤1: 导入需要的图表类
from pyecharts.charts import Bar
# 步骤2: 创建图表对象
bar = Bar()
# 步骤3: 添加数据
bar.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [5, 20, 36, 10, 10, 100])
# 步骤4: 设置全局选项(可选)
bar.set_global_opts(title_opts={"text": "我的第一个图表"})
# 步骤5: 渲染生成HTML文件
bar.render("my_first_chart.html")
代码解析:
- 导入: 从pyecharts.charts导入你需要的图表类(如Bar、Line、Pie)
- 创建: 创建一个图表对象
- 数据: 用add_xaxis()添加x轴数据,用add_yaxis()添加y轴数据
- 选项: 设置标题、图例、工具箱等配置
- 渲染: 生成一个HTML文件,用浏览器打开就能看到图表
运行结果:
程序运行后,会在当前目录下生成my_first_chart.html文件。双击这个文件,浏览器会打开它,你就能看到一个漂亮的柱状图了!
给家长的小贴士
- HTML文件: 生成的图表是网页格式(HTML),不需要额外安装软件就能打开
- 代码结构: 强调“导入-创建-添加数据-设置选项-渲染“这5步固定流程
- 逐步演示: 建议先让孩子看完整的运行效果,激发学习兴趣
- 文件位置: 提醒孩子注意HTML文件的保存位置,方便查找
实践练习1:修改数据
任务: 将上面的代码复制下来,修改数据:
- x轴改成你喜欢的6种水果
- y轴改成每种水果的价格(元)
- 标题改成“水果价格表“
提示:
bar.add_xaxis(["苹果", "香蕉", "橙子", "草莓", "葡萄", "西瓜"]) bar.add_yaxis("价格", [8, 3, 6, 15, 12, 5])答案:
点击查看完整代码
from pyecharts.charts import Bar # 创建图表对象 bar = Bar() # 添加数据 bar.add_xaxis(["苹果", "香蕉", "橙子", "草莓", "葡萄", "西瓜"]) bar.add_yaxis("价格(元)", [8, 3, 6, 15, 12, 5]) # 设置标题 bar.set_global_opts(title_opts={"text": "水果价格表"}) # 生成图表 bar.render("fruit_price.html")运行后打开
fruit_price.html,你就能看到水果价格的柱状图了!
15.2 数学统计知识复习 📊
在开始制作图表之前,让我们先复习一些数学统计知识。这些知识会在制作图表时经常用到!
15.2.1 平均数(Average)
什么是平均数?
平均数是一组数据的“代表值“,它能反映这组数据的整体水平。
🍎 生活中的例子: 假设你有5个苹果,分别重: 150克、160克、140克、155克、145克。
计算平均数的步骤:
# 步骤1: 把所有数据加起来
total = 150 + 160 + 140 + 155 + 145
print("总重量:", total) # 输出: 750克
# 步骤2: 除以数据的个数
average = total / 5
print("平均重量:", average) # 输出: 150克
用Python计算平均数:
# 一组数据
scores = [85, 90, 78, 92, 88]
# 方法1: 使用sum()和len()
average = sum(scores) / len(scores)
print(f"平均分: {average}")
# 方法2: 用循环计算
total = 0
for score in scores:
total += score
average = total / len(scores)
print(f"平均分: {average}")
平均数的数学意义:
- 如果每个人的成绩都等于平均分,那么总分不会变
- 平均数是“公平“的体现——每个人贡献相同
👨🏫 给家长的小贴士
- 平均数 vs 总数: 问孩子“为什么有了总数还要算平均数?“(因为人数不同时,总数不能直接比较)
- 生活中的平均数: 平均气温、平均身高、平均速度、平均价格
- 计算技巧: 先估算,再精确计算。比如[85, 90, 78, 92, 88],可以估算“大约85左右“
- 错误认知: 平均数不一定是数据中的某个值(比如[1, 2, 10],平均数是4.33,不在原数据中)
15.2.2 中位数(Median)
什么是中位数?
中位数是把数据按大小排列后,位于中间位置的那个数。
🏃 生活中的例子: 跑步比赛,5个人的成绩是:
- 3分20秒、3分15秒、3分25秒、3分18秒、3分22秒
找中位数的步骤:
# 步骤1: 把数据从小到大排列
times = [3*60+15, 3*60+18, 3*60+20, 3*60+22, 3*60+25] # 转换为秒
print("排序前:", times)
# 使用Python排序
times_sorted = sorted(times)
print("排序后:", times_sorted) # [195, 198, 200, 202, 205]
# 步骤2: 找中间位置的数据(第3个)
median_index = len(times_sorted) // 2 # 5//2 = 2(索引从0开始)
median = times_sorted[median_index]
print(f"中位数: {median}秒,即{median//60}分{median%60}秒")
中位数的特点:
- 数据个数是奇数时,中位数就是中间的那个数
- 数据个数是偶数时,中位数是中间两个数的平均数
偶数个数据的例子:
# 6个数据
scores = [85, 90, 78, 92, 88, 95]
# 排序
scores_sorted = sorted(scores) # [78, 85, 88, 90, 92, 95]
# 中间两个数: 第3个(88)和第4个(90)
middle1 = scores_sorted[2] # 第3个,索引为2
middle2 = scores_sorted[3] # 第4个,索引为3
median = (middle1 + middle2) / 2
print(f"中位数: {median}") # 输出: 89.0
中位数的数学意义:
- 中位数不受极端值(太大或太小的数)的影响
- 比如工资统计,如果有一个人工资特别高,平均数会失真,但中位数能反映真实情况
👨🏫 给家长的小贴士
- 平均数 vs 中位数: 举例说明差异
- 班级成绩: [60, 85, 88, 90, 92],平均数=83,中位数=88(接近)
- 班级成绩: [10, 85, 88, 90, 92],平均数=73,中位数=88(差异大)
- 什么时候用中位数: 当有极端值(异常大或异常小的数据)时
- 排序技能: 教孩子手动排序的方法(冒泡排序的简化版)
- 找位置: 奇数个数据的位置 = (总数+1)÷2,偶数个数据取中间两个的平均
15.2.3 众数(Mode)
什么是众数?
众数是一组数据中出现次数最多的数。
🎨 生活中的例子: 班级同学最喜欢的颜色统计:
- 红色:5人、蓝色:8人、绿色:3人、黄色:8人、紫色:2人
# 数据
colors = ["红", "蓝", "绿", "黄", "紫"]
counts = [5, 8, 3, 8, 2]
# 找最大值
max_count = max(counts)
print(f"最多人选的人数: {max_count}")
# 找最大值的位置
max_index = counts.index(max_count)
mode_color = colors[max_index]
print(f"众数(最受欢迎的颜色): {mode_color}")
多个众数的情况:
# 数据: [1, 2, 2, 3, 3, 4]
# 2出现2次,3也出现2次
# 这组数据有"双众数": 2和3
# 统计每个数出现的次数
from collections import Counter
data = [1, 2, 2, 3, 3, 4]
count_result = Counter(data)
print("统计结果:", count_result) # Counter({2: 2, 3: 2, 1: 1, 4: 1})
# 找出现最多的次数
max_count = max(count_result.values())
# 找所有众数
modes = [num for num, count in count_result.items() if count == max_count]
print(f"众数: {modes}") # 输出: [2, 3]
众数的特点:
- 一组数据可能没有众数(所有数都只出现1次)
- 一组数据可能有多个众数
- 众数一定是数据中的某个值(这一点和平均数不同!)
👨🏫 给家长的小贴士
- 众数 vs 平均数: 众数关注“最多“,平均数关注“整体“
- 投票选举: 众数就像民主投票,得票最多的当选
- 实际应用:
- 商店进货哪种商品(卖得最好的)
- 鞋厂生产哪种尺码(穿的人最多的)
- 编程思维: 用字典统计频次是常见的数据处理方法
15.2.4 数据分组(区间统计)
什么是数据分组?
当数据很多时,我们不会逐个统计,而是把数据分成几个区间(范围),统计每个区间有多少个数据。
📊 生活中的例子:
统计班级50个学生的考试成绩:
- 100分: 3人
- 90-99分: 12人
- 80-89分: 20人
- 70-79分: 10人
- 60-69分: 4人
- 60分以下: 1人
用Python实现数据分组:
# 原始成绩数据
scores = [95, 87, 92, 78, 85, 90, 88, 92, 85, 76,
82, 89, 91, 85, 88, 90, 87, 85, 92, 88]
# 定义分数段
ranges = ["优秀(90-100)", "良好(80-89)", "及格(60-79)", "不及格(0-59)"]
counts = [0, 0, 0, 0]
# 统计每个分数段的人数
for score in scores:
if score >= 90:
counts[0] += 1
elif score >= 80:
counts[1] += 1
elif score >= 60:
counts[2] += 1
else:
counts[3] += 1
print("分数段分布:")
for i in range(len(ranges)):
print(f"{ranges[i]}: {counts[i]}人")
数据分组的数学意义:
- 简化数据,让数据更容易理解
- 保留数据的整体趋势,同时忽略细节
- 方便制作统计图表(直方图、饼图)
分组的技巧:
- 等距分组: 每个区间的长度相同(如0-10, 10-20, 20-30)
- 有意义分组: 根据实际意义划分(如成绩的优、良、及格)
- 边界明确: 明确区间的起点和终点(包括端点吗?)
👨🏫 给家长的小贴士
- 为什么分组: 问孩子“50个人的成绩,逐个柱状图会很拥挤,怎么办?“(引出分组)
- 选择区间: 举例说明区间太大或太小的问题
- 太大: [0-100]只有一个区间,没意义
- 太小: [0-1, 1-2, 2-3…]太细碎
- 合适: [0-59, 60-69, 70-79, 80-89, 90-100]
- 包含边界: 90分属于哪个区间?需要约定(通常“左闭右开“[90,100)或“左开右闭“(89,100])
- 图表对应: 分组数据适合做饼图,显示各部分占比
15.2.5 综合练习:数据分析
现在让我们用刚才学到的统计知识,分析一组真实数据!
📚 案例分析:班级阅读情况统计
# 班级同学这学期阅读的书籍数量
books_read = [5, 8, 12, 6, 7, 10, 9, 8, 15, 6,
7, 8, 9, 11, 7, 8, 10, 12, 8, 9]
# 1. 计算平均数
average = sum(books_read) / len(books_read)
print(f"平均每人读{average:.1f}本书")
# 2. 找中位数
sorted_books = sorted(books_read)
n = len(sorted_books)
if n % 2 == 1: # 奇数个
median = sorted_books[n // 2]
else: # 偶数个
median = (sorted_books[n // 2 - 1] + sorted_books[n // 2]) / 2
print(f"中位数: {median}本")
# 3. 找众数
from collections import Counter
count_result = Counter(books_read)
max_count = max(count_result.values())
modes = [num for num, count in count_result.items() if count == max_count]
print(f"众数: {modes}本")
# 4. 数据分组
ranges = ["0-5本", "6-10本", "11-15本", "16本以上"]
counts = [0, 0, 0, 0]
for books in books_read:
if books <= 5:
counts[0] += 1
elif books <= 10:
counts[1] += 1
elif books <= 15:
counts[2] += 1
else:
counts[3] += 1
print("\n阅读量分组统计:")
for i in range(len(ranges)):
percentage = counts[i] / len(books_read) * 100
print(f"{ranges[i]}: {counts[i]}人,占{percentage:.1f}%")
运行结果:
平均每人读8.7本书
中位数: 8.0本
众数: [8]本
阅读量分组统计:
0-5本: 1人,占5.0%
6-10本: 15人,占75.0%
11-15本: 4人,占20.0%
16本以上: 0人,占0.0%
数据分析结论:
- 大部分同学(75%)阅读量在6-10本之间
- 平均数(8.7本)和中位数(8本)接近,说明数据分布比较均匀
- 众数是8本,说明阅读8本的同学最多
- 全班没有一个人阅读超过15本,但也没有一个人阅读少于6本(除了1人)
👨🏫 给家长的小贴士
- 数据思维: 教孩子从数据中“读故事“,而不是只看数字
- 多角度分析: 平均数、中位数、众数各有用处,综合分析更全面
- 批判性思维: 问孩子“如果你是老师,看到这个数据会怎么做?“(比如:组织读书分享会)
- 现实应用: 鼓励孩子用这套方法分析自己的数据(游戏时长、学习时间等)
- 编程价值: 强调Python让数据分析变得简单高效,手算20个数据要很久,Python只需要几秒
🎯 实践练习2:你自己的数据分析
任务: 收集一组你感兴趣的数据,并用Python分析:
数据主题建议:
- 游戏数据: 最近10次游戏的得分/等级
- 运动数据: 最近2周每天的运动时长
- 学习数据: 最近10次作业的分数
- 创意数据: 其他你感兴趣的数据
要求:
- 至少10个数据点
- 计算平均数、中位数、众数
- 进行数据分组(至少3个区间)
- 写出分析结论(至少3条)
答案示例:
点击查看参考答案
# 示例:游戏得分分析 scores = [85, 92, 78, 88, 95, 82, 90, 87, 91, 89] # 平均数 avg = sum(scores) / len(scores) print(f"平均分: {avg:.1f}") # 中位数 sorted_scores = sorted(scores) median = (sorted_scores[4] + sorted_scores[5]) / 2 print(f"中位数: {median}") # 众数 from collections import Counter count_result = Counter(scores) max_count = max(count_result.values()) modes = [s for s, c in count_result.items() if c == max_count] print(f"众数: {modes}") # 数据分组 ranges = ["优秀(90-100)", "良好(80-89)", "及格(60-79)", "不及格(0-59)"] counts = [0, 0, 0, 0] for score in scores: if score >= 90: counts[0] += 1 elif score >= 80: counts[1] += 1 elif score >= 60: counts[2] += 1 else: counts[3] += 1 print("\n分数段分布:") for i in range(len(ranges)): print(f"{ranges[i]}: {counts[i]}人")
15.3 柱状图 - 比较大小的高手
15.3.1 柱状图的应用场景
**柱状图(Bar Chart)**是最常见的图表类型之一,它用柱子的高度来表示数据的大小。
柱状图适合用来:
- 比较不同类别: 比较不同产品的销量
- 排名: 显示班级成绩排名
- 统计: 统计每个月的零花钱支出
生活中的柱状图例子:
- 奥运会奖牌榜
- 游戏英雄战斗力对比
- 各城市人口数量对比
15.3.2 创建一个简单的柱状图
让我们从最简单的例子开始——制作一个班级成绩的柱状图:
from pyecharts.charts import Bar
# 创建柱状图
bar = Bar()
# 添加x轴数据(学生姓名)
bar.add_xaxis(["小明", "小红", "小刚", "小丽", "小华"])
# 添加y轴数据(语文成绩)
bar.add_yaxis("语文成绩", [85, 90, 78, 92, 88])
# 设置标题
bar.set_global_opts(title_opts={"text": "班级语文成绩"})
# 生成HTML文件
bar.render("class_scores.html")
运行结果:
程序会生成class_scores.html文件,用浏览器打开后,你会看到5个不同高度的柱子,每个柱子代表一个学生的语文成绩。
15.3.3 添加多个系列的数据
有时候我们需要对比多组数据。比如,想同时显示每个学生的语文、数学、英语成绩:
from pyecharts.charts import Bar
bar = Bar()
# 添加x轴(学生姓名)
bar.add_xaxis(["小明", "小红", "小刚", "小丽", "小华"])
# 添加多组数据
bar.add_yaxis("语文", [85, 90, 78, 92, 88])
bar.add_yaxis("数学", [92, 88, 85, 95, 90])
bar.add_yaxis("英语", [78, 95, 82, 88, 91])
# 设置标题
bar.set_global_opts(title_opts={"text": "班级成绩表"})
# 生成图表
bar.render("class_scores_all.html")
图表解读:
- 每个学生会有3根柱子,分别代表语文、数学、英语成绩
- 不同颜色的柱子代表不同的科目
- 图表右上角会显示图例(语文、数学、英语),点击可以隐藏/显示对应的数据
给家长的小贴士
- 颜色区分: 帮助孩子理解不同颜色代表不同数据系列
- 图例功能: 演示点击图例可以隐藏/显示数据,这是pyecharts的交互功能
- 数据对应: 确保x轴和y轴的数据数量一致,否则会报错
- 中文字符: pyecharts完全支持中文,不会出现乱码问题
实践练习2:最喜欢的运动统计
任务: 调查班级同学最喜欢的运动,制作柱状图:
- x轴: 篮球、足球、羽毛球、乒乓球、跑步、游泳
- y轴: 喜欢该项运动的人数(假设为: 15, 12, 8, 10, 6, 9)
- 标题: “班级运动喜好调查”
要求:
- 添加y轴名称:“人数”
- 添加数据标签显示每个柱子上的具体数值
答案:
点击查看完整代码
from pyecharts.charts import Bar from pyecharts import options as opts bar = Bar() # 添加数据 bar.add_xaxis(["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]) bar.add_yaxis( series_name="人数", yaxis_data=[15, 12, 8, 10, 6, 9], label_opts=opts.LabelOpts(is_show=True) # 显示数据标签 ) # 设置全局选项 bar.set_global_opts( title_opts={"text": "班级运动喜好调查"}, yaxis_opts=opts.AxisOpts(name="人数"), xaxis_opts=opts.AxisOpts(name="运动项目") ) # 生成图表 bar.render("sports_survey.html")运行后,每个柱子上会显示具体人数,方便读取数据!
15.3.4 柱状图的高级设置
1. 水平柱状图
默认的柱状图是垂直的,柱子从下往上。有时我们需要水平的柱状图,柱子从左往右:
from pyecharts.charts import Bar
from pyecharts import options as opts
bar = Bar()
# 添加数据(反转x和y轴的添加顺序)
bar.add_xaxis(["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"])
bar.add_yaxis("人数", [15, 12, 8, 10, 6, 9])
# 设置全局选项
bar.set_global_opts(
title_opts={"text": "班级运动喜好调查"},
yaxis_opts=opts.AxisOpts(name="人数"),
xaxis_opts=opts.AxisOpts(name="运动项目")
)
# 反转x轴和y轴
bar.reversal_axis()
# 生成图表
bar.render("horizontal_bar.html")
使用场景: 水平柱状图适合类别名称很长的情况(如“数学竞赛成绩“、“英语演讲比赛“等),避免文字重叠。
2. 堆叠柱状图
堆叠柱状图可以让多组数据叠加显示:
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.globals import ThemeType
# 使用主题
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
bar.add_xaxis(["第一季度", "第二季度", "第三季度", "第四季度"])
bar.add_yaxis("电子产品", [10, 20, 30, 40], stack="stack1")
bar.add_yaxis("服装", [15, 25, 20, 35], stack="stack1")
bar.add_yaxis("食品", [20, 15, 25, 30], stack="stack1")
bar.set_global_opts(
title_opts={"text": "季度销售额"},
yaxis_opts=opts.AxisOpts(name="销售额(万元)"),
xaxis_opts=opts.AxisOpts(name="季度"),
toolbox_opts=opts.ToolboxOpts(is_show=True) # 显示工具栏
)
bar.render("stacked_bar.html")
使用场景: 堆叠柱状图适合显示部分与整体的关系,比如每天不同类别商品的销售总额。
给家长的小贴士
- 主题样式: pyecharts提供了多个主题(LIGHT, DARK, ROMA等),可以尝试不同风格
- 工具栏: toolbox_opts会显示下载图片、数据视图等功能,很实用
- 堆叠概念: 用积木叠高高来类比堆叠柱状图,孩子更容易理解
- 代码复用: 鼓励孩子把常用配置保存起来,下次直接使用
15.3.5 柱状图的常见问题
问题1: 中文显示乱码
虽然pyecharts默认支持中文,但如果你的Python文件编码不是UTF-8,可能会出现乱码。
解决方法: 在Python文件的第一行添加:
# -*- coding: utf-8 -*-
问题2: 柱子太多显示不下
当x轴的类别太多时,柱子会挤在一起。
解决方法:
bar.set_global_opts(
xaxis_opts=opts.AxisOpts(
axislabel_opts=opts.LabelOpts(rotate=45) # 旋转标签45度
)
)
问题3: 数值差异太大
如果一组数据是[5, 8, 10],另一组是[1000, 2000, 3000],数值小的柱子几乎看不见。
解决方法: 使用双y轴(在高级应用中会学习)或调整数据比例。
实践练习3:比较自己和偶像的数据
任务: 制作一个柱状图,对比你和偶像的数据(可以是游戏、运动、学习等):
- 要求:至少3个对比项目(如:身高、体重、年龄,或游戏等级、胜率、场次)
- 使用水平柱状图
- 添加标题和数据标签
示例数据:
me = [165, 50, 12] # 身高cm, 体重kg, 年龄 idol = [178, 65, 25] items = ["身高(cm)", "体重(kg)", "年龄"]答案:
点击查看完整代码
from pyecharts.charts import Bar from pyecharts import options as opts # 你的数据 me = [165, 50, 12] idol = [178, 65, 25] items = ["身高(cm)", "体重(kg)", "年龄"] bar = Bar() bar.add_xaxis(items) bar.add_yaxis("我", me, label_opts=opts.LabelOpts(is_show=True)) bar.add_yaxis("偶像", idol, label_opts=opts.LabelOpts(is_show=True)) bar.set_global_opts( title_opts={"text": "我和偶像的对比"} ) bar.reversal_axis() bar.render("me_vs_idol.html")
15.4 折线图 - 追踪变化趋势
15.4.1 折线图的应用场景
**折线图(Line Chart)**用线段连接各个数据点,显示数据随时间或其他因素的变化趋势。
折线图适合用来:
- 显示趋势: 比如一年的气温变化
- 对比变化: 比较两个学生的成绩进步情况
- 预测未来: 根据历史数据预测趋势
生活中的折线图例子:
- 天气预报的气温曲线
- 新冠疫情的数据曲线
- 股票价格的K线图
15.4.2 创建一个简单的折线图
让我们制作一个显示一周气温变化的折线图:
from pyecharts.charts import Line
# 创建折线图
line = Line()
# 添加x轴数据(星期)
line.add_xaxis(["周一", "周二", "周三", "周四", "周五", "周六", "周日"])
# 添加y轴数据(最高气温)
line.add_yaxis("最高气温(°C)", [22, 24, 26, 25, 23, 28, 30])
# 设置标题
line.set_global_opts(title_opts={"text": "一周气温变化"})
# 生成图表
line.render("temperature_line.html")
图表解读:
- x轴表示星期
- y轴表示温度
- 折线显示温度的变化趋势
- 可以看出哪天最热,哪天最凉快
15.4.3 添加多个数据系列
折线图特别适合对比多个数据系列的变化趋势:
from pyecharts.charts import Line
line = Line()
# 添加x轴
line.add_xaxis(["周一", "周二", "周三", "周四", "周五", "周六", "周日"])
# 添加多组数据
line.add_yaxis("最高气温(°C)", [22, 24, 26, 25, 23, 28, 30])
line.add_yaxis("最低气温(°C)", [15, 16, 18, 17, 14, 19, 20])
# 设置标题
line.set_global_opts(title_opts={"text": "一周气温变化"})
# 生成图表
line.render("temperature_double_line.html")
图表解读:
- 两条折线分别代表最高气温和最低气温
- 可以看出每天的温差(两条线之间的距离)
- 可以看出气温的总体变化趋势
给家长的小贴士
- 趋势解读: 教孩子如何从折线图中读取信息(上升、下降、波动)
- 数据对比: 多条折线对比时,引导孩子找出规律(如:A一直比B高,A和B呈相反变化)
- 实际应用: 鼓励孩子记录自己的数据(如每天的学习时间),用折线图分析
- 数据收集: 这个过程还能培养孩子的数据收集习惯
实践练习4:我的成绩进步曲线
任务: 制作一个折线图,显示你最近5次考试的成绩变化:
- x轴: 第1次、第2次、第3次、第4次、第5次
- y轴: 语文和数学的成绩
- 添加数据标记点
示例数据:
chinese = [75, 78, 82, 85, 88] math = [80, 79, 83, 87, 90] exams = ["第1次", "第2次", "第3次", "第4次", "第5次"]答案:
点击查看完整代码
from pyecharts.charts import Line from pyecharts import options as opts # 成绩数据 chinese = [75, 78, 82, 85, 88] math = [80, 79, 83, 87, 90] exams = ["第1次", "第2次", "第3次", "第4次", "第5次"] line = Line() line.add_xaxis(exams) line.add_yaxis( "语文", chinese, markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]), markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average")]) ) line.add_yaxis("数学", math) line.set_global_opts( title_opts={"text": "我的成绩进步曲线"}, yaxis_opts=opts.AxisOpts(name="分数"), xaxis_opts=opts.AxisOpts(name="考试次数") ) line.render("my_scores.html")运行后,你会看到两条折线,语文的最高分会自动标记,平均分也会显示!
15.4.4 平滑曲线和面积图
1. 平滑曲线
默认的折线图是直线连接各个点。设置is_smooth=True可以让线条变得平滑:
from pyecharts.charts import Line
line = Line()
line.add_xaxis(["1月", "2月", "3月", "4月", "5月", "6月"])
line.add_yaxis("销售额(万元)", [10, 15, 13, 18, 20, 25], is_smooth=True)
line.set_global_opts(title_opts={"text": "上半年销售额"})
line.render("smooth_line.html")
效果: 折线变成了平滑的曲线,看起来更美观,适合表示连续变化的数据(如气温、速度等)。
2. 面积图
面积图是在折线图下方填充颜色,强调数据的“量“:
from pyecharts.charts import Line
from pyecharts import options as opts
line = Line()
line.add_xaxis(["周一", "周二", "周三", "周四", "周五", "周六", "周日"])
line.add_yaxis(
"学习时间(小时)",
[2, 2.5, 3, 2, 3.5, 4, 3],
areastyle_opts=opts.AreaStyleOpts(opacity=0.5) # 填充区域,透明度0.5
)
line.set_global_opts(title_opts={"text": "一周学习时间统计"})
line.render("area_line.html")
使用场景: 面积图适合强调累积量或总量,如每天的学习时间、每月的零花钱支出。
给家长的小贴士
- 平滑 vs 直线: 平滑曲线看起来更美观,但不适合强调精确的数据点
- 面积图: 适合用“积木堆叠“或“装水“的类比解释
- 透明度: opacity范围是0到1,0表示完全透明,1表示不透明
- 交互功能: 鼠标悬停在图表上时,会显示详细的数据提示框
15.4.5 折线图的标记功能
pyecharts可以在折线图上自动标记特殊点:
from pyecharts.charts import Line
from pyecharts import options as opts
line = Line()
line.add_xaxis(["1月", "2月", "3月", "4月", "5月", "6月"])
line.add_yaxis(
"销售额(万元)",
[10, 15, 13, 18, 20, 25],
# 标记点:最大值、最小值
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="最大值"),
opts.MarkPointItem(type_="min", name="最小值")
]
),
# 标记线:平均值
markline_opts=opts.MarkLineOpts(
data=[
opts.MarkLineItem(type_="average", name="平均值")
]
)
)
line.set_global_opts(title_opts={"text": "上半年销售额"})
line.render("marked_line.html")
标记说明:
- 标记点: 用圆点标记特殊位置(最大值、最小值、自定义点)
- 标记线: 用直线标记特殊位置(平均值、自定义线)
实践练习5:游戏等级提升记录
任务: 假设你在一周内玩游戏,每天记录等级提升:
- x轴: 周一到周日
- y轴: 等级(假设起始等级1,每天提升不同)
- 要求:标记最大提升的那一天,显示平均等级
示例数据:
levels = [1, 3, 5, 8, 10, 15, 18] gains = [0, 2, 2, 3, 2, 5, 3] # 每天提升的等级答案:
点击查看完整代码
from pyecharts.charts import Line from pyecharts import options as opts levels = [1, 3, 5, 8, 10, 15, 18] days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] line = Line() line.add_xaxis(days) line.add_yaxis( "等级", levels, markpoint_opts=opts.MarkPointOpts( data=[ opts.MarkPointItem(type_="max", name="最高等级"), opts.MarkPointItem(type_="min", name="最低等级") ] ), markline_opts=opts.MarkLineOpts( data=[ opts.MarkLineItem(type_="average", name="平均等级") ] ) ) line.set_global_opts( title_opts={"text": "游戏等级提升记录"}, yaxis_opts=opts.AxisOpts(name="等级"), xaxis_opts=opts.AxisOpts(name="日期") ) line.render("game_levels.html")
15.5 饼图 - 显示比例关系
15.5.1 饼图的应用场景
**饼图(Pie Chart)**用圆形的扇形大小表示各部分占整体的比例。
饼图适合用来:
- 显示占比: 班级男女生比例
- 分配关系: 零花钱的用途分配
- 组成结构: 家庭支出中各项费用的占比
生活中的饼图例子:
- 预算分配图
- 选举结果占比
- 手机存储空间使用情况
重要: 饼图的数据加起来应该是100%(或1),表示一个整体。
15.5.2 创建一个简单的饼图
让我们制作一个显示班级运动爱好的饼图:
from pyecharts.charts import Pie
# 数据
sports = ["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]
counts = [15, 12, 8, 10, 6, 9]
# 创建饼图
pie = Pie()
# 添加数据
pie.add("", list(zip(sports, counts)))
# 设置标题
pie.set_global_opts(title_opts={"text": "班级运动喜好分布"})
# 生成图表
pie.render("sports_pie.html")
代码解析:
list(zip(sports, counts))将两个列表合并成:[("篮球", 15), ("足球", 12), ...]- 饼图的
add()方法的第一个参数是系列名称(可以为空字符串)
15.5.3 饼图的样式设置
1. 显示百分比和标签
默认情况下,饼图会显示类别名称。我们可以同时显示百分比:
from pyecharts.charts import Pie
from pyecharts import options as opts
sports = ["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]
counts = [15, 12, 8, 10, 6, 9]
pie = Pie()
pie.add(
"",
list(zip(sports, counts)),
label_opts=opts.LabelOpts(formatter="{b}: {d}%") # {b}=名称, {d}=百分比
)
pie.set_global_opts(title_opts={"text": "班级运动喜好分布"})
pie.render("sports_pie_percent.html")
formatter参数说明:
{a}: 系列名称{b}: 数据项名称(如“篮球“){c}: 数值(如15){d}: 百分比(如18.07%)
2. 环形饼图
环形饼图比普通饼图更美观,中间是空心的:
from pyecharts.charts import Pie
from pyecharts import options as opts
sports = ["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]
counts = [15, 12, 8, 10, 6, 9]
pie = Pie()
pie.add(
"",
list(zip(sports, counts)),
radius=["30%", "70%"] # 内圆半径30%,外圆半径70%
)
pie.set_global_opts(title_opts={"text": "班级运动喜好分布"})
pie.render("donut_pie.html")
radius参数:
- 第一个值: 内圆半径
- 第二个值: 外圆半径
- 两个值越接近,环形越细
给家长的小贴士
- 百分比概念: 饼图是帮助孩子理解百分比的绝佳工具
- 数据归一化: 如果数据加起来不是100%,pyecharts会自动计算百分比
- 颜色识别: 教孩子如何从饼图的颜色和面积大小直观地理解比例
- 环形 vs 实心: 环形饼图可以在中间显示总数或标题,更美观
实践练习6:我的零花钱花哪里了
任务: 制作一个饼图,显示你一个月零花钱的使用情况:
- 类别: 零食、文具、玩具、游戏、其他
- 数据: 自己设定一个合理的分配(如: 30%, 20%, 15%, 25%, 10%)
- 要求:使用环形饼图,显示百分比
示例数据:
items = ["零食", "文具", "玩具", "游戏", "其他"] money = [60, 40, 30, 50, 20] # 单位:元答案:
点击查看完整代码
from pyecharts.charts import Pie from pyecharts import options as opts items = ["零食", "文具", "玩具", "游戏", "其他"] money = [60, 40, 30, 50, 20] pie = Pie() pie.add( "", list(zip(items, money)), radius=["35%", "65%"], # 环形 label_opts=opts.LabelOpts(formatter="{b}: {c}元 ({d}%)") ) pie.set_global_opts( title_opts={"text": "我的零花钱使用情况"}, legend_opts=opts.LegendOpts(orient="vertical", pos_left="left") ) pie.render("allowance_spending.html")运行后,你会看到一个漂亮的环形饼图,每个部分显示金额和百分比!
15.5.4 饼图的Rose图
Rose图(玫瑰图)是饼图的变体,扇形的半径不同:
from pyecharts.charts import Pie
from pyecharts import options as opts
sports = ["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]
counts = [15, 12, 8, 10, 6, 9]
pie = Pie()
pie.add(
"",
list(zip(sports, counts)),
radius="60%", # 半径
rosetype="radius" # 设置为玫瑰图
)
pie.set_global_opts(title_opts={"text": "班级运动喜好分布(Rose图)"})
pie.render("rose_pie.html")
Rose图特点:
- 每个扇形的半径不同,数据越大,扇形越大
- 适合数据差异较大的情况
- 视觉效果更丰富
给家长的小贴士
- Rose图 vs 饼图: Rose图强调数值差异,饼图强调比例关系
- 选择建议: 数据差异大时用Rose图,数据相近时用普通饼图
- 交互功能: 点击某个扇形,该扇形会突出显示
15.5.5 饼图的嵌套
饼图可以嵌套,显示多层数据:
from pyecharts.charts import Pie
from pyecharts import options as opts
# 内圈数据
inner_data = [("电子产品", 60), ("服装", 30), ("食品", 50)]
# 外圈数据(细分)
outer_data = [
("手机", 30), ("电脑", 20), ("耳机", 10),
("男装", 15), ("女装", 15),
("零食", 25), ("饮料", 15), ("水果", 10)
]
pie = Pie()
# 添加内圈
pie.add(
"",
inner_data,
radius=["0%", "35%"], # 从中心到35%的区域
label_opts=opts.LabelOpts(formatter="{b}: {d}%")
)
# 添加外圈
pie.add(
"",
outer_data,
radius=["45%", "70%"], # 从45%到70%的区域
label_opts=opts.LabelOpts(formatter="{b}: {d}%")
)
pie.set_global_opts(title_opts={"text": "销售额分布(嵌套饼图)"})
pie.render("nested_pie.html")
使用场景: 嵌套饼图适合显示“大类-小类“的层级关系,如“运动-球类、跑步、游泳“。
实践练习7:我的时间分配
任务: 制作一个嵌套饼图,显示你一天的时间分配:
内圈(大类):
- 睡眠: 9小时
- 上学: 8小时
- 作业: 3小时
- 娱乐: 4小时
外圈(娱乐细分):
- 看电视: 1.5小时
- 玩游戏: 1小时
- 运动: 1小时
- 其他: 0.5小时
答案:
点击查看完整代码
from pyecharts.charts import Pie from pyecharts import options as opts # 内圈: 大类 inner_data = [ ("睡眠", 9), ("上学", 8), ("作业", 3), ("娱乐", 4) ] # 外圈: 娱乐细分 outer_data = [ ("看电视", 1.5), ("玩游戏", 1), ("运动", 1), ("其他", 0.5), # 补充其他类别的数据(为了图形完整) ("睡眠细分", 9), ("上学细分", 8), ("作业细分", 3) ] pie = Pie() pie.add( "", inner_data, radius=["0%", "35%"], label_opts=opts.LabelOpts(formatter="{b}: {c}小时") ) pie.add( "", outer_data, radius=["45%", "70%"], label_opts=opts.LabelOpts(formatter="{b}: {c}小时") ) pie.set_global_opts(title_opts={"text": "我的一天时间分配"}) pie.render("my_day_pie.html")提示: 这个例子展示了嵌套饼图的应用,但外圈数据不完全对称,实际情况中可能需要更完整的数据分类。
15.6 综合项目:制作班级成绩分析报告
现在我们已经学会了柱状图、折线图、饼图,让我们做一个综合项目:班级成绩分析报告系统。
这个项目会综合运用我们学到的所有知识!
15.6.1 项目需求
假设你是班长,老师给你一份班级成绩数据,你需要:
- 用柱状图显示每个学生的总分排名
- 用折线图显示班级平均分的变化趋势
- 用饼图显示各分数段的人数分布
- 生成一个完整的HTML报告
原始数据:
| 姓名 | 语文 | 数学 | 英语 | 物理 | 化学 |
|---|---|---|---|---|---|
| 小明 | 85 | 92 | 78 | 88 | 90 |
| 小红 | 90 | 88 | 95 | 92 | 94 |
| 小刚 | 78 | 85 | 82 | 80 | 83 |
| 小丽 | 92 | 95 | 88 | 90 | 91 |
| 小华 | 88 | 90 | 91 | 85 | 89 |
| 小强 | 80 | 82 | 85 | 78 | 80 |
| 小芳 | 95 | 90 | 92 | 95 | 93 |
15.6.2 项目实现
让我们一步步完成这个项目:
步骤1: 准备数据
# 学生姓名
students = ["小明", "小红", "小刚", "小丽", "小华", "小强", "小芳"]
# 各科成绩
chinese = [85, 90, 78, 92, 88, 80, 95]
math = [92, 88, 85, 95, 90, 82, 90]
english = [78, 95, 82, 88, 91, 85, 92]
physics = [88, 92, 80, 90, 85, 78, 95]
chemistry = [90, 94, 83, 91, 89, 80, 93]
# 计算总分
total_scores = []
for i in range(len(students)):
total = chinese[i] + math[i] + english[i] + physics[i] + chemistry[i]
total_scores.append(total)
print("总分:", total_scores)
运行结果:
总分: [433, 459, 408, 456, 443, 405, 465]
步骤2: 柱状图 - 总分排名
from pyecharts.charts import Bar
from pyecharts import options as opts
# 创建柱状图
bar = Bar()
# 添加数据
bar.add_xaxis(students)
bar.add_yaxis(
"总分",
total_scores,
label_opts=opts.LabelOpts(is_show=True) # 显示数值
)
# 设置全局选项
bar.set_global_opts(
title_opts={"text": "班级总分排名"},
yaxis_opts=opts.AxisOpts(name="分数"),
xaxis_opts=opts.AxisOpts(name="学生"),
toolbox_opts=opts.ToolboxOpts(is_show=True) # 显示工具栏
)
# 生成图表
bar.render("class_ranking.html")
步骤3: 折线图 - 科目平均分
from pyecharts.charts import Line
# 计算各科平均分
chinese_avg = sum(chinese) // len(chinese)
math_avg = sum(math) // len(math)
english_avg = sum(english) // len(english)
physics_avg = sum(physics) // len(physics)
chemistry_avg = sum(chemistry) // len(chemistry)
subjects = ["语文", "数学", "英语", "物理", "化学"]
avg_scores = [chinese_avg, math_avg, english_avg, physics_avg, chemistry_avg]
# 创建折线图
line = Line()
line.add_xaxis(subjects)
line.add_yaxis(
"平均分",
avg_scores,
markpoint_opts=opts.MarkPointOpts(
data=[
opts.MarkPointItem(type_="max", name="最高分"),
opts.MarkPointItem(type_="min", name="最低分")
]
)
)
line.set_global_opts(
title_opts={"text": "各科目平均分"},
yaxis_opts=opts.AxisOpts(name="分数"),
xaxis_opts=opts.AxisOpts(name="科目")
)
line.render("subject_averages.html")
步骤4: 饼图 - 分数段分布
from pyecharts.charts import Pie
# 统计分数段
ranges = ["优秀(90分以上)", "良好(80-89)", "及格(60-79)", "不及格(60分以下)"]
counts = [0, 0, 0, 0]
# 统计总分段
for score in total_scores:
avg = score / 5 # 计算平均分
if avg >= 90:
counts[0] += 1
elif avg >= 80:
counts[1] += 1
elif avg >= 60:
counts[2] += 1
else:
counts[3] += 1
print("分数段分布:", counts)
# 创建饼图
pie = Pie()
pie.add(
"",
list(zip(ranges, counts)),
radius=["30%", "60%"],
label_opts=opts.LabelOpts(formatter="{b}: {c}人 ({d}%)")
)
pie.set_global_opts(title_opts={"text": "班级成绩分布"})
pie.render("score_distribution.html")
运行结果:
分数段分布: [3, 3, 1, 0] # 优秀3人,良好3人,及格1人,不及格0人
步骤5: 组合所有图表
pyecharts提供了一个Page类,可以把多个图表组合在一个HTML页面:
from pyecharts.charts import Bar, Line, Pie
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
# 数据准备(省略,参考上面的代码)
# 创建三个图表(代码省略)
bar = Bar()
# ... 添加数据和选项
line = Line()
# ... 添加数据和选项
pie = Pie()
# ... 添加数据和选项
# 组合图表
from pyecharts.charts import Page
page = Page(layout=Page.SimplePageLayout)
page.add(
bar,
line,
pie
)
page.render("class_report.html")
运行结果: 打开class_report.html,你会看到三个图表从上到下排列在一个页面中,形成一个完整的成绩分析报告!
给家长的小贴士
- 项目式学习: 这个综合项目能培养孩子的整体思维和问题解决能力
- 数据收集: 鼓励孩子用真实数据(如自己班级的成绩)替换示例数据
- 分析能力: 让孩子根据图表分析班级情况(如:哪科最难,谁进步最大)
- 逐步完成: 强调分步骤完成,不要试图一次写完所有代码
- 调试技巧: 如果某个图表有问题,单独运行它的代码,找出错误
综合练习8:完整的数据分析报告
任务: 选择一个你感兴趣的主题,制作一个完整的数据分析报告:
主题建议:
- 运动数据分析: 班级同学最喜欢的运动类型
- 游戏数据分析: 你和朋友的游戏等级、胜率、场次对比
- 零花钱分析: 一个月的零花钱来源和用途
- 阅读分析: 这学期读了多少本书,各类书的比例
- 自定义主题: 其他你感兴趣的数据
要求:
- 至少包含3种图表(柱状图、折线图、饼图)
- 每个图表都要有标题和坐标轴说明
- 用Page组合所有图表
- 根据图表写出3条分析结论
示例代码框架:
点击查看代码框架
from pyecharts.charts import Bar, Line, Pie from pyecharts.charts import Page from pyecharts import options as opts # 步骤1: 准备数据 # TODO: 填写你的数据 # 步骤2: 创建柱状图 bar = Bar() # TODO: 添加数据和选项 # 步骤3: 创建折线图 line = Line() # TODO: 添加数据和选项 # 步骤4: 创建饼图 pie = Pie() # TODO: 添加数据和选项 # 步骤5: 组合所有图表 page = Page() page.add(bar, line, pie) page.render("my_report.html") print("报告已生成!")
15.7 进阶技巧:让图表更美观
15.7.1 使用主题
pyecharts提供了多种预设主题,可以快速改变图表的配色:
from pyecharts.charts import Bar
from pyecharts import options as opts
from pyecharts.globals import ThemeType
# 使用DARK主题
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
bar.add_xaxis(["苹果", "香蕉", "橙子", "草莓", "葡萄"])
bar.add_yaxis("价格", [8, 3, 6, 15, 12])
bar.set_global_opts(title_opts={"text": "水果价格表"})
bar.render("themed_chart.html")
可用主题:
ThemeType.LIGHT: 浅色主题(默认)ThemeType.DARK: 深色主题ThemeType.ROMA: 罗马主题ThemeType.SHINE: 闪亮主题ThemeType.VINTAGE: 复古主题
15.7.2 自定义颜色
如果你想自定义图表的颜色,可以使用颜色列表:
from pyecharts.charts import Pie
from pyecharts import options as opts
items = ["篮球", "足球", "羽毛球", "乒乓球", "跑步", "游泳"]
counts = [15, 12, 8, 10, 6, 9]
pie = Pie()
pie.add(
"",
list(zip(items, counts)),
# 自定义颜色
color=["#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", "#F7DC6F"]
)
pie.set_global_opts(title_opts={"text": "班级运动喜好"})
pie.render("custom_colors.html")
颜色代码说明:
- 使用十六进制颜色码(如
#FF6B6B) - 可以在线搜索“hex color picker“选择颜色
- 颜色列表长度应该与数据项数量一致
15.7.3 添加提示框和工具栏
from pyecharts.charts import Bar
from pyecharts import options as opts
bar = Bar()
bar.add_xaxis(["第一季度", "第二季度", "第三季度", "第四季度"])
bar.add_yaxis("销售额", [120, 200, 150, 180])
bar.set_global_opts(
# 提示框配置
tooltip_opts=opts.TooltipOpts(
trigger="axis", # 坐标轴触发
axis_pointer_type="shadow" # 阴影指示器
),
# 工具栏配置
toolbox_opts=opts.ToolboxOpts(
is_show=True,
feature={
"saveAsImage": {}, # 保存为图片
"dataView": {}, # 数据视图
"restore": {} # 还原
}
),
# 区域缩放
datazoom_opts=opts.DataZoomOpts(is_show=True)
)
bar.render("advanced_features.html")
功能说明:
- 提示框: 鼠标悬停时显示详细信息
- 工具栏: 右上角显示保存、数据视图等工具
- 区域缩放: 可以缩放查看部分数据
给家长的小贴士
- 颜色搭配: 教孩子基本的配色原则(对比色、同类色)
- 主题选择: 不同主题适合不同场合(如DARK适合夜间查看)
- 功能叠加: 不要一次添加太多功能,会影响图表的可读性
- 审美培养: 鼓励孩子尝试不同的配色,培养审美能力
15.8 常见错误和调试
15.8.1 数据类型错误
错误代码:
from pyecharts.charts import Bar
bar = Bar()
bar.add_xaxis("苹果") # 错误:应该是列表
bar.add_yaxis("价格", 8) # 错误:应该是列表
错误信息:
TypeError: Input x_axis data must be list
正确代码:
bar.add_xaxis(["苹果"]) # 使用列表
bar.add_yaxis("价格", [8]) # 使用列表
给家长的小贴士
- 列表 vs 单个值: pyecharts需要列表,即使只有一个数据也要用
[8]- 仔细阅读错误信息: 错误信息会明确告诉你是哪个参数有问题
15.8.2 数据长度不一致
错误代码:
bar.add_xaxis(["苹果", "香蕉", "橙子"])
bar.add_yaxis("价格", [8, 3]) # 只有2个数据,少了1个
错误信息:
AssertionError: x_axis data and y_axis data must be same length
解决方法: 确保x轴和y轴的数据数量一致:
bar.add_xaxis(["苹果", "香蕉", "橙子"])
bar.add_yaxis("价格", [8, 3, 6]) # 3个数据
15.8.3 文件路径错误
错误代码:
bar.render("C:\Users\用户名\桌面\chart.html")
错误信息:
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes
原因: Python中\是转义字符,\U会被认为是Unicode转义。
解决方法1: 使用原始字符串
bar.render(r"C:\Users\用户名\桌面\chart.html") # 注意r前缀
解决方法2: 使用正斜杠
bar.render("C:/Users/用户名/桌面/chart.html") # 使用/
解决方法3: 只写文件名(推荐)
bar.render("chart.html") # 保存到当前目录
给家长的小贴士
- 路径问题: 小学生可能不理解文件路径,建议让他们只写文件名
- 文件查找: 生成的HTML文件在当前工作目录,可以让孩子用文件管理器搜索
- 桌面快捷方式: 在桌面上创建一个“我的图表“文件夹,方便查找
15.8.4 HTML文件打不开或空白
问题1: HTML文件打开后是空白页
原因: 代码运行时出现错误,但没有生成完整的HTML文件。
解决方法: 在Python中运行代码时,查看是否有错误提示。常见的错误:
- 拼写错误:
add_xasis应该是add_xaxis - 缺少括号或引号
- 变量名未定义
问题2: 浏览器打不开HTML文件
原因: 浏览器太老,不支持某些特性。
解决方法: 更新浏览器或使用Chrome、Edge、Firefox等现代浏览器。
15.8.5 调试技巧
技巧1: 逐步验证
不要一次写完所有代码,而是分步测试:
# 步骤1: 测试数据
print("x轴:", ["苹果", "香蕉"])
print("y轴:", [8, 3])
# 步骤2: 测试图表创建
bar = Bar()
print("图表创建成功")
# 步骤3: 测试添加数据
bar.add_xaxis(["苹果", "香蕉"])
bar.add_yaxis("价格", [8, 3])
print("数据添加成功")
# 步骤4: 测试渲染
bar.render("test.html")
print("渲染完成")
技巧2: 简化数据
如果数据很复杂,先用简单数据测试:
# 复杂数据可能有1000条
# x_data = [...] # 1000条
# y_data = [...] # 1000条
# 先用3条数据测试
x_data = ["A", "B", "C"]
y_data = [1, 2, 3]
bar = Bar()
bar.add_xaxis(x_data)
bar.add_yaxis("测试", y_data)
bar.render("simple_test.html")
技巧3: 查看HTML源代码
如果图表显示不正常,用文本编辑器打开HTML文件,搜索"code":
<script>
var chart = echarts.init(...);
var option = {
"title": {...},
"tooltip": {...},
...
};
chart.setOption(option);
</script>
查看是否有"error"或"undefined"等异常信息。
给家长的小贴士
- 调试思维: 教孩子“分而治之“的调试方法,把大问题拆成小问题
- 错误是朋友: 强调错误信息是帮助我们解决问题的线索
- 保存中间版本: 鼓励孩子定期保存代码的备份,出错时可以回退
15.9 本章小结
15.9.1 核心知识点回顾
1. 数据可视化的重要性
- 把抽象的数字变成直观的图形
- 让数据更容易理解和分析
- 帮助发现数据背后的规律
2. pyecharts库的使用流程
安装: pip install pyecharts
↓
导入: from pyecharts.charts import Bar
↓
创建: bar = Bar()
↓
数据: bar.add_xaxis() / bar.add_yaxis()
↓
选项: bar.set_global_opts()
↓
渲染: bar.render("file.html")
3. 三种常见图表
| 图表类型 | 用途 | 适合场景 |
|---|---|---|
| 柱状图 | 比较不同类别 | 排名、对比、统计 |
| 折线图 | 显示变化趋势 | 成绩进步、气温变化、股票走势 |
| 饼图 | 显示比例关系 | 费用分配、偏好分布、成分构成 |
4. 图表的配置选项
- 标题: title_opts
- 坐标轴: xaxis_opts / yaxis_opts
- 标签: label_opts
- 图例: legend_opts
- 工具栏: toolbox_opts
- 提示框: tooltip_opts
5. 高级功能
- 多系列: 在一个图表上显示多组数据
- 堆叠: 堆叠柱状图显示部分与整体
- 嵌套: 嵌套饼图显示层级关系
- 组合: 用Page组合多个图表
15.9.2 能力检查表
请孩子自我检查以下技能是否掌握:
- 能独立安装pyecharts库
- 能创建并保存一个简单的柱状图
- 能创建并保存一个简单的折线图
- 能创建并保存一个简单的饼图
- 能为图表添加标题和坐标轴说明
- 能在一个图表上显示多组数据
- 能使用Page组合多个图表
- 能读懂简单的错误信息并调试
- 能独立完成一个数据分析小项目
15.9.3 常见问题快速参考
| 问题 | 解决方法 |
|---|---|
| 安装失败 | 使用国内镜像源:pip install pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple |
| 中文乱码 | 在文件第一行添加# -*- coding: utf-8 -*- |
| 数据长度不一致 | 检查x轴和y轴的数据数量是否相同 |
| HTML文件找不到 | 只写文件名(如chart.html),保存到当前目录 |
| 图表空白 | 检查浏览器,使用Chrome或Edge等现代浏览器 |
15.10 挑战练习
挑战1: 天气数据分析
任务: 从网上查找你所在城市最近一周的天气数据(最高气温、最低气温、天气状况),制作:
- 折线图:显示气温变化
- 饼图:显示不同天气状况的比例(如:晴天3天,阴天2天,雨天2天)
要求:
- 使用真实数据
- 图表有标题和说明
- 添加数据标记点(最高温、最低温)
挑战2: 我的学习时间统计
任务: 记录自己一周每天的学习时间,制作:
- 柱状图:显示每天的学习时长
- 饼图:显示学习时间的分配(如:周一2小时,周二3小时…)
要求:
- 数据真实可靠
- 分析哪天学习时间最长/最短
- 找出学习规律并给出建议
挑战3: 游戏数据分析
任务: 如果你有喜欢的游戏,记录游戏数据,制作:
- 柱状图:你和朋友的等级对比
- 折线图:最近10次的胜率变化
- 饼图:使用英雄/武器的频率
要求:
- 至少包含3种图表
- 用Page组合所有图表
- 写出分析结论(如:我最擅长哪个英雄)
挑战4: 班级调查报告
任务: 设计一个班级调查(如:最喜欢的科目、最喜欢的运动、每天的学习时间…),收集数据后制作完整的分析报告。
要求:
- 调查至少10名同学
- 使用柱状图、折线图、饼图
- 报告包含:
- 调查主题
- 数据来源
- 图表分析
- 你的建议
挑战5: 创意数据可视化
任务: 选择一个你感兴趣的主题(如:我的阅读记录、零花钱追踪、运动数据分析…),制作一个创意数据可视化项目。
要求:
- 数据真实且有连续性(至少记录一周)
- 至少3个图表
- 尝试使用主题、自定义颜色等高级功能
- 向同学展示你的报告,并收集反馈
15.11 下一步预告
恭喜你完成了第15章的学习!你已经掌握了:
- ✅ 数据可视化的基本概念
- ✅ 柱状图、折线图、饼图的制作
- ✅ pyecharts库的使用方法
- ✅ 完整的数据分析报告制作
在第16章:图形程序中,你将学习:
- 使用tkinter库创建图形界面
- 按钮、文本框、标签等控件
- 制作带界面的交互程序
想象一下,不再是在黑色的命令行窗口输入命令,而是有漂亮的窗口、按钮、输入框…这就是图形界面的魅力!我们下一章见!
附录:pyecharts速查表
常用图表类
from pyecharts.charts import Bar, Line, Pie
# 柱状图
bar = Bar()
bar.add_xaxis(x_data)
bar.add_yaxis(series_name, y_data)
bar.render("bar.html")
# 折线图
line = Line()
line.add_xaxis(x_data)
line.add_yaxis(series_name, y_data)
line.render("line.html")
# 饼图
pie = Pie()
pie.add(series_name, data)
pie.render("pie.html")
常用配置选项
from pyecharts import options as opts
# 标题
title_opts={"text": "图表标题"}
# 坐标轴
xaxis_opts=opts.AxisOpts(name="x轴名称")
yaxis_opts=opts.AxisOpts(name="y轴名称")
# 标签
label_opts=opts.LabelOpts(is_show=True) # 显示数据标签
# 提示框
tooltip_opts=opts.TooltipOpts(trigger="axis")
# 工具栏
toolbox_opts=opts.ToolboxOpts(is_show=True)
# 数据缩放
datazoom_opts=opts.DataZoomOpts(is_show=True)
常用主题
from pyecharts.globals import ThemeType
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.ROMA))
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.SHINE))
Page组合图表
from pyecharts.charts import Page
page = Page()
page.add(chart1, chart2, chart3)
page.render("combined.html")
祝贺你完成第15章的学习! 🎉
现在,你已经能用Python制作专业的数据报表了!试试用你学到的技能,记录和分析生活中的数据吧!
第16章 图形程序 - 让程序有“面子“
引言:从黑白世界到彩色世界
想象一下,如果你一直在用这样的方式和使用电脑程序:
请输入你的名字:小明
请输入你的年龄:12
你好,小明!你今年12岁了。
这是我们在前面章节中一直使用的命令行程序(Command Line Interface,简称CLI)。它的特点是:
- 只能输入文字
- 只能显示文字
- 需要记住各种命令
- 界面简陋(黑底白字)
但是现在,你用的QQ、微信、王者荣耀、我的世界……这些程序是什么样子的?
- 有漂亮的窗口
- 可以点击按钮
- 可以在输入框里打字
- 可以看到图片和颜色
- 可以用鼠标操作
这种程序叫图形界面程序(Graphical User Interface,简称GUI)!
什么是GUI?
GUI(Graphical User Interface)就是图形用户界面。让我们通过对比来理解:
| 特性 | 命令行程序(CLI) | 图形界面程序(GUI) |
|---|---|---|
| 外观 | 黑底白字,只有文字 | 彩色窗口,有图片、按钮、图标 |
| 操作方式 | 只能用键盘输入命令 | 可以用鼠标点击、拖拽 |
| 使用难度 | 需要记住命令 | 直观易懂,看图标就知道功能 |
| 例子 | 我们之前的所有程序 | QQ、微信、游戏、浏览器 |
为什么学习GUI程序?
学习制作图形界面程序,你将能够:
-
制作真正“像样“的软件
- 不再只是黑白的文字界面
- 可以有漂亮的按钮、输入框、图片
- 让你的程序看起来更专业
-
改善用户体验
- 用户不需要记住命令
- 看到按钮就知道能做什么
- 操作更直观、更方便
-
将之前的程序“升级“
- 把第14章的命令行课表查询程序改成带按钮的
- 把计算器程序改成有按钮和显示屏幕的
- 把猜数字游戏改成有界面的
-
理解日常软件的原理
- QQ的聊天窗口是怎么做出来的?
- 游戏的设置界面是怎么设计的?
- 学完这一章,你就知道答案了!
本章学习路线
本章将教你使用tkinter库制作图形界面程序,同时融入几何和坐标知识:
第1步:认识tkinter库 - Python自带的GUI工具
↓
第2步:复习数学坐标知识 - 窗口坐标系统
↓
第3步:创建第一个窗口 - 设置大小和位置
↓
第4步:添加组件 - 按钮、输入框、标签(运用坐标知识)
↓
第5步:布局管理 - 让组件排列整齐(运用几何知识)
↓
第6步:事件处理 - 让按钮"动"起来
↓
第7步:综合项目 - 改写CLI程序为GUI版本
👨🏫 给家长的小贴士
- GUI是现代软件的标准: 几乎所有现代软件都使用图形界面
- 培养用户思维: 让孩子思考“怎么让用户更方便地使用程序“
- 激发创造力: 图形界面可以自由设计颜色、布局,孩子会很有成就感
- 实际应用: 可以制作家庭记账本、学习计划表等实用工具
- 本章重点融入的数学知识:
- 坐标系: 计算机窗口的坐标原点在左上角(与数学坐标系不同)
- 位置和尺寸: 组件的(x, y)位置,宽度width,高度height
- 面积计算: 窗口面积 = 宽 × 高
- 几何图形: 矩形、正方形在界面布局中的应用
- 本章融入的计算机知识:
- 显卡和显示器: 图形如何显示在屏幕上
- 事件驱动: 点击按钮如何触发程序执行
- CPU的中断机制: 计算机如何响应鼠标和键盘操作
tkinter是什么?
tkinter是Python自带的一个图形界面库。它的名字来源于:
- tk: 一个著名的图形界面工具包(Tool Kit)
- inter: interface(界面)的缩写
- t: 表示这是Tk的Python接口( Tcl/Tk 的Python接口)
为什么要用tkinter?
- 免费且内置:Python安装时就自带了,不需要额外安装
- 简单易学:代码简洁,容易上手
- 功能够用:可以制作常见的界面元素
- 跨平台:在Windows、Mac、Linux上都能运行
tkinter能做什么?
- ✅ 创建窗口
- ✅ 添加按钮
- ✅ 添加输入框
- ✅ 添加文字标签
- ✅ 添加图片
- ✅ 添加下拉菜单
- ✅ 添加复选框和单选按钮
- ✅ 添加滑动条
- ✅ ……还有很多其他组件
给家长的小贴士
- GUI是现代软件的标准:几乎所有现代软件都使用图形界面
- 培养用户思维:让孩子思考“怎么让用户更方便地使用程序“
- 激发创造力:图形界面可以自由设计颜色、布局,孩子会很有成就感
- 实际应用:可以制作家庭记账本、学习计划表等实用工具
- 学习曲线:GUI比命令行程序复杂一些,需要更多耐心
- 建议:先让孩子熟悉一个简单例子,再鼓励他设计自己的界面
16.1 第一个窗口程序
16.1.1 最简单的窗口
让我们从最简单的开始——创建一个空白窗口!
# 导入tkinter库
import tkinter as tk
# 创建主窗口
root = tk.Tk()
# 进入消息循环(让窗口一直显示)
root.mainloop()
运行结果: 弹出一个空白窗口!
代码解释:
-
import tkinter as tk- 导入tkinter库
as tk表示给tkinter起个简短的别名,以后用tk代替tkinter
-
root = tk.Tk()- 创建一个主窗口
Tk()是创建主窗口的函数root是这个窗口的名字(你可以叫它window或main_window)
-
root.mainloop()- 进入消息循环
- 这是最重要的一行!
- 让窗口一直显示,等待用户操作
- 如果没有这一行,窗口会一闪而过
小知识:什么是“消息循环“?
想象一下你开了一家店:
root = tk.Tk():把店面装修好,准备开门root.mainloop():你站在店门口,一直等待顾客进来
- 如果顾客来了(点击按钮、输入文字等),你就处理顾客的需求
- 如果没有顾客,你就继续等待
- 如果没有这一步,店开一下就关门了!
16.1.2 给窗口起个名字
现在我们的窗口标题是默认的“tk“,让我们改个名字:
import tkinter as tk
root = tk.Tk()
# 设置窗口标题
root.title("我的第一个GUI程序")
root.mainloop()
运行结果: 窗口标题变成了“我的第一个GUI程序“!
16.1.3 设置窗口大小
窗口默认大小可能不太合适,让我们设置一下:
import tkinter as tk
root = tk.Tk()
root.title("我的第一个GUI程序")
# 设置窗口大小(宽x高)
root.geometry("400x300")
root.mainloop()
运行结果: 窗口变成了400像素宽、300像素高!
注意:
geometry的意思是“几何形状“"400x300"中的x是字母x,不是乘号!- 单位是像素(Pixel,电脑屏幕最小的显示单位)
16.1.4 综合示例:漂亮的窗口
import tkinter as tk
root = tk.Tk()
root.title("我的第一个GUI程序")
root.geometry("500x400")
# TODO: 后面我们会在这里添加按钮、输入框等组件
root.mainloop()
⚠️ 常见错误
错误1:忘记mainloop()
import tkinter as tk root = tk.Tk() # 忘记写 root.mainloop()结果:窗口一闪而过,或者根本不显示
错误2:大小写成乘号
root.geometry(400x300) # 错误!x会被当作变量名正确写法:
root.geometry("400x300")(必须加引号,且x是字母)
🎮 实践练习1:创建你的第一个窗口
任务:创建一个窗口,满足以下要求:
- 标题为:“Python图形界面”
- 大小为:600×400
- 尝试修改大小,看看不同尺寸的效果
提示:使用
title()和geometry()方法🔍 查看答案
import tkinter as tk root = tk.Tk() root.title("Python图形界面") root.geometry("600x400") root.mainloop()
16.2 认识计算机坐标系 📐
在开始添加组件之前,让我们先学习计算机的坐标系,这对放置组件非常重要!
16.2.1 计算机坐标系 vs 数学坐标系
你在数学课上学过平面直角坐标系:
- 原点: 在左下角
- x轴: 向右为正方向
- y轴: 向上为正方向
- 坐标: (x, y),x是横坐标,y是纵坐标
数学坐标系示例:
y↑
|
4 | • (3, 4)
3 |
2 |
1 | • (1, 1)
0---+---+---+---+---→x
0 1 2 3 4
但是,计算机的坐标系完全不同!
16.2.2 计算机窗口坐标系
计算机坐标系的特点:
- 原点: 在左上角(记住这个重要差异!)
- x轴: 向右为正方向(和数学一样)
- y轴: 向下为正方向(和数学相反!)
- 单位: 像素(Pixel)
计算机坐标系示例:
0 1 2 3 4 →x
0---+---+---+---+---
1 | • (1, 1)
2 |
3 | • (3, 3)
4 |
↓y
关键差异:
- 数学坐标系:y向上,计算机坐标系:y向下
- 数学坐标系:原点在左下,计算机坐标系:原点在左上
为什么计算机坐标系是这样的?
- 显示器扫描是从左上角开始的(像我们看书,从左上到右下)
- 这样设计符合西方文字的阅读习惯(从上到下,从左到右)
👨🏫 给家长的小贴士
- 类比方法: 用阅读顺序解释为什么y轴向下(看书从第一行开始,往下看)
- 对比记忆: 在纸上画两个坐标系对比,加深印象
- 实际演示: 在纸上画图,然后思考在计算机上如何实现
- 常见错误: 孩子容易混淆两个坐标系,需要多次强调“左上角是原点“
16.2.3 窗口的坐标和尺寸
让我们用代码理解窗口的坐标和尺寸:
import tkinter as tk
root = tk.Tk()
root.title("窗口坐标示例")
# 设置窗口大小(宽x高)
root.geometry("400x300")
print(f"窗口宽度: {root.winfo_width()}") # 400
print(f"窗口高度: {root.winfo_height()}") # 300
# 注意:窗口创建后,需要更新才能获取正确尺寸
root.update()
print(f"更新后宽度: {root.winfo_width()}")
print(f"更新后高度: {root.winfo_height()}")
root.mainloop()
代码解析:
geometry("400x300"): 设置窗口宽400像素,高300像素winfo_width(): 获取窗口的当前宽度winfo_height(): 获取窗口的当前高度update(): 强制窗口更新,确保获取到正确的尺寸
16.2.4 组件的位置坐标
当我们添加按钮、标签等组件时,需要指定它们的位置。
位置参数:
x: 组件左上角的x坐标(从窗口左边开始)y: 组件左上角的y坐标(从窗口上边开始)width: 组件的宽度height: 组件的高度
示例:
import tkinter as tk
root = tk.Tk()
root.title("组件位置示例")
root.geometry("400x300")
# 添加一个标签,指定位置(x=50, y=100)
label = tk.Label(root, text="我在哪里?", bg="yellow")
label.place(x=50, y=100, width=200, height=30)
root.mainloop()
代码解析:
x=50: 标签左边距离窗口左边50像素y=100: 标签上边距离窗口上边100像素width=200: 标签宽度200像素height=30: 标签高度30像素
可视化:
窗口(400x300)
┌────────────────────────────┐
│ ↑y │
│ │ │
│ │ ┌──────────┐ │
│100 │黄色标签 │(200x30) │
│ │ └──────────┘ │
│ │ │
│ └─→x │
│ 50 │
└────────────────────────────┘
16.2.5 坐标计算练习
让我们做一些数学练习,巩固坐标的概念!
练习1: 计算组件位置
窗口大小是600×400,你想把一个按钮放在:
- 窗口的正中央
- 按钮大小是100×50
数学计算:
窗口宽度 = 600,窗口高度 = 400
按钮宽度 = 100,按钮高度 = 50
正中央的x坐标 = (窗口宽度 - 按钮宽度) / 2
= (600 - 100) / 2
= 500 / 2
= 250
正中央的y坐标 = (窗口高度 - 按钮高度) / 2
= (400 - 50) / 2
= 350 / 2
= 175
所以按钮坐标是 (250, 175)
Python代码验证:
import tkinter as tk
root = tk.Tk()
root.title("居中按钮")
root.geometry("600x400")
# 计算居中位置
window_width = 600
window_height = 400
button_width = 100
button_height = 50
center_x = (window_width - button_width) / 2 # 250
center_y = (window_height - button_height) / 2 # 175
# 创建按钮
button = tk.Button(root, text="我在正中央!", bg="lightblue")
button.place(x=center_x, y=center_y, width=button_width, height=button_height)
print(f"按钮坐标: ({center_x}, {center_y})")
root.mainloop()
练习2: 计算窗口面积和组件面积
import tkinter as tk
root = tk.Tk()
root.title("面积计算")
root.geometry("500x400")
# 窗口面积
window_area = 500 * 400
print(f"窗口面积: {window_area} 平方像素")
# 添加3个按钮
btn1 = tk.Button(root, text="按钮1", bg="red")
btn1.place(x=50, y=50, width=100, height=40)
btn2 = tk.Button(root, text="按钮2", bg="green")
btn2.place(x=200, y=100, width=120, height=50)
btn3 = tk.Button(root, text="按钮3", bg="blue")
btn3.place(x=100, y=250, width=150, height=60)
# 计算按钮总面积
btn1_area = 100 * 40 # 4000
btn2_area = 120 * 50 # 6000
btn3_area = 150 * 60 # 9000
total_btn_area = btn1_area + btn2_area + btn3_area
print(f"按钮1面积: {btn1_area}")
print(f"按钮2面积: {btn2_area}")
print(f"按钮3面积: {btn3_area}")
print(f"按钮总面积: {total_btn_area}")
print(f"按钮占窗口比例: {total_btn_area / window_area * 100:.1f}%")
root.mainloop()
运行结果:
窗口面积: 200000 平方像素
按钮1面积: 4000
按钮2面积: 6000
按钮3面积: 9000
按钮总面积: 19000
按钮占窗口比例: 9.5%
👨🏫 给家长的小贴士
- 数学融入: GUI编程是复习数学知识(坐标、面积、比例)的好机会
- 可视化: 比起纸上的题目,GUI让学生能直观看到计算结果
- 实际应用: 问孩子“如果让你设计一个登录界面,按钮应该放哪里?“
- 难度递进: 从简单的位置计算开始,逐步到复杂的布局
- 鼓励调试: 让孩子修改坐标数值,看看组件位置如何变化
16.2.6 坐标系对比总结
| 特性 | 数学坐标系 | 计算机坐标系 |
|---|---|---|
| 原点位置 | 左下角 | 左上角 |
| x轴方向 | 向右为正 | 向右为正 |
| y轴方向 | 向上为正 | 向下为正 |
| 坐标表示 | (x, y) | (x, y) |
| 常见用途 | 数学函数图像 | 窗口、网页布局 |
🎯 实践练习2:坐标计算练习
任务: 创建一个窗口(600×400),完成以下组件的放置:
- 标签“标题“:放在窗口正上方(x=200, y=20,宽200,高30)
- 按钮“确定“:放在窗口正中央,大小100×40
- 按钮“取消“:放在“确定“按钮右边50像素处
- 计算“确定“按钮的坐标(x, y)
- 计算两个按钮总共占多少面积
答案:
🔍 查看答案
import tkinter as tk root = tk.Tk() root.title("坐标练习") root.geometry("600x400") # 1. 标题 title_label = tk.Label(root, text="用户登录", bg="lightyellow", font=("Arial", 16)) title_label.place(x=200, y=20, width=200, height=30) # 2. 确定按钮(正中央) btn_width = 100 btn_height = 40 window_width = 600 window_height = 400 ok_x = (window_width - btn_width) / 2 # 250 ok_y = (window_height - btn_height) / 2 # 180 ok_btn = tk.Button(root, text="确定", bg="lightgreen") ok_btn.place(x=ok_x, y=ok_y, width=btn_width, height=btn_height) print(f"确定按钮坐标: ({ok_x}, {ok_y})") # 3. 取消按钮(右边50像素) cancel_x = ok_x + btn_width + 50 # 250 + 100 + 50 = 400 cancel_y = ok_y # 和确定按钮同一行 cancel_btn = tk.Button(root, text="取消", bg="lightcoral") cancel_btn.place(x=cancel_x, y=cancel_y, width=btn_width, height=btn_height) # 4. 计算总面积 one_btn_area = btn_width * btn_height # 4000 two_btn_area = one_btn_area * 2 # 8000 print(f"两个按钮总面积: {two_btn_area} 平方像素") root.mainloop()
16.3 常用组件:按钮、标签和输入框
窗口创建好了,但里面空空如也!让我们添加一些组件(Widget)。
什么是组件? 组件就是窗口里的各种元素,比如:
- 按钮(Button)
- 标签(Label,显示文字)
- 输入框(Entry)
- 文本框(Text)
- 等等……
16.2.1 标签(Label)- 显示文字
标签用来在窗口上显示文字或图片。
import tkinter as tk
root = tk.Tk()
root.title("标签示例")
root.geometry("300x200")
# 创建一个标签
label = tk.Label(root, text="你好,这是我的第一个标签!")
# 把标签显示到窗口上
label.pack()
root.mainloop()
运行结果: 窗口中显示了一行文字:“你好,这是我的第一个标签!”
代码解释:
-
tk.Label(root, text="...")root:表示这个标签要放在哪个窗口里text="...":标签上显示的文字
-
label.pack()- 这一行很重要!
- 把标签“打包“放到窗口上
- 如果不写这一行,标签不会显示
🎯 类比时间
想象你在布置房间:
tk.Label():在纸上画出装饰品.pack():把这个装饰品真正贴到墙上
16.2.2 按钮(Button)- 可以点击
按钮是最常用的组件之一,点击后可以触发某个操作。
import tkinter as tk
root = tk.Tk()
root.title("按钮示例")
root.geometry("300x200")
# 创建一个按钮
button = tk.Button(root, text="点击我")
# 把按钮显示到窗口上
button.pack()
root.mainloop()
运行结果: 窗口中显示了一个按钮,上面写着“点击我“,你可以用鼠标点击它!(虽然现在点击不会发生什么)
16.2.3 输入框(Entry)- 输入文字
输入框让用户可以输入文字。
import tkinter as tk
root = tk.Tk()
root.title("输入框示例")
root.geometry("300x200")
# 创建一个标签作为提示
label = tk.Label(root, text="请输入你的名字:")
label.pack()
# 创建一个输入框
entry = tk.Entry(root)
entry.pack()
root.mainloop()
运行结果:
- 上面一行文字:“请输入你的名字:”
- 下面一个白色的输入框,你可以在里面打字!
16.2.4 让按钮“动“起来:事件处理
现在按钮能点击,但点击后什么都没发生。让我们让按钮点击后做点事情!
import tkinter as tk
# 定义一个函数(点击按钮时会执行这个函数)
def on_button_click():
print("按钮被点击了!")
root = tk.Tk()
root.title("按钮点击示例")
root.geometry("300x200")
# 创建按钮,点击时执行on_button_click函数
button = tk.Button(root, text="点击我", command=on_button_click)
button.pack()
root.mainloop()
运行结果: 每次点击按钮,在命令行(终端/黑窗口)中会输出:“按钮被点击了!”
代码解释:
-
def on_button_click():- 定义了一个函数
- 这个函数包含了点击按钮时要执行的代码
-
command=on_button_clickcommand是Button的一个参数- 它告诉按钮:被点击时执行哪个函数
- 注意:函数名后面不要加括号
()
⚠️ 重要提醒
# ✅ 正确写法 button = tk.Button(root, text="点击我", command=on_button_click) # ❌ 错误写法 button = tk.Button(root, text="点击我", command=on_button_click())为什么不能加括号?
- 加了括号意味着“立刻执行这个函数“
- 不加括号意味着“把这个函数的名字告诉按钮,等点击时再执行“
16.2.5 实用示例:获取输入框的内容
让我们做一个更有用的例子:在输入框输入名字,点击按钮后显示问候语!
import tkinter as tk
def say_hello():
# 获取输入框的内容
name = entry.get()
# 创建一个新标签显示问候语
result_label = tk.Label(root, text=f"你好,{name}!")
result_label.pack()
root = tk.Tk()
root.title("问候程序")
root.geometry("300x200")
# 提示标签
label = tk.Label(root, text="请输入你的名字:")
label.pack()
# 输入框
entry = tk.Entry(root)
entry.pack()
# 按钮
button = tk.Button(root, text="问候", command=say_hello)
button.pack()
root.mainloop()
运行结果:
- 在输入框输入名字,比如“小明“
- 点击“问候“按钮
- 下面会显示:“你好,小明!”
代码解释:
-
entry.get()- 获取输入框中用户输入的内容
- 返回一个字符串
-
每次点击按钮,都会创建一个新标签显示问候语
🎮 实践练习2:制作一个简单的计算器
任务:制作一个能计算两个数之和的程序
要求:
- 两个输入框:输入第一个数和第二个数
- 一个按钮:点击时计算和
- 一个标签:显示计算结果
提示:
- 使用两个Entry组件
- 使用
entry.get()获取输入- 注意:
get()返回的是字符串,需要用int()转换为数字🔍 查看答案
import tkinter as tk def calculate_sum(): # 获取两个输入框的值 num1 = entry1.get() num2 = entry2.get() # 转换为整数并计算 result = int(num1) + int(num2) # 显示结果 result_label.config(text=f"结果:{result}") root = tk.Tk() root.title("加法计算器") root.geometry("300x200") # 第一个数 label1 = tk.Label(root, text="第一个数:") label1.pack() entry1 = tk.Entry(root) entry1.pack() # 第二个数 label2 = tk.Label(root, text="第二个数:") label2.pack() entry2 = tk.Entry(root) entry2.pack() # 计算按钮 button = tk.Button(root, text="计算", command=calculate_sum) button.pack() # 结果标签 result_label = tk.Label(root, text="结果:") result_label.pack() root.mainloop()进阶挑战:
- 如果用户输入的不是数字,程序会出错吗?如何改进?
- 提示:使用
try-except捕获错误
16.3 布局管理:让组件排列整齐
现在你会发现一个问题:每次用.pack(),组件都是自动从上往下排。如果我们想要更灵活的布局呢?
tkinter提供了三种布局管理器:
- pack:按顺序排列(简单)
- grid:网格排列(灵活)
- place:精确位置(精确)
16.3.1 pack布局 - 简单排列
pack是最简单的布局方式,组件会按顺序从上到下、从左到右排列。
import tkinter as tk
root = tk.Tk()
root.title("pack布局示例")
root.geometry("300x200")
label1 = tk.Label(root, text="第一个标签")
label1.pack()
label2 = tk.Label(root, text="第二个标签")
label2.pack()
label3 = tk.Label(root, text="第三个标签")
label3.pack()
root.mainloop()
运行结果: 三个标签从上到下排列
pack的常用参数:
# 从顶部开始排列
label.pack(side="top")
# 从底部开始排列
label.pack(side="bottom")
# 从左边开始排列
label.pack(side="left")
# 从右边开始排列
label.pack(side="right")
# 设置外部间距(与其他组件的距离)
label.pack(padx=10, pady=10) # x方向10像素,y方向10像素
# 设置内部填充(组件内容与边框的距离)
label.pack(ipadx=5, ipady=5)
16.3.2 grid布局 - 网格排列
grid让窗口像一个表格,可以指定组件放在哪一行、哪一列。
import tkinter as tk
root = tk.Tk()
root.title("grid布局示例")
root.geometry("300x200")
# 第1行,第1列
label1 = tk.Label(root, text="用户名:")
label1.grid(row=0, column=0)
# 第1行,第2列
entry1 = tk.Entry(root)
entry1.grid(row=0, column=1)
# 第2行,第1列
label2 = tk.Label(root, text="密码:")
label2.grid(row=1, column=0)
# 第2行,第2列
entry2 = tk.Entry(root)
entry2.grid(row=1, column=1)
# 第3行,跨两列
button = tk.Button(root, text="登录")
button.grid(row=2, column=0, columnspan=2)
root.mainloop()
运行结果:
用户名: [输入框]
密码: [输入框]
[ 登录按钮 ]
代码解释:
row=0, column=0:放在第0行、第0列(注意:从0开始计数!)columnspan=2:跨2列(按钮横跨两列)
💡 什么时候用pack,什么时候用grid?
用pack:
- 简单的从上到下排列
- 不需要精确控制位置
用grid:
- 需要表格式的布局
- 需要精确控制行和列
- 比如登录表单(标签和输入框对齐)
🎮 实践练习3:使用grid布局制作登录界面
任务:使用grid布局制作一个登录界面
要求:
- 用户名标签和输入框(第1行)
- 密码标签和输入框(第2行)
- 登录按钮(第3行,跨两列居中)
🔍 查看答案
import tkinter as tk def login(): username = entry_username.get() password = entry_password.get() result_label.config(text=f"用户名:{username}\n密码:{password}") root = tk.Tk() root.title("登录界面") root.geometry("300x200") # 用户名 label_username = tk.Label(root, text="用户名:") label_username.grid(row=0, column=0, padx=5, pady=5) entry_username = tk.Entry(root) entry_username.grid(row=0, column=1, padx=5, pady=5) # 密码 label_password = tk.Label(root, text="密码:") label_password.grid(row=1, column=0, padx=5, pady=5) entry_password = tk.Entry(root, show="*") # 显示为星号 entry_password.grid(row=1, column=1, padx=5, pady=5) # 登录按钮 button_login = tk.Button(root, text="登录", command=login) button_login.grid(row=2, column=0, columnspan=2, pady=10) # 结果标签 result_label = tk.Label(root, text="") result_label.grid(row=3, column=0, columnspan=2) root.mainloop()新知识点:
show="*":让输入框显示为星号(用于密码输入)padx=5, pady=5:设置组件的外部间距
16.3.3 place布局 - 精确定位
place可以精确指定组件的位置(不常用,了解一下即可)。
import tkinter as tk
root = tk.Tk()
root.title("place布局示例")
root.geometry("300x200")
# 在坐标(100, 50)处放置标签
label = tk.Label(root, text="精确位置的标签")
label.place(x=100, y=50)
root.mainloop()
16.4 更多常用组件
除了按钮、标签和输入框,tkinter还有很多其他有用的组件。
16.4.1 文本框(Text)- 多行文本
**输入框(Entry)**只能输入一行,**文本框(Text)**可以输入多行。
import tkinter as tk
def show_text():
# 获取文本框内容
content = text.get("1.0", "end") # 从第1行第0列到末尾
print(content)
root = tk.Tk()
root.title("文本框示例")
root.geometry("400x300")
# 创建文本框
text = tk.Text(root, width=40, height=10)
text.pack()
# 创建按钮
button = tk.Button(root, text="显示内容", command=show_text)
button.pack()
root.mainloop()
运行结果:
- 一个大的文本框,可以输入多行文字
- 点击按钮后,在终端显示文本框内容
代码解释:
width=40, height=10:文本框宽40个字符,高10行text.get("1.0", "end"):获取从第1行第0列到末尾的所有内容
16.4.2 复选框(Checkbutton)
复选框让用户选择“是/否“或“选中/不选中“。
import tkinter as tk
def show_hobbies():
if var_music.get() == 1:
print("你喜欢音乐")
if var_sports.get() == 1:
print("你喜欢运动")
if var_reading.get() == 1:
print("你喜欢阅读")
root = tk.Tk()
root.title("复选框示例")
root.geometry("300x200")
# 创建变量存储复选框状态
var_music = tk.IntVar()
var_sports = tk.IntVar()
var_reading = tk.IntVar()
# 创建复选框
check_music = tk.Checkbutton(root, text="音乐", variable=var_music)
check_music.pack()
check_sports = tk.Checkbutton(root, text="运动", variable=var_sports)
check_sports.pack()
check_reading = tk.Checkbutton(root, text="阅读", variable=var_reading)
check_reading.pack()
# 按钮
button = tk.Button(root, text="确定", command=show_hobbies)
button.pack()
root.mainloop()
代码解释:
tk.IntVar():创建一个整数变量variable=var_music:把复选框和变量绑定var_music.get() == 1:如果复选框被选中,值为1,否则为0
16.4.3 单选按钮(Radiobutton)
单选按钮让用户从多个选项中选一个。
import tkinter as tk
def show_grade():
grade = var_grade.get()
print(f"你选择的年级是:{grade}")
root = tk.Tk()
root.title("单选按钮示例")
root.geometry("300x200")
# 创建变量存储选项
var_grade = tk.StringVar()
var_grade.set("一年级") # 默认值
# 创建单选按钮
radio1 = tk.Radiobutton(root, text="一年级", variable=var_grade, value="一年级")
radio1.pack()
radio2 = tk.Radiobutton(root, text="二年级", variable=var_grade, value="二年级")
radio2.pack()
radio3 = tk.Radiobutton(root, text="三年级", variable=var_grade, value="三年级")
radio3.pack()
# 按钮
button = tk.Button(root, text="确定", command=show_grade)
button.pack()
root.mainloop()
代码解释:
tk.StringVar():创建一个字符串变量value="一年级":这个选项代表的值- 所有单选按钮使用同一个
variable,这样它们就会互斥(只能选一个)
🎮 实践练习4:制作调查问卷
任务:制作一个调查问卷
要求:
- 姓名(输入框)
- 年级(单选按钮:一年级/二年级/三年级/四年级/五年级/六年级)
- 爱好(复选框:阅读/运动/音乐/绘画/游戏)
- 提交按钮(点击后显示用户的选择)
🔍 查看答案
import tkinter as tk def submit(): name = entry_name.get() grade = var_grade.get() hobbies = [] if var_reading.get() == 1: hobbies.append("阅读") if var_sports.get() == 1: hobbies.append("运动") if var_music.get() == 1: hobbies.append("音乐") if var_painting.get() == 1: hobbies.append("绘画") if var_games.get() == 1: hobbies.append("游戏") result = f"姓名:{name}\n年级:{grade}\n爱好:{', '.join(hobbies)}" result_label.config(text=result) root = tk.Tk() root.title("调查问卷") root.geometry("400x500") # 姓名 label_name = tk.Label(root, text="姓名:") label_name.pack(pady=5) entry_name = tk.Entry(root) entry_name.pack(pady=5) # 年级 label_grade = tk.Label(root, text="年级:") label_grade.pack(pady=5) var_grade = tk.StringVar() var_grade.set("一年级") grades = ["一年级", "二年级", "三年级", "四年级", "五年级", "六年级"] for g in grades: radio = tk.Radiobutton(root, text=g, variable=var_grade, value=g) radio.pack() # 爱好 label_hobbies = tk.Label(root, text="爱好(可多选):") label_hobbies.pack(pady=5) var_reading = tk.IntVar() var_sports = tk.IntVar() var_music = tk.IntVar() var_painting = tk.IntVar() var_games = tk.IntVar() check_reading = tk.Checkbutton(root, text="阅读", variable=var_reading) check_reading.pack() check_sports = tk.Checkbutton(root, text="运动", variable=var_sports) check_sports.pack() check_music = tk.Checkbutton(root, text="音乐", variable=var_music) check_music.pack() check_painting = tk.Checkbutton(root, text="绘画", variable=var_painting) check_painting.pack() check_games = tk.Checkbutton(root, text="游戏", variable=var_games) check_games.pack() # 提交按钮 button_submit = tk.Button(root, text="提交", command=submit) button_submit.pack(pady=10) # 结果 result_label = tk.Label(root, text="") result_label.pack(pady=10) root.mainloop()新知识点:
- 使用循环创建多个单选按钮
', '.join(hobbies):把列表用逗号连接成字符串
16.5 综合项目:改写命令行程序为GUI版本
现在我们已经学习了tkinter的基本知识,让我们把之前的命令行程序改写成图形界面版本!
16.5.1 项目选择:猜数字游戏
你还记得第7章(条件语句)中的猜数字游戏吗?
原版(命令行版本):
import random
secret = random.randint(1, 100)
guess = 0
while guess != secret:
guess = int(input("猜一个1-100的数字:"))
if guess > secret:
print("太大了!")
elif guess < secret:
print("太小了!")
else:
print("恭喜你,猜对了!")
改版(GUI版本):
import random
import tkinter as tk
from tkinter import messagebox
def check_guess():
# 获取用户输入
user_input = entry_guess.get()
# 检查是否输入了数字
if not user_input:
messagebox.showwarning("提示", "请输入一个数字!")
return
try:
guess = int(user_input)
except ValueError:
messagebox.showerror("错误", "请输入有效的数字!")
return
# 检查数字范围
if guess < 1 or guess > 100:
messagebox.showwarning("提示", "请输入1-100之间的数字!")
return
# 检查猜测结果
global attempts
attempts += 1
if guess > secret:
result_label.config(text="太大了!再试一次", fg="red")
elif guess < secret:
result_label.config(text="太小了!再试一次", fg="blue")
else:
result_label.config(text=f"恭喜你猜对了!答案就是{secret}!\n你用了{attempts}次。", fg="green")
messagebox.showinfo("成功", f"恭喜你猜对了!\n答案:{secret}\n尝试次数:{attempts}")
restart_game()
def restart_game():
global secret, attempts
secret = random.randint(1, 100)
attempts = 0
result_label.config(text="游戏已重新开始!请猜1-100的数字", fg="black")
entry_guess.delete(0, tk.END)
# 初始化游戏
secret = random.randint(1, 100)
attempts = 0
# 创建主窗口
root = tk.Tk()
root.title("猜数字游戏")
root.geometry("400x300")
# 标题
title_label = tk.Label(root, text="猜数字游戏(1-100)", font=("Arial", 16))
title_label.pack(pady=10)
# 说明
instruction_label = tk.Label(root, text="我已经想好了一个1-100的数字,你来猜!")
instruction_label.pack(pady=5)
# 输入框
entry_guess = tk.Entry(root, font=("Arial", 12))
entry_guess.pack(pady=10)
entry_guess.focus() # 让输入框自动获得焦点
# 按钮
button_guess = tk.Button(root, text="猜一下", command=check_guess, font=("Arial", 12))
button_guess.pack(pady=5)
button_restart = tk.Button(root, text="重新开始", command=restart_game, font=("Arial", 12))
button_restart.pack(pady=5)
# 结果标签
result_label = tk.Label(root, text="请输入1-100的数字", font=("Arial", 12))
result_label.pack(pady=10)
root.mainloop()
运行效果:
- 窗口标题:“猜数字游戏”
- 显示说明:“我已经想好了一个1-100的数字,你来猜!”
- 输入框:输入猜测的数字
- “猜一下“按钮:点击后检查猜测结果
- “重新开始“按钮:开始新游戏
- 结果标签:显示“太大了“、“太小了“或“恭喜你猜对了”
新知识点:
-
messagebox.showwarning("标题", "消息")- 显示警告对话框
- 有黄色的警告图标
-
messagebox.showerror("标题", "消息")- 显示错误对话框
- 有红色的错误图标
-
messagebox.showinfo("标题", "消息")- 显示信息对话框
- 有蓝色的信息图标
-
entry_guess.delete(0, tk.END)- 清空输入框的内容
0:从第0个字符开始tk.END:到末尾
-
entry_guess.focus()- 让输入框自动获得焦点
- 程序启动后可以直接输入,不需要先点击输入框
-
result_label.config(text="...", fg="red")- 修改标签的文字和颜色
fg是foreground(前景色)的缩写
16.5.2 更多改进思路
还可以继续改进这个游戏:
-
添加进度提示
# 显示还剩多少次机会 attempts_left_label = tk.Label(root, text=f"剩余机会:{max_attempts - attempts}") attempts_left_label.pack() -
添加历史记录
# 记录之前的猜测 history_label = tk.Label(root, text="历史记录:" + ", ".join(history)) history_label.pack() -
添加难度选择
# 简单:1-50,普通:1-100,困难:1-200
🎮 实践练习5:改写其他CLI程序
任务:选择一个之前写过的命令行程序,改写成GUI版本
建议选择:
- 计算器(第6章顺序语句)
- 成绩等级判断(第7章条件语句)
- 乘法口诀表(第8章循环语句)
- 简单计算器(第12章函数)
要求:
- 使用至少3种不同的组件
- 合理布局(美观、易用)
- 添加错误处理(输入非数字等)
- 添加说明文字
提示:
- 先画草图:界面怎么设计
- 列出需要的组件
- 选择合适的布局方式(pack或grid)
- 逐步添加功能,不要一次写完
16.6 美化界面
现在我们的程序功能已经完整,但界面还可以更漂亮!
16.6.1 设置字体和颜色
import tkinter as tk
root = tk.Tk()
root.title("美化界面")
root.geometry("400x300")
# 大标题
title_label = tk.Label(
root,
text="欢迎来到Python世界",
font=("Arial", 20, "bold"), # 字体、大小、加粗
fg="blue", # 前景色(文字颜色)
bg="yellow" # 背景色
)
title_label.pack(pady=20)
# 按钮
button = tk.Button(
root,
text="点击我",
font=("宋体", 14),
bg="green",
fg="white",
activebackground="darkgreen", # 点击时的背景色
activeforeground="white", # 点击时的文字颜色
relief="raised", # 边框样式:raised(凸起)、sunken(凹陷)、flat(扁平)
bd=3 # 边框宽度
)
button.pack(pady=10)
root.mainloop()
运行效果:
- 黄色背景、蓝色粗体大标题
- 绿色按钮(白色文字)
- 点击按钮时变成深绿色
16.6.2 常用颜色
tkinter支持多种颜色设置方式:
# 1. 颜色名称
fg="red"
fg="blue"
fg="green"
fg="yellow"
fg="black"
fg="white"
# 2. 十六进制颜色码(更精确)
fg="#FF0000" # 红色
fg="#0000FF" # 蓝色
fg="#00FF00" # 绿色
fg="#FFFF00" # 黄色
常用颜色速查表:
| 颜色 | 名称 | 十六进制 |
|---|---|---|
| 红色 | red | #FF0000 |
| 绿色 | green | #008000 |
| 蓝色 | blue | #0000FF |
| 黄色 | yellow | #FFFF00 |
| 黑色 | black | #000000 |
| 白色 | white | #FFFFFF |
| 橙色 | orange | #FFA500 |
| 紫色 | purple | #800080 |
16.6.3 设置组件大小
# 设置标签的大小(宽度和高度)
label = tk.Label(
root,
text="固定大小的标签",
width=20, # 宽度(字符数)
height=3 # 高度(行数)
)
# 设置按钮的大小
button = tk.Button(
root,
text="固定大小的按钮",
width=15,
height=2
)
🎨 实践练习6:美化猜数字游戏
任务:美化之前制作的猜数字游戏
要求:
- 标题使用大字体、加粗、蓝色
- 按钮使用绿色背景、白色文字
- 输入框使用大字体
- 结果文字根据情况显示不同颜色(太大=红色,太小=蓝色,正确=绿色)
- 添加背景色
🔍 查看答案
import random import tkinter as tk from tkinter import messagebox def check_guess(): user_input = entry_guess.get() if not user_input: messagebox.showwarning("提示", "请输入一个数字!") return try: guess = int(user_input) except ValueError: messagebox.showerror("错误", "请输入有效的数字!") return if guess < 1 or guess > 100: messagebox.showwarning("提示", "请输入1-100之间的数字!") return global attempts attempts += 1 if guess > secret: result_label.config(text="太大了!再试一次", fg="red") elif guess < secret: result_label.config(text="太小了!再试一次", fg="blue") else: result_label.config(text=f"恭喜你猜对了!答案就是{secret}!\n你用了{attempts}次。", fg="green") messagebox.showinfo("成功", f"恭喜你猜对了!\n答案:{secret}\n尝试次数:{attempts}") restart_game() def restart_game(): global secret, attempts secret = random.randint(1, 100) attempts = 0 result_label.config(text="游戏已重新开始!请猜1-100的数字", fg="black") entry_guess.delete(0, tk.END) # 初始化游戏 secret = random.randint(1, 100) attempts = 0 # 创建主窗口 root = tk.Tk() root.title("猜数字游戏") root.geometry("500x400") root.configure(bg="#f0f0f0") # 设置窗口背景色 # 标题 title_label = tk.Label( root, text="🎮 猜数字游戏(1-100)", font=("Arial", 20, "bold"), fg="blue", bg="#f0f0f0" ) title_label.pack(pady=15) # 说明 instruction_label = tk.Label( root, text="我已经想好了一个1-100的数字,你来猜!", font=("Arial", 12), bg="#f0f0f0" ) instruction_label.pack(pady=5) # 输入框 entry_guess = tk.Entry(root, font=("Arial", 14)) entry_guess.pack(pady=10) entry_guess.focus() # 按钮框架 button_frame = tk.Frame(root, bg="#f0f0f0") button_frame.pack(pady=10) button_guess = tk.Button( button_frame, text="🔍 猜一下", command=check_guess, font=("Arial", 12), bg="green", fg="white", width=10 ) button_guess.grid(row=0, column=0, padx=5) button_restart = tk.Button( button_frame, text="🔄 重新开始", command=restart_game, font=("Arial", 12), bg="orange", fg="white", width=10 ) button_restart.grid(row=0, column=1, padx=5) # 结果标签 result_label = tk.Label( root, text="请输入1-100的数字", font=("Arial", 14), bg="#f0f0f0" ) result_label.pack(pady=15) root.mainloop()
16.7 常见错误和调试
在编写GUI程序时,可能会遇到各种问题。让我们看看常见的错误和解决方法。
16.7.1 常见错误
错误1:窗口不显示
错误代码:
import tkinter as tk
root = tk.Tk()
# 忘记写 root.mainloop()
原因:忘记调用mainloop()
解决方法:在代码最后加上root.mainloop()
错误2:组件不显示
错误代码:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="你好")
# 忘记写 label.pack() 或 label.grid()
root.mainloop()
原因:创建组件后没有使用布局管理器(pack、grid或place)
解决方法:在创建组件后调用布局方法
label = tk.Label(root, text="你好")
label.pack() # 或 label.grid(...)
错误3:组件重叠
错误代码:
import tkinter as tk
root = tk.Tk()
# 同时使用pack和grid
label1 = tk.Label(root, text="标签1")
label1.pack()
label2 = tk.Label(root, text="标签2")
label2.grid(row=0, column=0)
root.mainloop()
错误提示:
_tkinter.TclError: cannot use geometry manager pack inside .!frame which already has slaves managed by grid
原因:在同一个父容器中混用pack和grid
解决方法:在同一个父容器中只使用一种布局方式
# 全部使用pack
label1.pack()
label2.pack()
# 或者全部使用grid
label1.grid(row=0, column=0)
label2.grid(row=1, column=0)
错误4:获取输入框内容时出错
错误代码:
def get_input():
# 用户没有输入任何内容
text = entry.get()
number = int(text) # 如果text是空字符串,会出错
错误提示:
ValueError: invalid literal for int() with base 10: ''
原因:输入框为空时,get()返回空字符串,无法转换为数字
解决方法:先检查是否为空
def get_input():
text = entry.get()
# 检查是否为空
if not text:
messagebox.showwarning("提示", "请输入内容!")
return
number = int(text)
错误5:函数调用时参数错误
错误代码:
def say_hello(name):
print(f"你好,{name}!")
button = tk.Button(root, text="点击", command=say_hello("小明"))
错误现象:程序启动时就调用了函数,而不是点击时调用
原因:command=say_hello("小明")会立刻执行函数,正确的做法是传递函数名
解决方法:使用lambda表达式
# 方法1:使用lambda
button = tk.Button(root, text="点击", command=lambda: say_hello("小明"))
# 方法2:改写函数,不使用参数
def say_hello():
name = entry.get()
print(f"你好,{name}!")
button = tk.Button(root, text="点击", command=say_hello)
16.7.2 调试技巧
技巧1:使用print调试
在关键位置添加print语句,查看程序执行情况
def check_guess():
guess = entry.get()
print(f"用户输入:{guess}") # 调试输出
if int(guess) > secret:
print("猜大了") # 调试输出
result_label.config(text="太大了")
技巧2:使用messagebox显示中间结果
def check_guess():
guess = entry.get()
messagebox.showinfo("调试", f"用户输入:{guess}")
# 后续代码...
技巧3:逐步添加功能
不要一次写完所有代码,而是逐步添加功能,每步都测试
# 第1步:先创建窗口
root = tk.Tk()
root.mainloop()
# 第2步:添加标签
root = tk.Tk()
label = tk.Label(root, text="你好")
label.pack()
root.mainloop()
# 第3步:添加按钮
root = tk.Tk()
label = tk.Label(root, text="你好")
label.pack()
button = tk.Button(root, text="点击")
button.pack()
root.mainloop()
# 第4步:添加功能
def on_click():
print("点击了")
button = tk.Button(root, text="点击", command=on_click)
技巧4:注释掉部分代码
如果程序出错,可以注释掉部分代码,逐步缩小问题范围
def complex_function():
# 注释掉复杂的部分
# result = some_calculation()
# another_function(result)
# 先测试简单部分
print("函数被调用")
🎮 实践练习7:调试练习
任务:找出下面代码中的5个错误并修正
import tkinter as tk def show_info(): name = entry.get() age = int(age_entry.get()) print(f"姓名:{name},年龄:{age}") root = tk.Tk() root.title("信息输入") label = tk.Label(root, text="姓名:") label.pack() entry = tk.Entry(root) entry.grid(row=0, column=1) # 错误1 age_label = tk.Label(root, text="年龄:") age_label.pack() age_entry = tk.Entry(root) age_entry.pack() button = tk.Button(root, text="提交", command=show_info()) # 错误2 button.pack() # 错误3:忘记mainloop()🔍 查看答案
错误1:混用pack和grid布局
# 错误 label.pack() entry.grid(row=0, column=1) # 正确:统一使用pack label.pack() entry.pack() # 或统一使用grid label.grid(row=0, column=0) entry.grid(row=0, column=1)错误2:command参数不应该加括号
# 错误 button = tk.Button(root, text="提交", command=show_info()) # 正确 button = tk.Button(root, text="提交", command=show_info)错误3:忘记mainloop()
# 正确 root.mainloop()额外问题:
- 如果age_entry为空,
int(age_entry.get())会报错- 应该添加错误处理
完整正确代码:
import tkinter as tk from tkinter import messagebox def show_info(): name = entry.get() age_text = age_entry.get() if not name or not age_text: messagebox.showwarning("提示", "请填写完整信息!") return try: age = int(age_text) result_label.config(text=f"姓名:{name},年龄:{age}") except ValueError: messagebox.showerror("错误", "年龄必须是数字!") root = tk.Tk() root.title("信息输入") root.geometry("300x200") label = tk.Label(root, text="姓名:") label.pack() entry = tk.Entry(root) entry.pack() age_label = tk.Label(root, text="年龄:") age_label.pack() age_entry = tk.Entry(root) age_entry.pack() button = tk.Button(root, text="提交", command=show_info) button.pack() result_label = tk.Label(root, text="") result_label.pack() root.mainloop()
16.8 本章小结
16.8.1 核心知识点回顾
1. GUI vs CLI
- GUI(图形用户界面):有窗口、按钮、颜色,用鼠标操作
- CLI(命令行界面):只有文字,用键盘输入命令
2. tkinter库
- Python自带的GUI库
- 可以创建窗口、按钮、输入框等组件
- 使用
root = tk.Tk()创建主窗口 - 使用
root.mainloop()让窗口持续显示
3. 常用组件
| 组件 | 类名 | 用途 |
|---|---|---|
| 标签 | Label | 显示文字或图片 |
| 按钮 | Button | 点击后执行操作 |
| 输入框 | Entry | 输入单行文字 |
| 文本框 | Text | 输入多行文字 |
| 复选框 | Checkbutton | 多选 |
| 单选按钮 | Radiobutton | 单选 |
4. 布局管理器
pack:按顺序排列(从上到下、从左到右)grid:网格排列(指定行和列)place:精确定位(指定坐标)
5. 事件处理
# 定义处理函数
def on_click():
print("按钮被点击")
# 绑定事件
button = tk.Button(root, text="点击", command=on_click)
6. messagebox对话框
messagebox.showinfo():显示信息messagebox.showwarning():显示警告messagebox.showerror():显示错误
7. 美化界面
font:设置字体fg:设置前景色(文字颜色)bg:设置背景色width、height:设置大小
16.8.2 能力检查表
学习完本章后,请检查自己是否掌握了以下技能:
- 能够创建一个tkinter窗口
- 能够在窗口中添加标签、按钮、输入框
- 能够使用pack和grid布局管理器
- 能够让按钮点击时执行某个函数
- 能够获取输入框的内容
- 能够使用messagebox显示对话框
- 能够设置组件的字体和颜色
- 能够将命令行程序改写为GUI版本
- 能够调试简单的GUI程序错误
16.8.3 常见问题快速参考
| 问题 | 解决方法 |
|---|---|
| 窗口不显示 | 检查是否调用了root.mainloop() |
| 组件不显示 | 检查是否调用了.pack()或.grid() |
| 点击按钮没反应 | 检查command=函数名是否正确(不要加括号) |
| 输入框获取内容出错 | 检查输入框是否为空,使用try-except处理错误 |
| 组件重叠 | 同一个父容器中不要混用pack和grid |
| 函数传参错误 | 使用lambda表达式:command=lambda: func(args) |
16.9 挑战练习
挑战1:计算器升级版 ⭐⭐
制作一个图形界面的计算器,要求:
- 有数字按钮(0-9)
- 有运算符按钮(+、-、×、÷)
- 有等号和清除按钮
- 有一个显示区域(Label)
提示:
- 使用grid布局排列按钮
- 点击数字按钮时,把数字添加到显示区域
- 点击等号时,计算表达式的结果(可以使用
eval()函数)
挑战2:记账本 ⭐⭐⭐
制作一个家庭记账本,要求:
- 可以输入收入或支出
- 可以输入金额、类别、备注
- 可以记录到列表中(用Label显示)
- 可以计算总收入、总支出、结余
- 可以清空所有记录
提示:
- 使用多个Entry输入不同信息
- 使用Radiobutton选择收入/支出
- 使用List或字典存储记录
- 使用Text组件显示所有记录
挑战3:待办事项清单 ⭐⭐⭐⭐
制作一个待办事项清单(TODO List),要求:
- 可以添加新的待办事项
- 可以标记事项为“已完成“
- 可以删除事项
- 可以按优先级排序(高/中/低)
- 可以保存到文件、从文件加载
提示:
- 使用Checkbutton标记完成状态
- 使用Radiobutton选择优先级
- 使用List或字典存储所有事项
- 使用文件操作保存和加载(第13章知识)
挑战4:单词卡片学习工具 ⭐⭐⭐⭐
制作一个英语单词学习工具,要求:
- 可以添加新单词(英文+中文)
- 可以随机显示单词
- 可以显示答案(中文意思)
- 可以标记为“已掌握“或“需要复习“
- 可以统计学习进度
提示:
- 使用字典存储单词:
{"apple": "苹果", "banana": "香蕉"} - 使用random模块随机选择单词
- 使用两个按钮:“显示答案“和“下一个单词”
挑战5:简单的绘图板 ⭐⭐⭐⭐⭐
制作一个简单的绘图板,要求:
- 可以选择颜色
- 可以选择画笔粗细
- 可以用鼠标在Canvas(画布)上画线
- 可以清除画布
- 可以保存画好的图片
提示:
- 使用Canvas组件(本章未介绍,需要查资料)
- 绑定鼠标事件:
<Button-1>(点击)、<B1-Motion>(拖动) - 使用
create_line()方法画线
16.10 下一步
恭喜你完成了第16章!你已经学会了:
✅ 创建图形界面程序 ✅ 使用常用组件(标签、按钮、输入框等) ✅ 管理界面布局 ✅ 处理用户操作(点击、输入等) ✅ 美化界面 ✅ 将命令行程序改写为GUI版本
你的技能树:
Python基础
├─ 变量和数据类型 ✅
├─ 条件语句 ✅
├─ 循环语句 ✅
├─ 函数 ✅
├─ 文件操作 ✅
├─ 命令行程序 ✅
├─ 数据可视化(pyecharts)✅
└─ 图形界面程序(tkinter)✅ ← 当前位置
下一章(第17章):程序设计
在最后一章中,你将学习:
- 如何评价一个程序的好坏
- 变量的设计原则
- 程序设计的一般方法
- 如何规划一个完整的程序
这将帮助你从“会写代码“提升到“会设计程序“!
附录:tkinter速查表
A1. 常用组件速查
# 导入tkinter
import tkinter as tk
from tkinter import messagebox
# 创建主窗口
root = tk.Tk()
root.title("窗口标题")
root.geometry("400x300")
# 标签
label = tk.Label(root, text="文字")
label.pack()
# 按钮
button = tk.Button(root, text="点击", command=函数名)
button.pack()
# 输入框
entry = tk.Entry(root)
entry.pack()
content = entry.get() # 获取内容
# 文本框(多行)
text = tk.Text(root, width=40, height=10)
text.pack()
content = text.get("1.0", "end") # 获取内容
# 复选框
var = tk.IntVar()
checkbutton = tk.Checkbutton(root, text="选项", variable=var)
checkbutton.pack()
if var.get() == 1: # 被选中
# 单选按钮
var = tk.StringVar()
var.set("选项1")
radio1 = tk.Radiobutton(root, text="选项1", variable=var, value="选项1")
radio2 = tk.Radiobutton(root, text="选项2", variable=var, value="选项2")
radio1.pack()
radio2.pack()
# 进入消息循环
root.mainloop()
A2. 布局管理器速查
# pack布局
component.pack() # 默认:从上到下
component.pack(side="left") # 从左到右
component.pack(side="right") # 从右到左
component.pack(padx=10, pady=10) # 外部间距
# grid布局
component.grid(row=0, column=0) # 第0行第0列
component.grid(row=1, column=2) # 第1行第2列
component.grid(columnspan=2) # 跨2列
component.grid(rowspan=3) # 跨3行
# place布局
component.place(x=100, y=50) # 精确定位
A3. 颜色速查
# 前景色(文字颜色)
fg="red"
fg="#FF0000"
# 背景色
bg="blue"
bg="#0000FF"
# 常用颜色
# red, blue, green, yellow, black, white, orange, purple
A4. messagebox速查
from tkinter import messagebox
# 信息对话框
messagebox.showinfo("标题", "消息内容")
# 警告对话框
messagebox.showwarning("标题", "消息内容")
# 错误对话框
messagebox.showerror("标题", "消息内容")
# 确认对话框(返回"yes"或"no")
result = messagebox.askyesno("标题", "确定吗?")
# 是/否/取消对话框(返回"yes"、"no"或"cancel")
result = messagebox.askyesnocancel("标题", "确定吗?")
学习建议:
- 多动手实践,每个例子都亲自运行一遍
- 尝试修改代码,看看效果有什么变化
- 把之前的CLI程序改写成GUI版本
- 设计自己的小工具(如记账本、学习计划表)
- 遇到问题时,先用print或messagebox调试
记住:学习编程最好的方法就是多写代码!💪
第17章 程序设计 - 如何写出好程序
引言:从“能运行“到“写得好“
想象一下,有两个同学都写了一个“猜数字“游戏程序:
同学A的程序:
import random
n=random.randint(1,100)
while True:
g=int(input("?"))
if g>n:print("大")
elif g<n:print("小")
else:print("对");break
同学B的程序:
import random
# 猜数字游戏
# 目标:猜一个1-100之间的随机数
secret_number = random.randint(1, 100)
guess_count = 0
print("=== 猜数字游戏 ===")
print("我已经想好了一个1到100之间的数字")
print("你能猜到它是多少吗?")
while True:
guess = input("请输入你的猜测(输入q退出):")
# 允许用户退出
if guess == 'q':
print(f"游戏结束!正确答案是:{secret_number}")
break
# 验证输入
if not guess.isdigit():
print("请输入一个有效的数字!")
continue
guess_count += 1
guess = int(guess)
# 比较大小
if guess > secret_number:
print(f"{guess} 太大了!再试试")
elif guess < secret_number:
print(f"{guess} 太小了!再试试")
else:
print(f"恭喜你!{guess} 就是正确答案!")
print(f"你总共猜了 {guess_count} 次")
break
两个程序的对比
| 对比项 | 同学A的程序 | 同学B的程序 |
|---|---|---|
| 能否运行 | ✅ 能运行 | ✅ 能运行 |
| 变量命名 | ❌ n, g(看不懂) | ✅ secret_number, guess(清晰) |
| 注释 | ❌ 没有注释 | ✅ 有注释说明 |
| 用户体验 | ❌ 提示不清楚 | ✅ 友好的提示 |
| 错误处理 | ❌ 输入非数字会崩溃 | ✅ 验证输入,可以退出 |
| 代码格式 | ❌ 一行多语句 | ✅ 格式清晰 |
问题:如果你是老师,你会给哪个程序更高的分数?
答案:当然是同学B!虽然两个程序都能“运行“,但同学B的程序:
- 更容易理解和修改
- 更健壮(不容易出错)
- 用户体验更好
什么是“好程序“?
好程序不仅要能运行,还要:
- 正确性 - 能正确解决问题
- 可读性 - 别人能看懂你的代码
- 可维护性 - 容易修改和扩展
- 健壮性 - 不容易出错
- 效率 - 运行速度快,占用资源少
为什么要学习“程序设计“?
你可能在想:“我写的程序能运行不就行了吗?为什么要学这些?”
答案是:
-
让代码更容易理解
- 过了一个月,你自己都看不懂自己写的代码
- 别人看你的代码像看“天书“
-
让代码更容易修改
- 需求变化时,不用重写整个程序
- 可以轻松添加新功能
-
减少程序错误
- 好的设计让错误更少
- 出错了也更容易找到
-
为大型程序做准备
- 写10行的程序,随便写写也行
- 写100行、1000行的程序,就需要好的设计方法
-
成为一名优秀的程序员
- 初级程序员:能写出能运行的代码
- 高级程序员:能写出优雅、健壮的代码
本章学习路线
第1步:如何评价一个程序的好坏
↓
第2步:变量设计的原则
↓
第3步:程序设计的一般方法
↓
第4步:综合实践:用设计方法重写程序
↓
第5步:常见错误和调试技巧
给家长的小贴士:这一章是理论性较强的章节,但非常重要。建议家长:
- 用“写作文“类比程序设计:作文不仅要通顺,还要有结构、有逻辑
- 鼓励孩子对比自己之前的程序,找出可以改进的地方
- 强调“好习惯“的重要性:现在养成好习惯,以后写程序会更轻松
- 可以让孩子“代码审查“家长写的程序,找出问题
17.1 如何评价一个程序的好坏
程序评价的五个维度
我们可以从以下五个维度评价一个程序:
1. 正确性(Correctness)
定义:程序是否正确地解决了问题。
如何判断:
- 输入合法数据,输出结果是否正确?
- 边界情况是否正确?(例如:空列表、0、负数)
- 错误输入是否妥善处理?
举例:
写一个“计算平均分“的程序:
❌ 不正确的版本:
scores = [80, 90, 85]
average = sum(scores) / 3 # 假设固定3个科目
print(average)
问题:如果列表不是3个科目,结果就错了!
✅ 正确的版本:
def calculate_average(scores):
if not scores: # 处理空列表
return 0
return sum(scores) / len(scores)
# 测试各种情况
print(calculate_average([80, 90, 85])) # 正常情况
print(calculate_average([])) # 空列表
print(calculate_average([100])) # 一个元素
给家长的小贴士:教导孩子“测试思维“
- 编写程序后,要主动测试各种情况
- 询问:“如果输入是空的会怎样?” “如果是负数会怎样?”
- 这能培养孩子的严谨思维
2. 可读性(Readability)
定义:程序是否容易被人类理解。
评价标准:
- ✅ 变量名能说明用途
- ✅ 有适当的注释
- ✅ 代码格式整齐
- ✅ 逻辑清晰
举例对比:
❌ 可读性差的代码:
a=10
b=20
c=a*b
print(c)
问题:a、b、c是什么意思?
✅ 可读性好的代码:
length = 10 # 长方形的长
width = 20 # 长方形的宽
area = length * width # 计算面积
print(f"面积是:{area}")
可读性的三个黄金法则:
-
好命名
# ❌ 差的命名 x = 10 s = "hello" flg = True # ✅ 好的命名 age = 10 user_name = "hello" is_valid = True -
好注释
# ❌ 没有注释 s = s.replace(" ", "") # ✅ 有注释 # 去除用户名中的所有空格 user_name = user_name.replace(" ", "") -
好格式
# ❌ 格式混乱 if x>0:x=x+1;print(x) # ✅ 格式清晰 if x > 0: x = x + 1 print(x)
给家长的小贴士:鼓励孩子“像讲故事一样写代码“
- 变量名要像一个“好标题“
- 注释要像“故事说明“
- 代码要像“分段清晰的文章“
3. 可维护性(Maintainability)
定义:程序是否容易被修改和扩展。
问题场景:
- 需求变化时,是否需要大改代码?
- 修复一个bug,会不会引入新的bug?
- 能否轻松添加新功能?
举例:
❌ 可维护性差的代码:
# 硬编码的值,难以修改
price = 100
tax = price * 0.13 # 税率13%写死在代码里
total = price + tax
print(total)
问题:如果税率改成15%,要修改所有地方!
✅ 可维护性好的代码:
# 使用常量,易于修改
TAX_RATE = 0.13 # 税率集中定义
def calculate_total(price):
"""计算含税总价"""
tax = price * TAX_RATE
return price + tax
print(calculate_total(100))
print(calculate_total(200))
优势:修改税率只需要改一行!
可维护性的技巧:
-
避免重复代码(DRY原则)
# ❌ 重复代码 area1 = length1 * width1 area2 = length2 * width2 area3 = length3 * width3 # ✅ 使用函数 def calculate_area(length, width): return length * width area1 = calculate_area(length1, width1) area2 = calculate_area(length2, width2) area3 = calculate_area(length3, width3) -
使用函数封装
# ❌ 所有代码堆在一起 a = 10 b = 20 print(a + b) c = 30 d = 40 print(c + d) # ✅ 封装成函数 def add_and_print(x, y): print(x + y) add_and_print(10, 20) add_and_print(30, 40)
给家长的小贴士:
- 用“乐高积木“比喻函数:每块积木(函数)做好后,可以重复使用
- 当孩子写类似的代码时,提醒:“这能不能做成一个函数?”
4. 健壮性(Robustness)
定义:程序是否能处理各种异常情况,不容易崩溃。
问题场景:
- 用户输入错误时,程序是否崩溃?
- 数据不完整时,程序是否继续运行?
- 出现错误时,是否有友好的提示?
举例:
❌ 不健壮的代码:
age = int(input("请输入年龄:"))
print(f"你明年{age + 1}岁")
问题:如果用户输入“abc“,程序崩溃!
✅ 健壮的代码:
while True:
age_input = input("请输入年龄:")
# 验证输入是否为数字
if not age_input.isdigit():
print("请输入一个有效的数字!")
continue
age = int(age_input)
# 验证年龄范围
if age < 0 or age > 150:
print("年龄应该在0-150之间!")
continue
print(f"你明年{age + 1}岁")
break
健壮性的三个原则:
-
永远不要相信用户输入
# 假设用户可能输入任何东西 user_input = input("请输入数字:") # 先验证再使用 if user_input.isdigit(): number = int(user_input) # 使用这个数字 else: print("输入无效!") -
处理边界情况
# 边界情况:空列表 scores = [] if scores: # 先检查是否为空 average = sum(scores) / len(scores) else: print("没有成绩数据") -
提供有用的错误信息
# ❌ 无用的错误信息 print("错误") # ✅ 有用的错误信息 print("错误:文件不存在,请检查文件名是否正确")
给家长的小贴士:
- 和孩子玩“找茬游戏“:让孩子想方设法“破坏“程序
- 问孩子:“如果你故意输入错误,程序会怎样?”
- 这能培养孩子的“防御性编程“思维
5. 效率(Efficiency)
定义:程序运行的速度和占用的资源。
对于初学者:
- 不要过度优化
- “先让它能运行,再让它运行得更快”
- 可读性比效率更重要
什么时候需要考虑效率:
- 数据量很大时(例如:处理10000条数据)
- 程序运行很慢时
- 使用有限的资源(例如:内存)
简单优化技巧:
-
避免重复计算
# ❌ 重复计算 for i in range(1000): result = sum(very_large_list) * i # 每次循环都重新计算 # ✅ 只计算一次 total = sum(very_large_list) for i in range(1000): result = total * i -
选择合适的数据结构
# 如果需要频繁查找,用字典而不是列表 # ❌ 用列表查找(慢) students_list = ["Alice", "Bob", "Charlie"] if "Bob" in students_list: # 需要遍历整个列表 print("找到Bob") # ✅ 用字典查找(快) students_dict = {"Alice": 1, "Bob": 2, "Charlie": 3} if "Bob" in students_dict: # 直接查找 print("找到Bob")
给家长的小贴士:
- 告诉孩子:“就像写作文,先写完,再润色”
- 对于初学者,可读性 > 效率
- 如果程序运行速度能接受,就不需要优化
综合评价案例
让我们用五个维度评价一个完整的程序:
题目:写一个“学生成绩管理“程序
版本A:基础版
scores = []
while True:
s = input("输入成绩(q退出):")
if s == 'q':
break
scores.append(int(s))
print(sum(scores)/len(scores))
版本B:改进版
def calculate_average(scores):
"""计算平均分"""
if not scores:
return 0
return sum(scores) / len(scores)
def get_valid_score(prompt):
"""获取有效的成绩输入"""
while True:
user_input = input(prompt)
if user_input.lower() == 'q':
return None
# 验证输入
if not user_input.isdigit():
print("请输入一个有效的数字!")
continue
score = int(user_input)
# 验证范围
if score < 0 or score > 100:
print("成绩应该在0-100之间!")
continue
return score
def main():
"""主程序"""
print("=== 学生成绩管理系统 ===")
scores = []
while True:
score = get_valid_score("请输入成绩(0-100,输入q退出):")
if score is None:
break
scores.append(score)
if scores:
average = calculate_average(scores)
highest = max(scores)
lowest = min(scores)
print(f"\n=== 成绩统计 ===")
print(f"学生人数:{len(scores)}")
print(f"平均分:{average:.2f}")
print(f"最高分:{highest}")
print(f"最低分:{lowest}")
else:
print("没有输入成绩数据")
if __name__ == "__main__":
main()
评价对比:
| 维度 | 版本A | 版本B |
|---|---|---|
| 正确性 | ✅ 基本正确 | ✅ 完全正确(处理空列表) |
| 可读性 | ❌ 变量名s不明确 | ✅ 变量名清晰,有注释 |
| 可维护性 | ❌ 代码重复,难扩展 | ✅ 使用函数,易扩展 |
| 健壮性 | ❌ 输入非数字会崩溃 | ✅ 验证输入和范围 |
| 效率 | ✅ 效率可以接受 | ✅ 效率可以接受 |
结论:版本B是一个更好的程序!
练习1:评价以下程序
请用五个维度评价以下程序,指出优点和缺点:
# 计算圆的面积
r = float(input("请输入半径:"))
area = 3.14 * r * r
print(area)
📝 查看评价
评价结果:
-
正确性:⭐⭐⭐⭐
- ✅ 计算公式正确
- ⚠️ π只用3.14,精度不够
-
可读性:⭐⭐⭐
- ✅ 变量名r和area还算清晰
- ❌ 没有注释
- ❌ 输出没有说明
-
可维护性:⭐⭐⭐
- ⚠️ π的值硬编码
- ✅ 逻辑简单,容易理解
-
健壮性:⭐
- ❌ 没有检查半径是否为负数
- ❌ 输入非数字会崩溃
-
效率:⭐⭐⭐⭐⭐
- ✅ 简单计算,效率很高
改进建议:
import math
def calculate_circle_area(radius):
"""计算圆的面积"""
if radius <= 0:
raise ValueError("半径必须大于0")
return math.pi * radius * radius
try:
radius = float(input("请输入圆的半径:"))
area = calculate_circle_area(radius)
print(f"半径为 {radius} 的圆的面积是:{area:.2f}")
except ValueError as e:
print(f"输入错误:{e}")
17.2 变量的设计
为什么变量设计很重要?
变量是程序中最基本的“存储单元“。变量设计得好坏,直接影响程序的质量。
比喻:
- 变量就像收纳箱
- 好的变量设计:每个箱子贴上清晰的标签,只放一种物品
- 坏的变量设计:箱子没有标签,什么都混在一起
变量设计的三个原则
原则1:职责明确(Single Responsibility)
核心思想:一个变量只承担一个职责。
❌ 不好的例子:
# x既用来存储输入,又用来存储计算结果
x = input("请输入数字:")
x = int(x) * 2
print(x)
问题:x的职责不清晰,容易混淆。
✅ 好的例子:
# 每个变量职责明确
user_input = input("请输入数字:")
number = int(user_input)
doubled_number = number * 2
print(doubled_number)
比喻:
- 像整理房间,一个抽屉只放一种东西
- “袜子抽屉“只放袜子,“内衣抽屉“只放内衣
原则2:命名规范(Meaningful Names)
核心思想:变量名要能“自解释“,让人一看就知道它存的是什么。
命名规范:
-
使用有意义的英文名词
# ❌ 不好的命名 a = 10 x = "hello" f1 = 3.14 # ✅ 好的命名 age = 10 user_name = "hello" pi = 3.14 -
使用完整单词,不要过度缩写
# ❌ 过度缩写 s = "hello" # s是什么? nm = "Alice" # nm是name吗? cnt = 0 # cnt是count吗? # ✅ 完整单词 name = "hello" username = "Alice" count = 0 -
使用下划线分隔多个单词(snake_case)
# ❌ 不符合Python风格 userName = "Alice" StudentAge = 10 # ✅ Python风格(snake_case) user_name = "Alice" student_age = 10 -
布尔变量用is/has/can开头
# ✅ 清晰的布尔命名 is_valid = True has_permission = False can_edit = True is_empty = False # ❌ 不清晰的布尔命名 valid = True permission = False edit = True -
集合类型用复数名词
# ✅ 清晰的集合命名 students = ["Alice", "Bob", "Charlie"] scores = [80, 90, 85] books = ["书1", "书2", "书3"] # ❌ 不清晰的集合命名 student_list = ["Alice", "Bob", "Charlie"] score_array = [80, 90, 85]
命名禁忌:
- ❌ 使用单个字母(除了循环变量i, j, k)
- ❌ 使用拼音(如xingming)
- ❌ 使用中文(Python3支持但不推荐)
- ❌ 使用关键字(如if, for, while)
- ❌ 使用特殊字符(如@, #, $)
给家长的小贴士:
- 像教孩子写作文“起标题“一样,教孩子给变量起名
- 鼓励孩子使用“能看懂的英文“,而不是“a“, “b”, “c”
- 可以建议孩子准备一个“变量命名词典“,记录常用的英文单词
原则3:作用域最小化(Minimize Scope)
核心思想:变量的作用范围越小越好。
什么是作用域:
- 变量能被访问的代码范围
- 在函数内部定义的变量,只能在函数内部使用
- 在函数外部定义的变量,可以在整个程序中使用
为什么作用域要小:
- 减少变量被意外修改的风险
- 让程序更容易理解
- 降低代码的耦合度
❌ 不好的例子:
# 全局变量,任何地方都能修改
counter = 0
def increment():
global counter
counter = counter + 1
def decrement():
global counter
counter = counter - 1
increment()
decrement()
print(counter)
问题:counter是全局变量,任何函数都能修改,容易出错。
✅ 好的例子:
def process_numbers(numbers):
"""局部变量,作用域在函数内"""
counter = 0
total = 0
for num in numbers:
counter += 1
total += num
average = total / counter
return average
result = process_numbers([10, 20, 30])
print(result)
作用域最小化的技巧:
-
优先使用局部变量
# ✅ 好的做法:变量定义在需要的地方 def calculate_rectangle_area(length, width): area = length * width # 局部变量 return area -
避免全局变量
# ❌ 不好:使用全局变量 TAX_RATE = 0.13 def calculate_tax(price): return price * TAX_RATE # ✅ 更好:作为参数传递 def calculate_tax(price, tax_rate): return price * tax_rate -
循环变量的作用域
# ✅ 好的做法:循环变量只在循环中使用 for i in range(10): print(i) # i在循环外就没有意义了
给家长的小贴士:
- 用“隐私“的概念比喻作用域
- “就像你的日记本,只有你自己能看,别人不能随便翻”
- 变量也是一样,尽量让它“私有“,不要让所有人都能访问
变量设计的实战案例
案例:设计一个“学生成绩统计“程序
需求:
- 输入多个学生的成绩
- 计算平均分、最高分、最低分
- 统计及格人数
设计1:不好的变量设计
# ❌ 变量命名不清晰
a = []
while True:
b = input("输入成绩:")
if b == 'q':
break
a.append(int(b))
c = sum(a) / len(a)
d = max(a)
e = min(a)
f = 0
for g in a:
if g >= 60:
f = f + 1
print(c, d, e, f)
问题:
- a, b, c, d, e, f, g这些变量名完全没有意义
- 看代码完全不知道在做什么
设计2:改进的变量设计
# ✅ 变量命名清晰,职责明确
scores = [] # 存储所有成绩
passing_score = 60 # 及格分数线
while True:
user_input = input("请输入成绩(输入q退出):")
if user_input == 'q':
break
score = int(user_input)
scores.append(score)
if scores:
average_score = sum(scores) / len(scores) # 平均分
highest_score = max(scores) # 最高分
lowest_score = min(scores) # 最低分
passing_count = 0 # 及格人数
for score in scores:
if score >= passing_score:
passing_count += 1
print(f"平均分:{average_score:.2f}")
print(f"最高分:{highest_score}")
print(f"最低分:{lowest_score}")
print(f"及格人数:{passing_count}/{len(scores)}")
优点:
- 每个变量的职责都很明确
- 变量名能“自解释“
- 代码易于理解和维护
练习2:改进变量设计
请改进以下程序的变量设计:
x = input("请输入学生姓名:")
y = int(input("请输入语文成绩:"))
z = int(input("请输入数学成绩:"))
w = int(input("请输入英语成绩:"))
v = y + z + w
u = v / 3
print(f"{x}的总分是{v},平均分是{u}")
📝 查看改进方案
# ✅ 改进后的版本
student_name = input("请输入学生姓名:")
chinese_score = int(input("请输入语文成绩:"))
math_score = int(input("请输入数学成绩:"))
english_score = int(input("请输入英语成绩:"))
total_score = chinese_score + math_score + english_score
average_score = total_score / 3
print(f"{student_name}的总分是{total_score},平均分是{average_score:.2f}")
改进点:
- x → student_name:明确表示学生姓名
- y, z, w → chinese_score, math_score, english_score:分别表示各科成绩
- v → total_score:总分
- u → average_score:平均分
- 添加:.2f格式化平均分输出
17.3 程序设计的一般方法
从“想到哪里写到哪里“到“系统化设计“
初学者的做法:
看到题目 → 直接开始写代码 → 边写边想 → 不断修改
程序员的做法:
分析需求 → 设计方案 → 编写代码 → 测试调试 → 优化改进
比喻:
- 初学者:像没有地图就开车,开到哪算哪
- 程序员:先规划路线,再出发
程序设计的五个步骤
第1步:明确需求(Understand Requirements)
核心问题:
- 程序要解决什么问题?
- 输入是什么?输出是什么?
- 有哪些特殊要求?
方法:
-
列出输入和输出
题目:写一个猜数字游戏 输入: - 用户猜测的数字 输出: - "太大了"、"太小了"、"正确"的提示 - 猜测次数统计 -
明确功能要求
功能要求: 1. 生成1-100之间的随机数 2. 用户可以多次猜测 3. 每次猜测后给出提示 4. 猜中后显示猜测次数 5. 允许用户中途退出 -
确定边界条件
边界情况: - 用户输入的不是数字怎么办? - 用户输入的数字超出范围怎么办? - 用户一直猜不中怎么办?
给家长的小贴士:
- 让孩子把需求“说出来“或“写下来“
- 问孩子:“这个程序要做什么?输入是什么?输出是什么?”
- 这能培养孩子的“需求分析“能力
第2步:设计输入输出(Design Input/Output)
核心问题:
- 用户如何输入数据?
- 程序如何展示结果?
方法:
-
设计输入格式
# 猜数字游戏的输入设计 方案1:简单输入 请输入你的猜测:50 方案2:带提示的输入 猜数字游戏(1-100) 第1次猜测,请输入数字:50 (输入q退出) 选择方案2,更友好! -
设计输出格式
# 猜数字游戏的输出设计 方案1:简单输出 太大了 太小了 正确 方案2:详细输出 ===== 猜数字游戏 ===== 第1次猜测:50 提示:太大了! 你已经猜了1次 选择方案2,用户体验更好!
输入输出设计的原则:
- ✅ 提示信息清晰
- ✅ 输入格式简单
- ✅ 输出结果直观
- ✅ 提供退出选项
第3步:设计主要步骤(Design Main Steps)
核心问题:
- 程序的主要步骤是什么?
- 用什么控制结构?
方法:使用伪代码(Pseudocode)
什么是伪代码:
- 介于自然语言和编程语言之间的描述
- 不需要语法正确
- 重点是把逻辑说清楚
举例:猜数字游戏的伪代码
# 伪代码:猜数字游戏
1. 生成一个1-100的随机数
2. 初始化猜测次数为0
3. 循环:
3.1 提示用户输入猜测
3.2 如果用户输入q,退出循环
3.3 验证输入是否为有效数字
3.4 猜测次数加1
3.5 比较猜测和目标数字
如果猜中:显示恭喜,退出循环
如果太大:提示"太大"
如果太小:提示"太小"
4. 显示游戏结果
流程图表示:
开始
↓
生成随机数
↓
初始化次数
↓
┌─────────┐
│ 循环 │←──────┐
└─────────┘ │
↓ │
获取用户输入 │
↓ │
输入q? → 结束 │
↓ 否 │
验证输入 │
↓ │
次数+1 │
↓ │
比较大小 │
↓ │
猜中? → 是 → 结束 │
↓ 否 │
提示大小 ─────────┘
第4步:设计数据结构(Design Data Structures)
核心问题:
- 用什么变量存储数据?
- 用什么数据结构(列表、字典等)?
方法:
-
列出需要的变量
# 猜数字游戏需要的变量 secret_number # 目标数字(整数) guess_count # 猜测次数(整数) user_input # 用户输入(字符串) guess # 猜测的数字(整数) is_correct # 是否猜中(布尔值) -
确定数据结构
# 简单情况:用基本变量 secret_number = 50 guess_count = 0 # 复杂情况:用列表或字典 # 如果要记录所有猜测历史 guess_history = [50, 25, 37, 42] # 如果要记录多个玩家的成绩 player_scores = { "小明": 5, "小红": 7 }
数据结构选择原则:
- 数据量小 → 用基本变量
- 数据有顺序 → 用列表
- 数据需要查找 → 用字典
第5步:设计验证方法(Design Verification)
核心问题:
- 如何验证程序是否正确?
- 需要测试哪些情况?
方法:
-
设计测试用例
# 猜数字游戏的测试用例 测试用例1:正常情况 - 目标数字:50 - 猜测:30, 60, 40, 55, 45, 50 - 预期输出:太小、太大、太小、太大、太小、正确 测试用例2:边界情况 - 目标数字:1 - 猜测:0, 2, 1 - 预期输出:无效、太大、正确 测试用例3:错误输入 - 目标数字:50 - 猜测:abc, 50 - 预期输出:提示输入有效数字、正确 测试用例4:中途退出 - 目标数字:50 - 猜测:q - 预期输出:显示游戏结束和答案 -
验证方法
# 方法1:手工验证 print("目标数字是:50") # 调试输出 # 手动输入各种测试数据 # 方法2:自动测试 def test_guess_number(): # 模拟测试 assert compare_guess(50, 30) == "太小" assert compare_guess(50, 60) == "太大" assert compare_guess(50, 50) == "正确" print("所有测试通过!")
综合案例:完整的设计过程
题目:设计一个“成绩管理系统“
第1步:明确需求
功能需求:
1. 添加学生成绩
2. 查询学生成绩
3. 计算班级平均分
4. 找出最高分和最低分
5. 显示所有成绩
输入:
- 命令选择(1-5)
- 学生姓名
- 成绩分数
输出:
- 操作结果
- 成绩列表
- 统计信息
第2步:设计输入输出
# 输入设计
========== 成绩管理系统 ==========
1. 添加成绩
2. 查询成绩
3. 统计信息
4. 显示所有成绩
5. 退出
请选择操作(1-5):_
# 输出设计
✓ 成绩添加成功!
✓ 查询结果:小明的成绩是85分
=== 班级统计 ===
学生人数:30
平均分:82.5
最高分:98(小红)
最低分:45(小刚)
第3步:设计主要步骤(伪代码)
# 伪代码
main:
初始化成绩字典
循环:
显示菜单
获取用户选择
根据选择执行操作:
1 → add_score()
2 → query_score()
3 → show_statistics()
4 → show_all_scores()
5 → 退出程序
如果选择无效,提示错误
add_score:
输入学生姓名
输入成绩分数
验证成绩范围(0-100)
添加到字典
显示成功消息
query_score:
输入学生姓名
在字典中查找
如果找到,显示成绩
如果没找到,提示不存在
show_statistics:
如果字典为空,提示无数据
否则:
计算平均分
找最高分
找最低分
显示统计结果
第4步:设计数据结构
# 数据结构设计
# 主数据结构:用字典存储成绩
# key: 学生姓名(字符串)
# value: 成绩分数(整数)
scores = {
"小明": 85,
"小红": 92,
"小刚": 78
}
# 辅助变量
command = "" # 用户命令
student_name = "" # 学生姓名
score = 0 # 成绩分数
第5步:设计验证方法
# 测试用例
测试1:添加成绩
输入:小明,85
预期:添加成功,scores中有{"小明": 85}
测试2:查询成绩
输入:小明
预期:显示"小明的成绩是85分"
测试3:无效成绩
输入:小刚,150
预期:提示"成绩应该在0-100之间"
测试4:查询不存在的学生
输入:小华
预期:提示"找不到该学生"
测试5:统计信息
输入:scores = {"小明":85, "小红":92, "小刚":78}
预期:平均分=85,最高=92,最低=78
完整代码实现
def display_menu():
"""显示菜单"""
print("\n========== 成绩管理系统 ==========")
print("1. 添加成绩")
print("2. 查询成绩")
print("3. 统计信息")
print("4. 显示所有成绩")
print("5. 退出")
print("=" * 30)
def add_score(scores):
"""添加成绩"""
name = input("请输入学生姓名:")
score_str = input("请输入成绩(0-100):")
# 验证输入
if not score_str.isdigit():
print("错误:请输入有效的数字!")
return
score = int(score_str)
# 验证范围
if score < 0 or score > 100:
print("错误:成绩应该在0-100之间!")
return
# 添加成绩
scores[name] = score
print(f"✓ 成功添加{name}的成绩:{score}分")
def query_score(scores):
"""查询成绩"""
name = input("请输入要查询的学生姓名:")
if name in scores:
print(f"✓ {name}的成绩是{scores[name]}分")
else:
print(f"✗ 找不到学生:{name}")
def show_statistics(scores):
"""显示统计信息"""
if not scores:
print("✗ 还没有成绩数据!")
return
score_list = list(scores.values())
average = sum(score_list) / len(score_list)
highest = max(score_list)
lowest = min(score_list)
# 找出最高分和最低分的学生
highest_students = [name for name, score in scores.items() if score == highest]
lowest_students = [name for name, score in scores.items() if score == lowest]
print("\n=== 班级统计 ===")
print(f"学生人数:{len(scores)}")
print(f"平均分:{average:.2f}")
print(f"最高分:{highest}分({', '.join(highest_students)})")
print(f"最低分:{lowest}分({', '.join(lowest_students)})")
def show_all_scores(scores):
"""显示所有成绩"""
if not scores:
print("✗ 还没有成绩数据!")
return
print("\n=== 所有成绩 ===")
for name, score in scores.items():
print(f"{name}:{score}分")
def main():
"""主程序"""
scores = {} # 存储成绩的字典
while True:
display_menu()
command = input("请选择操作(1-5):")
if command == "1":
add_score(scores)
elif command == "2":
query_score(scores)
elif command == "3":
show_statistics(scores)
elif command == "4":
show_all_scores(scores)
elif command == "5":
print("感谢使用成绩管理系统!")
break
else:
print("✗ 无效的选择,请输入1-5之间的数字!")
if __name__ == "__main__":
main()
练习3:设计程序
按照上述五个步骤,设计一个“图书馆借阅系统“。
需求:
- 添加图书(书名、作者)
- 借阅图书(记录借阅人)
- 归还图书
- 查询图书状态
- 显示所有图书
请写出:
- 需求分析
- 输入输出设计
- 主要步骤(伪代码)
- 数据结构设计
- 测试用例
📝 查看设计参考
# 1. 需求分析
功能需求:
- 添加图书:输入书名和作者,添加到图书馆
- 借阅图书:输入书名和借阅人,记录借阅
- 归还图书:输入书名,清除借阅信息
- 查询图书:输入书名,显示图书状态(在馆/借出)
- 显示所有图书:列出所有图书及状态
# 2. 输入输出设计
========== 图书馆管理系统 ==========
1. 添加图书
2. 借阅图书
3. 归还图书
4. 查询图书
5. 显示所有图书
6. 退出
请选择操作(1-6):_
# 3. 主要步骤(伪代码)
main:
初始化图书字典
循环:
显示菜单
获取用户选择
根据选择执行操作
如果选择6,退出程序
add_book:
输入书名
输入作者
添加到字典
标记为"在馆"
borrow_book:
输入书名
输入借阅人
如果图书在馆:
标记为"借出"
记录借阅人
否则:
提示图书已借出
return_book:
输入书名
如果图书已借出:
标记为"在馆"
清除借阅人
否则:
提示图书在馆
query_book:
输入书名
如果图书存在:
显示书名、作者、状态
如果已借出,显示借阅人
否则:
提示图书不存在
# 4. 数据结构设计
books = {
"书名": {
"author": "作者名",
"borrower": "借阅人", # None表示在馆
"is_borrowed": False # False表示在馆
}
}
# 5. 测试用例
测试1:添加图书
输入:Python编程,小明
预期:成功添加,状态为"在馆"
测试2:借阅图书
输入:Python编程,小红
预期:成功借阅,借阅人为"小红"
测试3:重复借阅
输入:Python编程,小刚
预期:提示"图书已被小红借出"
测试4:归还图书
输入:Python编程
预期:成功归还,状态为"在馆"
测试5:查询不存在的图书
输入:Java编程
预期:提示"图书不存在"
17.4 综合实践:重写之前的程序
现在我们已经学习了程序设计的理论,让我们用这些知识来改进之前写过的程序!
案例1:改进“猜数字游戏“
回顾:你在第8章学过猜数字游戏
原始版本(可能的样子):
import random
n = random.randint(1, 100)
c = 0
while True:
g = input("请输入数字:")
if g == 'q':
break
g = int(g)
c = c + 1
if g > n:
print("太大了")
elif g < n:
print("太小")
else:
print("对了")
break
print(c)
问题分析:
- ❌ 变量命名不清晰(n, c, g)
- ❌ 没有输入验证
- ❌ 没有注释
- ❌ 用户提示不友好
- ❌ 输出格式简陋
改进版本:
import random
def guess_number_game():
"""猜数字游戏 - 猜一个1到100之间的随机数"""
print("=== 猜数字游戏 ===")
print("我已经想好了一个1到100之间的数字")
print("你能猜到它是多少吗?")
print("(输入q可以随时退出)\n")
# 生成随机数
secret_number = random.randint(1, 100)
guess_count = 0
guess_history = [] # 记录猜测历史
while True:
# 获取用户输入
user_input = input(f"第{guess_count + 1}次猜测,请输入数字:")
# 检查是否退出
if user_input.lower() == 'q':
print(f"\n游戏结束!正确答案是:{secret_number}")
return
# 验证输入
if not user_input.isdigit():
print("请输入一个有效的数字!\n")
continue
guess = int(user_input)
# 验证范围
if guess < 1 or guess > 100:
print("请输入1到100之间的数字!\n")
continue
# 记录猜测
guess_count += 1
guess_history.append(guess)
# 比较大小
if guess > secret_number:
print(f"{guess} 太大了!")
elif guess < secret_number:
print(f"{guess} 太小了!")
else:
print(f"\n🎉 恭喜你!{guess} 就是正确答案!")
print(f"你总共猜了 {guess_count} 次")
# 显示猜测历史
if guess_count > 1:
print(f"猜测历史:{guess_history}")
break
# 提供提示
print()
if __name__ == "__main__":
guess_number_game()
改进点:
- ✅ 清晰的函数名和变量名
- ✅ 完整的文档字符串
- ✅ 输入验证(数字、范围)
- ✅ 友好的用户界面
- ✅ 猜测历史记录
- ✅ 退出功能
- ✅ 格式化输出
案例2:改进“计算器程序“
原始版本(可能的样子):
n1 = int(input("第1个数:"))
n2 = int(input("第2个数:"))
op = input("运算符:")
if op == "+":
print(n1 + n2)
elif op == "-":
print(n1 - n2)
elif op == "*":
print(n1 * n2)
elif op == "/":
print(n1 / n2)
问题分析:
- ❌ 没有除零检查
- ❌ 没有输入验证
- ❌ 没有循环功能
- ❌ 输出简陋
改进版本:
def calculator():
"""简单计算器 - 支持加减乘除运算"""
print("=== 简单计算器 ===")
print("支持的运算:+ - * /")
print("输入q退出\n")
while True:
try:
# 获取第一个数字
num1_str = input("请输入第一个数字:")
if num1_str.lower() == 'q':
break
num1 = float(num1_str)
# 获取运算符
operator = input("请输入运算符(+ - * /):")
if operator not in ['+', '-', '*', '/']:
print("无效的运算符!请输入 + - * /\n")
continue
# 获取第二个数字
num2_str = input("请输入第二个数字:")
num2 = float(num2_str)
# 计算结果
result = None
if operator == '+':
result = num1 + num2
elif operator == '-':
result = num1 - num2
elif operator == '*':
result = num1 * num2
elif operator == '/':
# 除零检查
if num2 == 0:
print("错误:不能除以零!\n")
continue
result = num1 / num2
# 显示结果
print(f"结果:{num1} {operator} {num2} = {result}\n")
except ValueError:
print("错误:请输入有效的数字!\n")
if __name__ == "__main__":
calculator()
改进点:
- ✅ 支持小数计算(使用float)
- ✅ 除零检查
- ✅ 输入验证(try-except)
- ✅ 循环功能
- ✅ 格式化输出
- ✅ 退出功能
练习4:改进你自己的程序
从你之前写过的程序中选择一个(例如:
- 长方形计算器(第2章)
- 温度转换器(第4章)
- 水仙花数程序(第8章)
- 课表查询系统(第14章)
按照以下步骤进行改进:
-
评价原始程序
- 用五个维度评价
- 列出所有问题
-
设计改进方案
- 改进变量命名
- 添加输入验证
- 改进用户界面
- 添加错误处理
-
重写程序
- 应用本章学到的知识
- 使用函数封装
- 添加注释
-
测试程序
- 设计测试用例
- 验证各种情况
17.5 常见错误和调试
常见的程序设计错误
错误1:过早优化(Premature Optimization)
表现:
- 还没让程序运行起来,就开始考虑“怎么让它更快“
- 为了“效率“牺牲了可读性
例子:
# ❌ 过早优化的例子
# 为了节省一行代码,牺牲了可读性
result = (lambda x: x * x)(int(input("输入数字:")))
print(result)
# ✅ 先让它能运行,再考虑优化
user_input = input("输入数字:")
number = int(user_input)
result = number * number
print(result)
建议:
- “Make it work, make it right, make it fast”
- 先让它能运行,再让它运行正确,最后才考虑让它运行得快
- 对于初学者,可读性 > 效率
错误2:过度设计(Over-Engineering)
表现:
- 为简单的问题设计复杂的解决方案
- “用大炮打蚊子”
例子:
# ❌ 过度设计的例子
# 一个简单的加法程序,却用了复杂的架构
class NumberAdder:
"""数字加加器类"""
def __init__(self):
self.numbers = []
def add_number(self, number):
self.numbers.append(number)
def calculate_sum(self):
return sum(self.numbers)
def main():
adder = NumberAdder()
adder.add_number(10)
adder.add_number(20)
result = adder.calculate_sum()
print(result)
main()
# ✅ 简单直接的设计
num1 = 10
num2 = 20
result = num1 + num2
print(result)
建议:
- 简单问题用简单方案
- 只在需要时才引入复杂结构
- KISS原则:Keep It Simple, Stupid
错误3:重复代码(Code Duplication)
表现:
- 相同的代码在程序中出现多次
- 不知道如何使用函数
例子:
# ❌ 重复代码
area1 = length1 * width1
area2 = length2 * width2
area3 = length3 * width3
area4 = length4 * width4
# ✅ 使用函数
def calculate_area(length, width):
return length * width
area1 = calculate_area(length1, width1)
area2 = calculate_area(length2, width2)
area3 = calculate_area(length3, width3)
area4 = calculate_area(length4, width4)
建议:
- 遵循DRY原则:Don’t Repeat Yourself
- 相同的代码出现3次,就该考虑用函数
错误4:魔法数字(Magic Numbers)
表现:
- 代码中出现没有解释的数字
- 不知道这些数字是什么意思
例子:
# ❌ 魔法数字
area = 3.14159 * radius * radius
if score >= 60:
print("及格")
# ✅ 使用命名常量
PI = 3.14159
PASSING_SCORE = 60
area = PI * radius * radius
if score >= PASSING_SCORE:
print("及格")
建议:
- 给重要的数字起个名字
- 使用全大写字母命名常量
- 常量定义在程序开头
错误5:忽略错误处理(No Error Handling)
表现:
- 假设用户总是输入正确
- 程序遇到错误就崩溃
例子:
# ❌ 没有错误处理
age = int(input("请输入年龄:"))
print(f"你明年{age + 1}岁")
# ✅ 添加错误处理
try:
age = int(input("请输入年龄:"))
if age < 0 or age > 150:
print("年龄应该在0-150之间")
else:
print(f"你明年{age + 1}岁")
except ValueError:
print("请输入有效的数字!")
建议:
- 永远不要相信用户输入
- 使用try-except捕获异常
- 验证输入的有效性
调试技巧
技巧1:使用print调试
方法:在关键位置打印变量值
def calculate_average(scores):
print(f"[DEBUG] scores = {scores}") # 调试输出
if not scores:
print("[DEBUG] Empty list!")
return 0
total = sum(scores)
print(f"[DEBUG] total = {total}") # 调试输出
count = len(scores)
print(f"[DEBUG] count = {count}") # 调试输出
average = total / count
print(f"[DEBUG] average = {average}") # 调试输出
return average
优点:
- 简单直接
- 不需要额外工具
- 适合快速定位问题
缺点:
- 需要手动添加和删除
- 调试完成后要清理代码
给家长的小贴士:
- 教导孩子:“不知道哪里出错,就打印出来看看”
- 建议使用统一的格式,如
[DEBUG] - 调试完成后记得删除或注释掉
技巧2:逐步测试
方法:不要等程序全部写完才测试,每写一段就测试
# 第1步:测试基本功能
def calculate_area(length, width):
return length * width
# 立即测试
print(calculate_area(10, 20)) # 应该输出200
# 第2步:添加输入验证
def calculate_area(length, width):
if length <= 0 or width <= 0:
return 0
return length * width
# 再次测试
print(calculate_area(10, 20)) # 200
print(calculate_area(-10, 20)) # 0
# 第3步:添加文档和优化
def calculate_area(length, width):
"""计算长方形面积
Args:
length: 长度
width: 宽度
Returns:
面积,如果输入无效则返回0
"""
if length <= 0 or width <= 0:
return 0
return length * width
优点:
- 问题容易定位
- 每一步都是正确的
- 积累成就感
给家长的小贴士:
- 鼓励孩子“写一点,测一点“
- 不要等到全部写完才运行
- 这能培养孩子的“增量开发“习惯
技巧3:使用断言(Assertion)
方法:用assert语句检查假设
def calculate_average(scores):
"""计算平均分"""
assert isinstance(scores, list), "scores必须是列表"
assert len(scores) > 0, "scores不能为空"
total = sum(scores)
assert total >= 0, "总分不能为负数"
average = total / len(scores)
assert 0 <= average <= 100, f"平均分{average}超出范围"
return average
# 测试
print(calculate_average([80, 90, 85])) # 正常
# print(calculate_average([])) # 触发断言错误
优点:
- 能快速发现逻辑错误
- 文档化代码的假设
- 调试后可以选择禁用
使用场景:
- 检查函数的输入
- 验证计算结果
- 确保不变式成立
技巧4:简化问题
方法:遇到复杂问题时,先用简单版本复现
# 复杂版本:计算n个班级的平均分
def calculate_all_classes_average(students):
result = {}
for class_name, class_students in students.items():
# 复杂的计算...
pass
# 简化版本:先计算一个班级
def calculate_one_class_average(scores):
return sum(scores) / len(scores)
# 测试简化版本
print(calculate_one_class_average([80, 90, 85])) # 确保正确
# 再逐步扩展到复杂版本
优点:
- 降低问题复杂度
- 容易找到问题所在
- 逐步构建解决方案
给家长的小贴士:
- 告诉孩子:“太复杂了就先简化”
- 从最简单的情况开始
- 这能培养孩子的“问题分解“能力
17.6 本章小结
核心知识点回顾
1. 程序评价的五个维度
| 维度 | 评价标准 | 重要性 |
|---|---|---|
| 正确性 | 能否正确解决问题 | ⭐⭐⭐⭐⭐ |
| 可读性 | 是否容易理解 | ⭐⭐⭐⭐ |
| 可维护性 | 是否容易修改 | ⭐⭐⭐⭐ |
| 健壮性 | 是否容易出错 | ⭐⭐⭐⭐ |
| 效率 | 是否运行快速 | ⭐⭐⭐ |
2. 变量设计的三个原则
- 职责明确:一个变量只承担一个职责
- 命名规范:变量名要能“自解释“
- 作用域最小化:变量的作用范围越小越好
3. 程序设计的五个步骤
第1步:明确需求(做什么)
↓
第2步:设计输入输出(怎么交互)
↓
第3步:设计主要步骤(怎么做)
↓
第4步:设计数据结构(用什么数据)
↓
第5步:设计验证方法(怎么验证)
4. 常见错误
- ❌ 过早优化
- ❌ 过度设计
- ❌ 重复代码
- ❌ 魔法数字
- ❌ 忽略错误处理
5. 调试技巧
- ✅ 使用print调试
- ✅ 逐步测试
- ✅ 使用断言
- ✅ 简化问题
能力检查表
完成本章学习后,请检查你是否具备以下能力:
- 能用五个维度评价一个程序的好坏
- 能设计职责明确、命名规范的变量
- 能按照五个步骤设计程序
- 能使用伪代码和流程图设计算法
- 能改进自己之前写的程序
- 能识别和避免常见的程序设计错误
- 能使用调试技巧定位问题
给家长的小贴士:如何培养孩子的程序设计能力
1. 从小程序开始
不要:一开始就要求孩子写出“完美“的程序
应该:
- 先让程序能运行
- 再逐步改进
- 最后追求完美
比喻:学写作文
- 小学1年级:写通顺句子
- 小学3年级:写完整段落
- 小学6年级:写完整文章
- 不能要求1年级学生写出6年级水平的作文
2. 培养评价能力
活动建议:
- 让孩子“代码审查“:找出家长写的程序的问题
- 对比两个程序:哪个更好?为什么?
- 重构练习:改进之前写的程序
目的:
- 培养“批判性思维“
- 学会识别“好代码“和“坏代码“
- 建立“质量意识“
3. 强调设计过程
不要:看到题目就让孩子直接写代码
应该:
- 先讨论:这个程序要做什么?
- 再设计:用什么数据结构?什么算法?
- 最后实现:编写代码
- 测试验证:是否正确?
比喻:
- 建房子:先设计图纸,再施工
- 写作文:先列提纲,再写作
- 编程也是一样:先设计,再编程
4. 鼓励持续改进
活动建议:
- 定期回顾:这周写的程序,下周再看,能不能改进?
- 版本对比:版本1、版本2、版本3,哪个最好?
- 最佳实践:总结好的做法,形成“编程规范“
目的:
- 培养“精益求精“的态度
- 学会从“能运行“到“写得好“
- 建立“持续改进“的习惯
17.7 挑战练习
挑战1:代码审查 ⭐⭐
审查以下程序,找出所有问题并改进:
a = input("名字")
b = int(input("年龄"))
c = int(input("成绩"))
if c >= 60:
print("及格")
else:
print("不及格")
print(c / b)
要求:
- 用五个维度评价
- 指出所有问题
- 重写程序
- 说明改进点
📝 查看参考答案
评价结果:
| 维度 | 评分 | 问题 |
|---|---|---|
| 正确性 | ⭐⭐⭐ | 基本正确,但除法可能有问题 |
| 可读性 | ⭐ | 变量名不清晰,无注释 |
| 可维护性 | ⭐⭐ | 无函数封装 |
| 健壮性 | ⭐ | 无输入验证 |
| 效率 | ⭐⭐⭐⭐ | 效率可以接受 |
问题列表:
- 变量名a, b, c不清晰
- 没有提示信息
- 没有输入验证
- 成绩除以年龄没有意义(可能是bug)
- 没有注释
- 没有函数封装
改进版本:
def print_student_status():
"""打印学生状态"""
# 获取学生信息
name = input("请输入学生姓名:")
age = input("请输入学生年龄:")
score = input("请输入学生成绩:")
# 验证输入
if not age.isdigit() or not score.isdigit():
print("错误:年龄和成绩必须是数字!")
return
age = int(age)
score = int(score)
# 验证范围
if age < 0 or age > 150:
print("错误:年龄应该在0-150之间!")
return
if score < 0 or score > 100:
print("错误:成绩应该在0-100之间!")
return
# 判断是否及格
if score >= 60:
status = "及格"
else:
status = "不及格"
# 输出结果
print(f"\n=== 学生信息 ===")
print(f"姓名:{name}")
print(f"年龄:{age}岁")
print(f"成绩:{score}分")
print(f"状态:{status}")
if __name__ == "__main__":
print_student_status()
改进点:
- ✅ 清晰的变量命名
- ✅ 完整的输入提示
- ✅ 输入验证(数字、范围)
- ✅ 格式化输出
- ✅ 函数封装
- ✅ 注释说明
挑战2:重构程序 ⭐⭐⭐
重构以下程序,应用本章学到的知识:
l = 10
w = 20
h = 5
s1 = l * w
s2 = l * h
s3 = w * h
print(s1, s2, s3)
print(s1 + s2 + s3)
要求:
- 给变量起好名字
- 添加注释
- 封装成函数
- 添加输入验证
- 改进输出格式
📝 查看参考答案
def calculate_surface_area(length, width, height):
"""计算长方体的表面积
Args:
length: 长度
width: 宽度
height: 高度
Returns:
表面积
"""
# 计算三个面的面积
area1 = length * width # 顶面和底面
area2 = length * height # 前面和后面
area3 = width * height # 左面和右面
# 表面积 = 2 × (三个面的面积之和)
surface_area = 2 * (area1 + area2 + area3)
return surface_area
def get_positive_number(prompt):
"""获取一个正数
Args:
prompt: 输入提示
Returns:
用户输入的正数
"""
while True:
user_input = input(prompt)
if not user_input.isdigit():
print("请输入一个有效的数字!")
continue
number = float(user_input)
if number <= 0:
print("请输入一个大于0的数字!")
continue
return number
def main():
"""主程序"""
print("=== 长方体表面积计算器 ===")
# 获取长宽高
length = get_positive_number("请输入长度:")
width = get_positive_number("请输入宽度:")
height = get_positive_number("请输入高度:")
# 计算表面积
surface_area = calculate_surface_area(length, width, height)
# 显示结果
print(f"\n=== 计算结果 ===")
print(f"长方体尺寸:{length} × {width} × {height}")
print(f"表面积:{surface_area:.2f}")
if __name__ == "__main__":
main()
挑战3:设计程序 ⭐⭐⭐⭐
按照程序设计的五个步骤,设计一个“密码强度检查器“:
功能需求:
- 输入密码
- 检查密码强度(弱/中/强)
- 显示改进建议
- 直到输入强密码为止
要求:
- 完成五个步骤的设计
- 实现完整程序
- 编写测试用例
- 提供改进建议
强度判断标准:
- 弱:长度<8或只有数字或只有字母
- 中:长度>=8且包含数字和字母
- 强:长度>=12且包含数字、字母和特殊字符
📝 查看参考答案
第1步:明确需求
功能需求:
1. 输入密码
2. 检查密码强度
3. 显示强度等级
4. 提供改进建议
5. 循环直到输入强密码
输入:
- 密码(字符串)
输出:
- 强度等级(弱/中/强)
- 改进建议
边界情况:
- 空字符串
- 只有数字
- 只有字母
- 包含特殊字符
第2步:设计输入输出
=== 密码强度检查器 ===
请输入密码:******
强度:弱
建议:
- 密码长度至少8位
- 包含数字和字母
- 包含特殊字符
请重新输入密码:******
强度:强
✓ 密码符合要求!
第3步:设计主要步骤(伪代码)
main:
循环:
输入密码
检查强度
显示强度和建议
如果是强密码:
退出循环
check_password_strength:
如果长度<8:
返回"弱"
如果只有数字或只有字母:
返回"弱"
如果长度>=8且包含数字和字母:
返回"中"
如果长度>=12且包含数字、字母和特殊字符:
返回"强"
get_suggestions:
根据密码的问题提供建议
- 如果太短,建议增加长度
- 如果只有数字,建议添加字母
- 如果只有字母,建议添加数字
- 如果没有特殊字符,建议添加特殊字符
第4步:设计数据结构
password = "" # 密码(字符串)
length = 0 # 长度(整数)
has_digit = False # 包含数字(布尔)
has_letter = False # 包含字母(布尔)
has_special = False # 包含特殊字符(布尔)
strength = "" # 强度(字符串)
suggestions = [] # 建议列表
第5步:设计验证方法
测试用例1:弱密码
输入:123
预期:弱(太短)
测试用例2:弱密码
输入:abcdefg
预期:弱(太短且只有字母)
测试用例3:弱密码
输入:12345678
预期:弱(只有数字)
测试用例4:中等密码
输入:abc12345
预期:中
测试用例5:强密码
输入:abc123!@#XYZ
预期:强
完整实现:
def check_password_strength(password):
"""检查密码强度
Args:
password: 要检查的密码
Returns:
(strength, suggestions): 强度等级和建议列表
"""
suggestions = []
# 检查长度
if len(password) < 8:
suggestions.append("密码长度至少8位")
return "弱", suggestions
# 检查是否包含数字
has_digit = any(char.isdigit() for char in password)
# 检查是否包含字母
has_letter = any(char.isalpha() for char in password)
# 检查是否包含特殊字符
has_special = any(not char.isalnum() for char in password)
# 判断强度
if not has_digit or not has_letter:
suggestions.append("密码应同时包含数字和字母")
if not has_digit:
suggestions.append("建议添加数字")
if not has_letter:
suggestions.append("建议添加字母")
return "弱", suggestions
if len(password) >= 12 and has_special:
suggestions.append("密码很安全!")
return "强", suggestions
if len(password) >= 8 and has_digit and has_letter:
suggestions.append("建议增加到12位以上")
suggestions.append("建议添加特殊字符(如!@#)")
return "中", suggestions
return "弱", ["密码不符合要求"]
def password_strength_checker():
"""密码强度检查器主程序"""
print("=== 密码强度检查器 ===")
print("密码要求:")
print("- 长度至少8位")
print("- 包含数字和字母")
print("- 强密码要求12位以上且包含特殊字符")
print()
while True:
password = input("请输入密码(输入q退出):")
if password.lower() == 'q':
print("已退出")
break
if not password:
print("密码不能为空!\n")
continue
# 检查强度
strength, suggestions = check_password_strength(password)
# 显示结果
print(f"\n强度:{strength}")
if strength == "强":
print("✓ " + "\n✓ ".join(suggestions))
print()
break
else:
print("建议:")
for suggestion in suggestions:
print(f"- {suggestion}")
print()
def test_password_checker():
"""测试密码强度检查器"""
test_cases = [
("123", "弱"),
("abcdefg", "弱"),
("12345678", "弱"),
("abc12345", "中"),
("abc123!@#XYZ", "强"),
]
print("=== 测试密码强度检查器 ===")
for password, expected in test_cases:
strength, _ = check_password_strength(password)
status = "✓" if strength == expected else "✗"
print(f"{status} '{password}' -> {strength} (期望: {expected})")
if __name__ == "__main__":
# 运行测试
test_password_checker()
print()
# 运行主程序
password_strength_checker()
挑战4:改进你自己的程序 ⭐⭐⭐⭐⭐
选择你之前写过的一个程序(例如:课表查询系统、猜数字游戏、水仙花数等),按照以下步骤进行改进:
-
评价原始程序
- 用五个维度评价
- 列出所有问题
-
设计改进方案
- 改进变量命名
- 添加输入验证
- 改进用户界面
- 添加错误处理
- 使用函数封装
-
重写程序
- 应用本章学到的知识
- 添加注释
- 改进结构
-
对比版本
- 列出改进前后的对比
- 说明改进理由
- 编写测试
- 设计测试用例
- 验证各种情况
第18章 计算机体系结构
本章导读
在前面的章节中,我们学习了Python编程的各个方面:从变量和函数,到图形界面和数据处理。你可能会有疑问:
- 计算机是如何执行这些Python代码的?
- 变量存储在哪里?
- 当我们输入数据时,计算机内部发生了什么?
这一章,我们将打开计算机的“外壳“,了解它内部是如何工作的。我们会发现,之前学过的很多知识,都与计算机的内部结构密切相关!
什么是计算机体系结构?
计算机体系结构是指计算机的组成部件以及这些部件如何协同工作。
想象一下,你的身体就是一个“计算机“:
- 大脑 = CPU(中央处理器),负责思考和做决定
- 眼睛/耳朵 = 输入设备,接收外界信息
- 嘴巴/手势 = 输出设备,向外界表达信息
- 记忆 = 内存和硬盘,存储信息
- 神经 = 总线,在各个部件之间传递信息
👨🏫 给家长的Tips
用人体做类比非常适合孩子理解:
- 问孩子:“如果我想踢足球,大脑会给腿发送什么指令?”(控制信号)
- “你记得的事情,哪些是短期的?哪些是长期的?”(内存 vs 硬盘)
- “如果你不复习,会忘记学过的内容吗?”(内存的易失性)
计算机的五大组成部分
计算机由五个主要部分组成:
flowchart TB
subgraph 计算机系统
InputDevice[输入设备<br/>Input Device]
CPU[CPU<br/>中央处理器]
Memory[内存<br/>Memory]
OutputDevice[输出设备<br/>Output Device]
Storage[硬盘<br/>Storage]
InputDevice -->|数据| CPU
CPU <-->|数据/指令| Memory
CPU -->|结果| OutputDevice
CPU <-->|数据| Storage
end
style InputDevice fill:#e1f5ff
style CPU fill:#ffe1e1
style Memory fill:#e1ffe1
style OutputDevice fill:#fff5e1
style Storage fill:#f5e1ff
让我们逐一了解每个部分,并联系我们已经学过的Python知识!
1. 输入设备(Input Devices)
输入设备是让计算机接收信息的设备。
常见的输入设备
- 键盘:输入文字和命令
- 鼠标:点击和移动
- 触摸屏:手指操作
- 麦克风:输入声音
- 摄像头:输入图像
与我们学过的知识联系
还记得我们学过的输入程序吗?
第2章:输入与输出
name = input("请输入你的名字:")
print(f"你好,{name}!")
当我们运行这个程序时:
- 键盘(输入设备)接收你敲击的名字
- 通过总线传给CPU
- CPU处理后将结果传给显卡
- 显示器(输出设备)显示“你好,xxx!“
第14章:命令行程序
import sys
name = sys.argv[1] # 从命令行接收参数
print(f"你好,{name}!")
这里,命令行参数也是一种输入,通过键盘输入命令传递给程序。
第16章:图形界面程序
import tkinter as tk
def on_click():
name = entry.get() # 从输入框获取文本
label.config(text=f"你好,{name}!")
root = tk.Tk()
entry = tk.Entry(root) # 输入框
entry.pack()
button = tk.Button(root, text="提交", command=on_click)
button.pack()
label = tk.Label(root, text="")
label.pack()
root.mainloop()
在这个GUI程序中:
- 输入框(Entry组件)是屏幕上的“虚拟输入设备“
- 你在输入框输入字符,这些字符被输入设备接收
- 点击按钮后,程序获取输入框的内容
👨🏫 给家长的Tips
引导孩子思考:
- “无论是命令行还是图形界面,都需要输入设备。为什么图形界面更友好?”
- “触摸屏既是输入设备又是输出设备,你知道吗?”
- “想象一下,如果没有输入设备,我们能和计算机交流吗?”
2. 输出设备(Output Devices)
输出设备是计算机向外界展示信息的设备。
常见的输出设备
- 显示器:显示图像和文字
- 打印机:打印纸质文档
- 扬声器:播放声音
- 投影仪:投射大屏幕
与我们学过的知识联系
第2章:print输出
print("Hello, World!")
当我们执行print()时:
- CPU计算要显示的内容
- 通过总线将数据传给显卡
- 显卡将数据转换为显示信号
- 显示器接收信号,显示文字
第15章:报表程序
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [10, 20, 15, 25, 30]
plt.plot(x, y)
plt.show() # 显示图表
这里的图表显示也是输出:
- matplotlib库生成图表数据
- 通过显示器展示给你看
第16章:图形界面
label.config(text="你好!")
在GUI程序中:
- 组件(Label、Button等)显示在显示器上
- 它们的变化(文字、颜色等)都是输出
练习1:分类游戏
将下列设备分类为输入设备、输出设备,或两者都是:
- 键盘
- 鼠标
- 显示器
- 打印机
- 扫描仪
- 摄像头
- 音箱
- 触摸屏
👉 点击查看答案
答案:
- 输入设备:键盘、鼠标、扫描仪、摄像头
- 输出设备:显示器、打印机、音箱
- 两者都是:触摸屏(既是输入又是输出)
3. 内存(Memory/RAM)
内存(Random Access Memory,随机存取存储器)是计算机的短期记忆。
内存的特点
- 速度快:CPU读写内存非常快
- 容量有限:通常8GB、16GB、32GB等
- 易失性:断电后数据会丢失
与我们学过的知识联系
还记得我们学过的变量吗?
第3-5章:变量(字符串、数字、布尔值)
name = "小明" # 字符串变量
age = 10 # 数字变量
is_student = True # 布尔变量
当我们创建这些变量时:
- 变量存储在内存中
- 每个变量都有一个内存地址
- Python自动管理内存,我们不需要手动分配
👨🏫 给家长的Tips
用“书包“类比内存:
- 书包空间有限(内存容量有限)
- 随时可以拿书出来用(读写快)
- 回家后书包里的书要拿走(易失性,断电数据丢失)
- 家里的书柜就像硬盘(容量大,永久存储)
练习2:计算内存占用
不同类型的变量占用内存不同(大致数值):
| 变量类型 | 示例 | 占用内存(估算) |
|---|---|---|
| 整数(int) | age = 10 | 约28字节 |
| 浮点数(float) | price = 3.14 | 约24字节 |
| 字符串(str) | name = “Python” | 约50字节 |
| 布尔值(bool) | flag = True | 约28字节 |
| 列表(list) | [1, 2, 3] | 约56字节 + 元素大小 |
问题:如果你的计算机有16GB内存,大约可以存储多少个整数变量?
👉 点击查看答案
解答:
- 16GB = 16 × 1024MB = 16,384MB
- 16,384MB = 16,777,216KB
- 16,777,216KB = 17,179,869,184字节
- 每个整数约28字节
- 可存储的整数数量 ≈ 17,179,869,184 ÷ 28 ≈ 613,566,756个
也就是说,16GB内存可以存储约6亿个整数变量!
思考:虽然可以存储这么多变量,但实际编程时我们不会创建这么多。为什么?
答案:因为程序还有其他数据需要存储,而且变量太多会让程序难以管理。
第10-11章:列表和字典
# 列表
scores = [90, 85, 78, 92, 88]
# 字典
student = {"name": "小明", "age": 10, "grade": "五年级"}
列表和字典也存储在内存中:
- 它们占用更多内存(因为要存储多个元素)
- 当列表很大时(如100万个元素),会占用大量内存
练习3:大列表的内存占用
如果一个列表存储100万个学生的成绩,大约占用多少内存?
👉 点击查看答案
解答:
- 每个整数(成绩)约28字节
- 列表本身还有一些额外开销
- 总内存 ≈ 1,000,000 × 28字节 ≈ 28,000,000字节 ≈ 28MB
100万个成绩占用约28MB内存,这对于16GB的计算机来说只是很小的一部分!
4. 硬盘(Storage/Hard Drive)
硬盘是计算机的长期记忆。
硬盘的特点
- 容量大:通常500GB、1TB、2TB等
- 速度慢:比内存慢得多
- 非易失性:断电后数据仍然保存
与我们学过的知识联系
还记得我们学过的文件操作吗?
第13章:JSON文件存储
import json
# 保存课表到文件
schedule = {
"周一": ["语文", "数学", "英语"],
"周二": ["数学", "语文", "体育"]
}
with open("schedule.json", "w", encoding="utf-8") as f:
json.dump(schedule, f)
# 从文件读取课表
with open("schedule.json", "r", encoding="utf-8") as f:
loaded_schedule = json.load(f)
在这个过程中:
schedule字典存储在内存中json.dump()将数据写入硬盘(schedule.json文件)- 关闭程序后,数据仍然保存在硬盘上
- 下次运行时,用
json.load()从硬盘读取数据
👨🏫 给家长的Tips
用“笔记本“类比硬盘:
- 笔记本可以记很多东西(容量大)
- 写字速度比脑子想得慢(速度慢)
- 合上本子,内容还在(非易失性)
- 想复习时,打开本子就能看到(读取数据)
内存 vs 硬盘对比
| 特性 | 内存(RAM) | 硬盘(Storage) |
|---|---|---|
| 速度 | 非常快 | 较慢 |
| 容量 | 较小(8-32GB) | 很大(500GB-2TB) |
| 价格 | 较贵 | 较便宜 |
| 断电后 | 数据丢失 | 数据保留 |
| 用途 | 存储正在运行的程序和数据 | 永久存储文件 |
为什么需要两者?
想象一下,如果只有硬盘,没有内存:
- 每次操作都要读写硬盘,速度会非常慢
- 计算机运行会变得很卡
如果只有内存,没有硬盘:
- 关机后所有数据都会丢失
- 无法保存照片、文档等文件
练习4:估算硬盘容量
如果一张照片占3MB空间,1TB的硬盘可以存储多少张照片?
👉 点击查看答案
解答:
- 1TB = 1,024GB = 1,048,576MB
- 可存储照片数 = 1,048,576MB ÷ 3MB ≈ 349,525张
1TB硬盘可以存储约35万张照片!
5. CPU(中央处理器)
CPU(Central Processing Unit,中央处理器)是计算机的大脑,负责执行所有计算和控制操作。
CPU的特点
- 速度快:以GHz为单位(如3.2GHz,表示每秒执行32亿个周期)
- 智能:能执行复杂的计算和逻辑判断
- 控制中心:指挥其他所有部件协同工作
与我们学过的知识联系
第4章:数学运算
result = 5 + 3 # 加法
result = 10 * 2 # 乘法
result = 20 / 4 # 除法
当我们执行这些运算时:
- CPU的**算术逻辑单元(ALU)**执行计算
- 每次运算只需要几个CPU周期(几纳秒)
练习5:计算CPU运算能力
如果你的CPU主频是3.2GHz,它1秒内可以执行多少次加法运算?
👉 点击查看答案
解答:
- 3.2GHz = 3,200,000,000 Hz(每秒32亿个周期)
- 假设每次加法需要1个周期(简化计算)
- 1秒可以执行约32亿次加法运算!
人类1秒可能只能做1-2次加法,而CPU可以做32亿次!这就是为什么计算机这么快!
第6-8章:程序控制(顺序、条件、循环)
# 顺序执行
a = 5
b = 10
c = a + b
# 条件判断
if score >= 60:
print("及格")
else:
print("不及格")
# 循环
for i in range(100):
print(i)
CPU如何执行这些程序?
- 取指令:从内存中读取程序指令
- 译码:理解指令要做什么
- 执行:执行指令(计算、判断、跳转等)
- 写回:将结果写回内存
这个过程每秒重复几十亿次!
👨🏫 给家长的Tips
用“厨师“类比CPU:
- 厨师根据菜谱(程序)做菜
- 按照菜谱的步骤(顺序执行)
- 根据情况调整(条件判断)
- 重复切菜动作(循环)
- 厨师的速度越快,做菜越快(CPU主频)
多核CPU
现代CPU通常有多个“核心“(core),如4核、6核、8核。
- 单核:一次只能做一件事
- 多核:可以同时做多件事(并行处理)
# 模拟多核处理(实际需要使用多进程/多线程库)
# 这个例子只是概念演示
def task1():
for i in range(1000):
result = i * i
def task2():
for j in range(1000):
result = j + j
# 单核:先执行task1,再执行task2
# 多核:task1和task2可以同时执行
练习6:多核的优势
如果CPU有4个核心,处理4个任务(每个任务需要1秒):
- 单核CPU需要多少秒?
- 4核CPU需要多少秒?
👉 点击查看答案
解答:
- 单核CPU:4秒(因为只能一个接一个执行)
- 4核CPU:1秒(因为可以同时执行4个任务)
这就是为什么多核CPU更快!
计算机如何执行Python程序?
现在我们了解了计算机的各个部件,让我们看看它们如何协同工作来执行一个Python程序。
示例:计算平均分
# 程序:计算三个成绩的平均分
score1 = 90
score2 = 85
score3 = 78
average = (score1 + score2 + score3) / 3
print(f"平均分是:{average}")
执行过程:
flowchart TD
subgraph 硬盘
A[Python程序文件]
end
subgraph 内存
B[程序载入内存]
C1[score1 = 90]
C2[score2 = 85]
C3[score3 = 78]
C4[average = 84.333...]
end
subgraph CPU
D1[第1行: 分配内存存储90]
D2[第2行: 分配内存存储85]
D3[第3行: 分配内存存储78]
D4[第4行: 读取score1, score2, score3<br/>执行加法和除法运算<br/>存储结果到average]
D5[第5行: 读取average<br/>传数据给显卡]
end
subgraph 输出设备
E[显卡/显示器]
end
A -->|1. 从硬盘读取程序到内存| B
B -->|2. CPU逐条读取并执行指令| D1
D1 -->|在内存中分配| C1
D1 --> D2
D2 -->|在内存中分配| C2
D2 --> D3
D3 -->|在内存中分配| C3
D3 --> D4
D4 -->|从内存读取| C1
D4 -->|从内存读取| C2
D4 -->|从内存读取| C3
D4 -->|将结果存入| C4
D4 --> D5
D5 -->|从内存读取| C4
D5 -->|通过总线传数据| E
E -->|显示文字| F["显示: 平均分是:84.333..."]
style 硬盘 fill:#e1f5ff
style 内存 fill:#e1ffe1
style CPU fill:#ffe1e1
style 输出设备 fill:#fff5e1
👨🏫 给家长的Tips
这个流程图非常重要!
- 让孩子理解:程序不是“一次性“执行的,而是“一步一步“执行的
- 每一步都需要CPU、内存、输入/输出设备的协同工作
- 可以用“做菜流程“类比:买菜→洗菜→切菜→炒菜→装盘
综合练习:设计你的计算机
现在你已经了解了计算机的各个部件,让我们设计一台计算机!
练习7:计算机配置选择
假设你要买一台计算机用于学习Python,请选择合适的配置:
| 部件 | 选项A | 选项B | 选项C | 你的选择 | 原因 |
|---|---|---|---|---|---|
| CPU | 双核2.0GHz | 四核3.0GHz | 八核4.0GHz | ||
| 内存 | 8GB | 16GB | 32GB | ||
| 硬盘 | 256GB SSD | 512GB SSD | 1TB SSD | ||
| 输入设备 | 标准键盘 | 机械键盘 | 游戏键盘 | ||
| 输出设备 | 普通显示器 | 高清显示器 | 4K显示器 |
👉 点击查看参考答案
参考答案:
| 部件 | 推荐选择 | 原因 |
|---|---|---|
| CPU | 四核3.0GHz | 学习Python足够,性价比高 |
| 内存 | 16GB | 可以运行多个程序,不会卡顿 |
| 硬盘 | 512GB SSD | 存储课程和作业足够,SSD速度快 |
| 输入设备 | 机械键盘 | 手感好,适合长时间编程 |
| 输出设备 | 高清显示器 | 清晰舒适,保护眼睛 |
注意:这只是学习Python的配置。如果要玩大型游戏或做视频剪辑,需要更高的配置。
练习8:连接知识点
让我们把之前学过的Python知识和计算机硬件联系起来:
- 变量(第3-5章)存储在_____
- 文件(第13章)存储在_____
- **print()**输出到_____(设备)
- **input()**从_____(设备)接收
- 运算(第4章)由_____执行
- 条件判断(第7章)由_____的_____单元执行
- 循环(第8章)由_____控制重复执行
👉 点击查看答案
答案:
- 内存
- 硬盘
- 显示器(输出设备)
- 键盘(输入设备)
- CPU
- CPU的算术逻辑单元(ALU)
- CPU
练习9:创意项目
设计一个Python程序,展示你对计算机硬件的理解!
项目想法:
- 计算机硬件测验:用GUI设计一个测验程序,问用户关于计算机硬件的问题
- 硬件信息显示:用Python读取并显示你计算机的硬件信息(CPU型号、内存大小等)
- 资源监控器:编写一个程序,实时显示CPU和内存使用情况
示例框架:
import tkinter as tk
import psutil # 需要安装:pip install psutil
def show_info():
cpu_percent = psutil.cpu_percent()
memory = psutil.virtual_memory()
mem_percent = memory.percent
info_text = f"""
计算机硬件信息:
─────────────────
CPU使用率:{cpu_percent}%
内存使用率:{mem_percent}%
内存总量:{memory.total / (1024**3):.1f} GB
已用内存:{memory.used / (1024**3):.1f} GB
"""
label.config(text=info_text)
root = tk.Tk()
root.title("计算机硬件信息")
button = tk.Button(root, text="刷新信息", command=show_info)
button.pack()
label = tk.Label(root, text="点击按钮查看信息", justify="left")
label.pack()
root.mainloop()
👨🏫 给家长的Tips
这个项目需要安装
psutil库:
- 在命令行输入:
pip install psutil- 这是一个很好的实践项目,让孩子看到真实的硬件数据
- 可以问孩子:“为什么CPU使用率会变化?”
- “运行什么程序会让CPU使用率升高?”
本章小结
我们学到了什么?
-
计算机的五大组成部分:
- 输入设备:键盘、鼠标等
- 输出设备:显示器、打印机等
- 内存:短期存储,速度快但易失
- 硬盘:长期存储,容量大但速度慢
- CPU:大脑,执行计算和控制
-
Python知识与硬件的联系:
- 变量 → 内存
- 文件 → 硬盘
- print() → 输出设备(显示器)
- input() → 输入设备(键盘)
- 运算 → CPU的ALU
- 控制结构 → CPU的控制单元
-
程序执行过程:
- 硬盘 → 内存 → CPU → 输出设备
- 所有部件协同工作
重要概念对比
| 概念 | 计算机硬件 | Python对应 |
|---|---|---|
| 短期记忆 | 内存(RAM) | 变量、列表、字典 |
| 长期记忆 | 硬盘 | 文件、JSON |
| 思考 | CPU | 运算、条件判断、循环 |
| 感觉 | 输入设备 | input() |
| 表达 | 输出设备 | print() |
给家长的辅导建议
-
实物演示:
- 如果可以,打开一台旧电脑,让孩子看到真实的硬件部件
- 指着内存条、硬盘、CPU,讲解它们的作用
-
类比教学:
- 人体类比:大脑=CPU,记忆=内存/硬盘,感官=输入/输出
- 厨房类比:厨师=CPU,菜谱=程序,食材=数据,锅碗瓢盆=内存
-
联系实际:
- 当孩子写程序时,问:“这个变量存在哪里?”
- “为什么关闭程序后数据会丢失?”
- “为什么要保存文件?”
-
扩展思考:
- “如果计算机没有内存,只有硬盘,会怎样?”
- “如果CPU速度慢10倍,使用计算机的体验会有什么不同?”
- “未来的计算机会是什么样子?”
下一步
恭喜你完成了这本书的所有章节!
你已经从零开始,学会了:
- ✅ Python基础语法(变量、运算、数据类型)
- ✅ 程序控制结构(顺序、条件、循环)
- ✅ 数据结构(列表、字典)
- ✅ 函数和库
- ✅ 文件操作
- ✅ 命令行程序、图形界面、数据报表
- ✅ 计算机体系结构
接下来的学习建议:
- 继续练习:编程需要多动手,找一些小项目做
- 学习更多库:如游戏开发(Pygame)、网站开发(Flask)、数据分析(Pandas)
- 参加竞赛:如NOI(全国青少年信息学奥林匹克竞赛)
- 加入社区:和其他小程序员交流,分享作品
记住:
学习编程不是为了成为程序员,而是为了理解数字世界,培养逻辑思维,享受创造的乐趣!
祝你在编程的世界里继续探索,创造更多精彩的作品!🎉
🎓 毕业快乐!你已经完成了Python基础教程的所有学习!