🐍 Python 第二课:让程序有脑子——控制流与函数
课程目标:
- 让程序学会做判断(if/else):不再是傻乎乎地从上往下执行
- 让程序学会循环(for/while):重复的事情交给它,你去喝咖啡
- 学会写函数:把代码打包,一次编写,到处使用
- 认识基本数据结构:列表、字典、元组——数据的"收纳盒"
- 学会处理错误:让程序优雅地崩溃(或者不要崩溃)
1) 回顾上节课
上节课我们学会了:
- 安装 Python(如果还没装好,请回去补课)
- 写第一个程序
print("Hello, Python!") - 变量和数据类型(int、float、str、bool)
- 输入输出(input() 和 print())
常见问题解答:
Q:为什么我的 input() 得到的数字不能加减?
A:因为 input() 得到的是字符串!需要用 int() 或 float() 转换。就像你问朋友"你多大了",他回答"二十",这是文字;你要做算术,得把它理解成数字 20。
Q:运行程序时提示 "IndentationError" 是什么意思?
A:缩进错误!Python 用缩进表示代码块,就像用括号表示段落。缩进不一致,Python 会抓狂。检查你是不是混用了空格和 Tab。
2) 条件判断:if/else——让程序有脑子
现实生活中,我们经常要做判断:
- 如果下雨,就带伞;否则,就不带
- 如果年满 18 岁,可以投票;否则,回家写作业
程序也需要这种能力!
基本语法
age = int(input("请输入你的年龄:"))
if age >= 18:
print("你已经成年了,可以投票!")
else:
print("未成年,回家写作业去吧!")注意:
if后面加冒号:,表示"我要开始说条件成立时要做的事了"- 下一行要缩进(4 个空格),表示这些是"条件成立时"的代码
else后面也要加冒号:,表示"否则的话"
多条件判断:elif
如果不止两种情况呢?用 elif(else if 的缩写):
score = int(input("请输入你的成绩:"))
if score >= 90:
print("优秀!")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格,准备补考吧...")执行逻辑:
- 先检查
score >= 90,成立就打印"优秀",然后跳过其他所有条件 - 不成立,检查
score >= 80,成立就打印"良好",然后跳过其他 - 以此类推...
- 如果都不成立,执行
else
比较运算符
| 运算符 | 含义 | 例子 |
|---|---|---|
== | 等于 | 5 == 5 为 True |
!= | 不等于 | 5 != 3 为 True |
> | 大于 | 5 > 3 为 True |
< | 小于 | 5 < 3 为 False |
>= | 大于等于 | 5 >= 5 为 True |
<= | 小于等于 | 3 <= 5 为 True |
注意: == 是两个等号,表示"判断是否相等";= 是一个等号,表示"赋值"。写错的话,Python 会报错或者产生奇怪的结果。
逻辑运算符:and、or、not
有时候需要组合多个条件:
age = 25
income = 5000
# 申请信用卡的条件:年满 18 且收入超过 3000
if age >= 18 and income > 3000:
print("信用卡申请通过!")
else:
print("抱歉,条件不满足")
# 或者:VIP 用户或者消费满 1000 可以打折
is_vip = True
spent = 800
if is_vip or spent >= 1000:
print("可以享受折扣!")
else:
print("原价支付")
# not:取反
is_raining = False
if not is_raining:
print("今天不下雨,可以出去玩")优先级: not > and > or,不确定就加括号!
嵌套 if:if 里面套 if
is_member = True
purchase_amount = 200
if is_member:
if purchase_amount >= 100:
print("会员且满 100,打 8 折")
else:
print("会员但不满 100,打 9 折")
else:
print("非会员,原价")建议: 嵌套不要超过 3 层,否则代码会像迷宫一样难读。如果逻辑太复杂,考虑拆分或者优化。
3) 循环:重复的事情,让程序干
while 循环:当...的时候,就一直做
# 倒计时程序
count = 5
while count > 0:
print(count)
count = count - 1 # 或者写成 count -= 1
print("发射!🚀")执行过程:
- 检查
count > 0,5 > 0 成立,执行循环体 - 打印 5,count 变成 4
- 检查
count > 0,4 > 0 成立,执行循环体 - 打印 4,count 变成 3
- ...直到 count 变成 0,0 > 0 不成立,退出循环
⚠️ 警告: 如果忘记写 count = count - 1,count 永远是 5,循环永远不停,这就是死循环!程序会卡死,需要按 Ctrl+C 强制终止。
for 循环:遍历神器
while 适合"不知道要循环多少次"的情况,for 适合"遍历一堆东西":
# 遍历字符串
for char in "Python":
print(char)
# 输出:
# P
# y
# t
# h
# o
# nrange() 函数:生成数字序列
# 打印 0 到 4
for i in range(5):
print(i)
# 打印 1 到 5
for i in range(1, 6):
print(i)
# 打印 0, 2, 4, 6, 8(步长为 2)
for i in range(0, 10, 2):
print(i)range() 的三种用法:
range(5):0, 1, 2, 3, 4(从 0 开始,到 5 结束,不包括 5)range(1, 6):1, 2, 3, 4, 5(从 1 开始,到 6 结束,不包括 6)range(0, 10, 2):0, 2, 4, 6, 8(从 0 开始,到 10 结束,步长为 2)
循环控制:break 和 continue
break:立即退出循环
# 找第一个能被 7 整除的数
for i in range(1, 100):
if i % 7 == 0: # % 是取余数
print(f"找到了:{i}")
break # 找到了,不找了,退出循环continue:跳过当前这次,继续下一次
# 打印 1-10 中的奇数
for i in range(1, 11):
if i % 2 == 0: # 如果是偶数
continue # 跳过,不执行下面的 print
print(i)区别:
break:循环结束,彻底走人continue:这次算了,继续下一轮
循环嵌套:循环里面套循环
# 打印乘法表
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}×{i}={i*j}", end="\t")
print() # 换行输出:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
...注意: 嵌套循环效率较低,大数据量时要小心。另外,内层循环的变量名不要和外层重复(虽然 Python 允许,但容易混淆)。
4) 函数:代码的打包艺术
为什么要用函数?
场景一: 你需要在程序的 10 个不同地方计算圆的面积。不写函数的话,你要复制粘贴 10 次同样的代码。万一要改公式(比如从 πr² 改成 3.14*r*r),你要改 10 处,漏改一处就 bug 了。
场景二: 你的主程序有 200 行,读起来像天书。如果把功能拆成函数,主程序可能只有 20 行,清晰明了。
定义函数
def greet(name):
"""
这是一个打招呼的函数
name: 对方的名字
"""
print(f"你好,{name}!很高兴认识你!")
# 调用函数
greet("张三")
greet("李四")语法解析:
def:define 的缩写,表示"我要定义一个函数了"greet:函数名,要小写,用下划线连接多个单词(Python 风格)(name):参数,函数需要的外部数据"""...""":文档字符串(docstring),说明函数是干嘛的,好习惯!- 函数体要缩进
返回值:return
函数可以处理数据,然后把结果"交出来":
def add(a, b):
"""计算两个数的和"""
result = a + b
return result # 把结果返回给调用者
# 使用返回值
sum = add(3, 5)
print(sum) # 输出 8
# 或者直接
print(add(10, 20)) # 输出 30重要: return 执行后,函数立即结束,后面的代码不会执行:
def test():
print("这行会执行")
return "结束了"
print("这行不会执行") # 永远不会执行
test()多个参数和默认参数
def make_coffee(coffee_type, size="中杯", sugar=True):
"""
制作咖啡
coffee_type: 咖啡类型(必填)
size: 杯型,默认中杯
sugar: 是否加糖,默认 True
"""
sugar_str = "加糖" if sugar else "不加糖"
print(f"制作完成:{size}的{coffee_type},{sugar_str}")
# 调用方式
make_coffee("拿铁") # 中杯拿铁,加糖
make_coffee("美式", "大杯") # 大杯美式,加糖
make_coffee("卡布奇诺", "小杯", False) # 小杯卡布奇诺,不加糖
make_coffee("摩卡", sugar=False) # 中杯摩卡,不加糖(指定参数名)参数传递方式:
- 按位置传:
make_coffee("美式", "大杯") - 按名字传:
make_coffee("摩卡", sugar=False) - 混合传:位置参数在前,命名参数在后
变量作用域:全局 vs 局部
# 全局变量:在函数外面定义的
global_var = "我是全局的"
def test():
# 局部变量:在函数里面定义的,外面访问不到
local_var = "我是局部的"
print(global_var) # 可以访问全局变量
print(local_var)
test()
print(global_var) # 正常
# print(local_var) # 报错!NameError: name 'local_var' is not defined如果想在函数里修改全局变量:
count = 0
def increment():
global count # 声明:我要用全局的 count,不是新建一个局部变量
count += 1
print(f"当前计数:{count}")
increment() # 输出:当前计数:1
increment() # 输出:当前计数:2建议: 尽量少用 global,容易混乱。可以通过参数传递和返回值来交换数据。
5) 数据结构:数据的"收纳盒"
列表(List):有序、可变、啥都能装
# 创建列表
fruits = ["苹果", "香蕉", "橙子"]
mixed = [1, "hello", 3.14, True, [1, 2, 3]] # 啥类型都能放,甚至列表里套列表
# 访问元素(索引从 0 开始!)
print(fruits[0]) # 苹果
print(fruits[1]) # 香蕉
print(fruits[-1]) # 橙子(-1 表示最后一个)
# 修改元素
fruits[1] = "葡萄"
print(fruits) # ['苹果', '葡萄', '橙子']
# 常用操作
fruits.append("西瓜") # 末尾添加
fruits.insert(1, "芒果") # 在索引 1 处插入
fruits.remove("葡萄") # 删除第一个匹配的元素
popped = fruits.pop() # 删除并返回最后一个元素
print(len(fruits)) # 获取长度
# 切片:获取子列表
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[2:5]) # [2, 3, 4](从索引 2 到 5,不包括 5)
print(numbers[:3]) # [0, 1, 2](从头开始到 3)
print(numbers[7:]) # [7, 8, 9](从 7 到末尾)
print(numbers[::2]) # [0, 2, 4, 6, 8](步长为 2)
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0](反转!)遍历列表:
for fruit in fruits:
print(f"我喜欢吃{fruit}")
# 带索引的遍历
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")字典(Dictionary):键值对,查东西快
列表是按位置找元素,字典是按"名字"找:
# 创建字典
student = {
"name": "张三",
"age": 20,
"major": "计算机",
"gpa": 3.8
}
# 访问
print(student["name"]) # 张三
print(student.get("phone", "未知")) # 安全获取,不存在返回默认值"未知"
# 修改和添加
student["age"] = 21 # 修改
student["phone"] = "13800138000" # 添加新键值对
# 删除
del student["gpa"]
# 遍历
for key in student:
print(f"{key}: {student[key]}")
# 或者同时遍历键和值
for key, value in student.items():
print(f"{key}: {value}")使用场景: 存储对象信息、配置项、计数统计等。
元组(Tuple):不可变的列表
# 创建元组(圆括号)
coordinates = (10, 20)
rgb = (255, 128, 0)
# 可以访问,不能修改
print(coordinates[0]) # 10
# coordinates[0] = 15 # 报错!TypeError: 'tuple' object does not support item assignment什么时候用元组?
- 数据不应该被修改(比如坐标、RGB 颜色)
- 作为字典的键(列表不能当键,因为可变)
- 函数返回多个值(其实就是返回元组)
def get_min_max(numbers):
return min(numbers), max(numbers) # 返回元组
minimum, maximum = get_min_max([3, 1, 4, 1, 5, 9])
print(minimum, maximum) # 1 9集合(Set):去重和交集并集
# 创建集合(花括号,或者 set())
s = {1, 2, 3, 3, 3, 3} # 自动去重
print(s) # {1, 2, 3}
# 常用操作
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a & b) # 交集:{3, 4}
print(a | b) # 并集:{1, 2, 3, 4, 5, 6}
print(a - b) # 差集:{1, 2}
print(a ^ b) # 对称差集(只在其中一个集合中的元素):{1, 2, 5, 6}6) 错误处理:让程序优雅地犯错
常见错误类型
| 错误类型 | 说明 | 例子 |
|---|---|---|
SyntaxError | 语法错误 | 漏了冒号、括号不匹配 |
NameError | 名字错误 | 使用了未定义的变量 |
TypeError | 类型错误 | 字符串和整数相加 |
ValueError | 值错误 | int("abc") |
IndexError | 索引错误 | 访问列表不存在的索引 |
KeyError | 键错误 | 访问字典不存在的键 |
ZeroDivisionError | 除零错误 | 10 / 0 |
try/except:捕获错误
try:
num = int(input("请输入一个数字:"))
result = 10 / num
print(f"10 除以 {num} 等于 {result}")
except ValueError:
print("输入的不是有效数字!")
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"发生了未知错误:{e}")执行流程:
- 先执行
try块里的代码 - 如果出错,根据错误类型匹配
except块 - 匹配成功,执行对应的
except块,然后继续 - 没有错误,跳过所有
except
else 和 finally
try:
f = open("data.txt", "r")
content = f.read()
except FileNotFoundError:
print("文件不存在")
else:
print("文件读取成功!")
print(content)
finally:
print("无论成功与否,这行都会执行")
# 通常用来关闭文件、释放资源等7) 综合练习
练习 1:猜数字游戏
计算机随机生成一个 1-100 的数字,用户来猜,告诉用户猜大了还是小了,直到猜中。
提示: 用 random.randint(1, 100) 生成随机数,需要 import random
参考答案:
import random
target = random.randint(1, 100)
attempts = 0
print("猜数字游戏!我想了一个 1-100 之间的数字。")
while True:
try:
guess = int(input("请输入你的猜测:"))
attempts += 1
if guess < target:
print("太小了!")
elif guess > target:
print("太大了!")
else:
print(f"恭喜你猜中了!答案就是 {target},你用了 {attempts} 次。")
break
except ValueError:
print("请输入一个有效的数字!")练习 2:学生成绩管理系统
用字典存储学生信息(姓名、成绩),实现以下功能:
- 添加学生
- 删除学生
- 查询学生成绩
- 显示所有学生
- 计算平均分
提示: 用字典存储,key 是学生姓名,value 是成绩。用循环显示菜单。
参考答案(框架):
students = {}
def add_student():
name = input("请输入学生姓名:")
try:
score = float(input("请输入成绩:"))
students[name] = score
print(f"已添加学生:{name},成绩:{score}")
except ValueError:
print("成绩必须是数字!")
def show_all():
if not students:
print("暂无学生数据")
return
print("\n学生成绩列表:")
print("-" * 20)
for name, score in students.items():
print(f"{name}: {score}")
print("-" * 20)
# 主循环
while True:
print("\n1. 添加学生 2. 删除学生 3. 查询成绩 4. 显示全部 5. 计算平均分 6. 退出")
choice = input("请选择操作:")
if choice == "1":
add_student()
elif choice == "4":
show_all()
# ... 其他选项自己实现
elif choice == "6":
print("再见!")
break
else:
print("无效的选择")8) 下节课预告:从白银到黄金
下节课我们将学习:
- 文件操作:读写文件,数据持久化
- 模块和包:组织代码,使用第三方库
- 面向对象编程(OOP):类与对象,封装继承多态
- 常用标准库:os、sys、datetime、json 等
- 实战小项目:综合运用所学知识
9) 学习建议
- 多写代码,少看视频:看懂了不等于会了,手指会了才是真的会
- 从模仿到创新:先抄示例代码,理解后尝试修改,最后独立写
- 善用百度:复制报错信息搜索,99% 的问题都有答案
- 读别人的代码:GitHub 上有很多优秀项目,学习别人的写法
- 坚持打卡:每天写一点,保持手感
记住: 编程是一门手艺,熟能生巧。你现在觉得难的,三个月后回头看会觉得"就这?"。
遇到问题? 百度一下,或者放一放,明天再看。有时候大脑需要后台编译。
祝编程愉快!Keep calm and code on! 🐍
课后作业:
- 完成上面的两个练习
- 用循环打印各种图案(金字塔、菱形等)
- 写一个函数,判断一个数是否是素数
- 尝试用列表推导式重写一些循环(进阶)
下节课见!
发表评论
评论列表