完全从零开始。忘掉所有语言的名字,像第一次观察世界一样,来认识编程中最基础、最重要的概念——变量。
第一课:我们为什么需要“变量”?
想象一个简单的任务:请你计算 (5 + 3) * 2 的结果。
你心算一下,得到 16。程序可以写成:
print( (5 + 3) * 2 )
直接写数字,也能完成。
但现实世界要复杂得多。比如,我们要计算一个会变化的东西,比如用户的游戏分数。
第一局,用户得了 5 分。
第二局,他又得了 3 分。
我们想计算他的总分,再奖励双倍。
如果直接写数字:
# 第一局后
total = 5
# 第二局后,我们需要把新的分数 3 加进去... 怎么办?
# 我们无法修改 “5” 这个数字本身。
你会发现,写死的数字(比如 5)是“死”的,它无法记录变化的状态。我们需要的,是一个可以存放会变化的数据的容器。
这个容器,就是 “变量”。
第二课:用现实世界理解变量——“标签”和“盒子”
这是理解变量的最佳比喻:
- 变量是一个“盒子”:在计算机的内存里,开辟出一个小空间,用来存放数据(一个数字、一段文字等)。
- 变量名是“标签”:我们给这个盒子贴上一个独一无二的标签(比如
score),这样我们就不用记住盒子在内存中复杂难记的“地址”(比如0x7ffeeb4c),而只要通过这个友好的标签名,就能找到它,并使用里面的数据。
核心操作只有三个:
- 创建盒子并贴标签(声明/定义变量)
- 往盒子里放东西(赋值)
- 看着标签,说出盒子里是什么(使用变量的值)
第三课:动手体验——用Python来玩“贴标签”游戏
我们选Python开始,因为它的语法最像我们给盒子“贴标签”和“放东西”的自然动作。
第一步:创建并赋值(贴上标签,放入物品)
score = 100
这行代码就是整个动作:
=:不是数学中的“等于”,而是 “放进去” 或 “指向” 的指令。score:我们想好的标签名。100:我们要放进盒子的具体数据。
执行后,内存中就建立了一个关系:标签 score ➜ 盒子里的数据 100。
第二步:使用(看着标签,取出物品)
print(score) # 输出:100
print(score * 2) # 输出:200
print(score + 50) # 输出:150
当我们使用 score 时,计算机会根据标签 score 找到那个盒子,把里面的数据 100 拿出来用。盒子里的东西不变。
第三步:重新赋值(把标签撕下来,贴到新盒子上,或者给旧盒子换新东西)
score = 150
print(score) # 输出:150
这行代码执行后,标签 score 不再指向装着 100 的旧盒子,而是指向了一个装着 150 的新盒子(或者理解成把旧盒子里的 100 换成了 150)。
原来的 100 如果没有其他标签指向它,就会被计算机的清洁工(垃圾回收机制)清理掉。
重点:标签(变量名)永远指向最新的那个值。
第四课:变量的“变”与“不变”
- 什么在“变”?
- 标签所指向的 “值” 可以变。
score可以从100变成150。 - 这个能力,让我们能够记录变化的状态(比如不断增加的游戏分数、实时变化的股价)。
- 标签所指向的 “值” 可以变。
- 什么“不变”?
- 标签(变量名)本身的意义 在程序运行中最好不变。
score就应该始终代表“分数”,如果你突然让它代表“用户名”,就会让读代码的人(包括未来的你自己)非常困惑。 - 编程好习惯:给变量起一个清晰、有意义的名字。
x->score(不好 vs 好)n->student_count(不好 vs 好)a->is_logged_in(不好 vs 好)
- 标签(变量名)本身的意义 在程序运行中最好不变。
第五课:一个思维体操
看这段代码,猜猜最后 a 和 b 的值是什么?
a = 10
b = 20
a = b
不要往下看,先在心里想一个答案。
解析:
a = 10:标签a指向盒子10。b = 20:标签b指向盒子20。- 关键步骤
a = b:这行代码的意思是 “让标签a指向标签b当前指向的那个东西”。- 计算机先去找
b指向什么?找到了,是20。 - 然后,把标签
a从原来的10上撕下来,贴到20这个盒子上。 - 所以最终结果是:
a和b现在都指向了同一个值20。 - 盒子
10现在没有标签了,会被清理。
- 计算机先去找
用图像表示:
初始: a → 10, b → 20
执行 a = b 后: a ↘
20
b ↗
所以,最后 print(a) 和 print(b) 都会输出 20。
小结:我们目前学了什么?
- 变量是什么:一个可以存放变化数据的、有名字的容器(盒子+标签)。
- 核心价值:用来记录和跟踪程序运行中变化的状态。
- 核心操作:
变量名 = 值:赋予变量一个值(贴标签,放东西)。- 使用
变量名:获取它当前代表的值(看标签,找东西)。
- 最重要的概念:
=是“赋值”操作(放进去/指向),不是数学等号。- 变量名应该清晰易懂。
这个基础认知,适用于几乎所有的编程语言。 就像学会了“开车”的基本原理(方向盘、油门、刹车),无论换什么牌子的车,你都能快速上手。不同语言只是在这些盒子的“材质”(类型)、贴标签的“规矩”(语法)上有所不同。
如果这个概念已经清晰了,我们就可以进入下一个最自然的问题:“我们可以往这个‘盒子’里放哪些不同种类的‘东西’?” —— 也就是 “数据类型”。
第一课:盒子里能放什么?——认识“数据类型”
上一课我们把变量比作一个盒子。现在我们要问:盒子里能放哪些东西?
在现实生活中,盒子可以放书、放水果、放衣服。在编程世界里,盒子(变量)里能放的东西也有不同的种类,我们称之为 “数据类型”。
为什么要有数据类型?
- 合理分配空间:就像冰箱放食物,衣柜放衣服,不同的东西需要不同大小的空间。数字、文字、真假值,它们在计算机内存中占用的空间是不同的。
- 规定能做什么操作:数字可以进行加减乘除,文字可以进行拼接、查找,真假值可以进行逻辑判断。不同类型的数据,能进行的操作是不同的。
第二课:基本数据类型初识
我们先用一种最直观的分类,来看最常见的几种数据类型。不要怕,我们先只看三种最基础的。
1. 整数(Integer)
- 是什么:没有小数部分的数字。比如:
-5,0,100,2024。 - 能做什么:加减乘除、比较大小等数学运算。
- 例子:游戏分数、年龄、数量。
python
# 在Python中,整数用 int 表示 score = 100 age = 18
2. 浮点数(Floating-point number)
- 是什么:有小数部分的数字。比如:
3.14,-0.5,2.0。 - 能做什么:和整数一样,可以进行数学运算,但注意小数计算可能有精度问题(这是计算机存储方式导致的,先知道即可)。
- 例子:身高、体重、圆周率。
python
height = 1.75 weight = 65.5
3. 字符串(String)
- 是什么:一串文本,用单引号或双引号包围。比如:
"hello",'世界'。 - 能做什么:拼接(连接)、截取、查找、替换等文本操作。
- 例子:姓名、地址、一句话。
python
name = "张三" greeting = '你好,世界!'
第三课:动态类型 vs 静态类型——盒子的“标签”有无说明
这是不同编程语言在数据类型上的一个核心区别。
情景模拟:我们去超市寄存包裹。
- 动态类型语言(如Python、JavaScript):
超市给你一个空盒子(变量),你随便往里面放什么都可以(数字、文本、水果)。盒子上只贴了标签(变量名),没有规定必须放什么。你甚至可以先放一个苹果,再把它换成一本书。pythonbox = 100 # 先放一个整数 box = “hello” # 换成字符串,可以!优点:灵活方便。
缺点:如果盒子里放的不是你期望的东西(比如你以为是水果,结果是一块石头),可能要到打开盒子(使用数据)的时候才发现错误。 - 静态类型语言(如C、Java):
超市的盒子上不仅贴了标签,还明确写了“仅放水果”或“仅放书籍”。你必须在寄存时就声明盒子里放什么类型的东西,而且一旦声明,就不能放入其他类型的物品。cint box = 100; // 声明一个只能放整数的盒子,并放入100 // box = “hello”; // 错误!不能把字符串放进整数盒子优点:安全,因为类型错误在寄存时(编译时)就能发现;而且计算机可以提前优化,效率高。
缺点:不够灵活,写代码时要多写一些声明类型的文字。
比喻:
- 动态类型:像通用的纸箱,什么都能装,但外面没写清楚里面是什么。
- 静态类型:像专用的包装盒(月饼盒、鞋盒),专门为一种东西设计,一看就知道里面是什么。
第四课:动手体验——用Python感受类型
Python是动态类型,我们可以直接观察类型的变化。
1. 查看类型
使用 type() 函数,可以查看一个变量里存放的数据是什么类型。
python
# 定义几个变量 a = 10 b = 3.14 c = "hello" print(type(a)) # 输出:<class 'int'> 表示整数类型 print(type(b)) # 输出:<class 'float'> 表示浮点数类型 print(type(c)) # 输出:<class 'str'> 表示字符串类型
2. 动态类型的变化
python
x = 10 print(type(x)) # 输出:<class 'int'> x = "now I am a string" print(type(x)) # 输出:<class 'str'>
同一个变量 x,可以先存放整数,再存放字符串。这就是动态类型。
3. 类型不同,操作不同
python
# 数字可以做数学运算 num1 = 10 num2 = 20 print(num1 + num2) # 输出:30 # 字符串可以做拼接 str1 = "hello" str2 = "world" print(str1 + str2) # 输出:helloworld # 但是数字和字符串不能直接相加(类型不同) # print(num1 + str1) # 这行会报错:TypeError
计算机很“死板”,它要求操作的数据类型要符合规则。如果你硬要让数字和文本相加,它会报错,因为它不知道你想做数学加法还是文本拼接。
第五课:其他常见数据类型(了解即可)
除了上面三种,还有几种常用的类型:
1. 布尔值(Boolean)
- 是什么:只有两个值:
True(真)和False(假)。代表逻辑判断的结果。 - 能做什么:用于条件判断(比如如果下雨,就带伞)。
- 例子:是否登录、是否成年、开关状态。
python
is_raining = True is_logged_in = False
2. 列表(List)
- 是什么:一个有序的集合,可以存放多个数据,用方括号
[]表示。 - 能做什么:可以增删改查其中的元素。
- 例子:购物清单、学生名单。
python
shopping_list = ["苹果", "香蕉", "牛奶"] scores = [85, 90, 78, 92]
3. 空值(None)
- 是什么:表示什么都没有,空盒子。在Python中用
None表示。 - 能做什么:通常用于初始化一个变量,表示暂时没有值。
python
result = None # 表示结果还没有计算出来
第六课:思维体操——类型转换
有时候我们需要把一种类型转换成另一种类型,比如把字符串的数字转换成整数进行计算。
python
# 输入的是字符串 age_str = "18" print(type(age_str)) # <class 'str'> # 转换成整数 age_int = int(age_str) print(type(age_int)) # <class 'int'> print(age_int + 2) # 输出:20 # 整数转字符串 new_str = str(age_int) + "岁" print(new_str) # 输出:18岁 print(type(new_str)) # <class 'str'>
注意:不是所有转换都能成功。比如 int("hello") 会报错,因为“hello”无法转换成整数。
小结:数据类型我们学了什么?
- 数据类型是什么:变量盒子里能放的不同种类的东西(整数、浮点数、字符串等)。
- 为什么要有类型:
- 合理利用内存空间。
- 规定数据能进行的操作。
- 两大类型系统:
- 动态类型(如Python):变量可以随时改变类型,灵活但可能隐藏错误。
- 静态类型(如C/Java):变量必须先声明类型,安全但不够灵活。
- 常见类型:
- 整数(
int)、浮点数(float)、字符串(str)是三个最基础的类型。 - 布尔值(
bool)用于逻辑判断。 - 列表(
list)用于存放多个数据。
- 整数(
- 类型转换:可以在一定条件下将一种类型转换为另一种。
重要理念:数据类型是数据的“分类”,不同的类型有不同的用途和操作方式。在编程时,要时刻注意你正在处理的数据是什么类型,就像在生活中要知道你手里拿的是水果还是书本一样。
接下来,我们可以继续探讨:当数据有了类型,我们如何用它们进行更复杂的操作?比如,如何把数据组合起来?如何根据不同的数据做出判断?——这就是 “数据结构” 和 “控制流” 的开始了。
好的!我们继续按照这个思路,循序渐进地学习。现在我们已经理解了变量是存放数据的“盒子”,接下来自然会问:“这些盒子在程序里是怎么互动、怎么决定程序走向的?”
这就引出了编程的另一个核心概念——控制流。
第六课:让程序“活”起来——控制流的基本思想
1. 程序默认是“一条直线”
到目前为止,我们的程序像一张清单,从上到下一条一条执行:
# 程序就像一张任务清单
print("开始")
score = 100
score = score + 20
print("最终分数:", score)
计算机忠实地按顺序执行每一行,不会跳过,不会重复,不会选择。
但现实世界充满了“如果…就…”的选择,和“重复做…直到…”的循环。
2. 生活中的控制流
场景一:出门前看天气(条件判断)
如果 下雨:
✓ 带上雨伞
否则:
✗ 不带雨伞
场景二:做饭时搅拌(循环)
重复这个动作:
✓ 搅拌一圈
直到 酱汁变浓稠
这些决策和重复,就是“控制流”——控制程序执行的流向。
第七课:学会做选择——条件判断(if语句)
第一步:最基本的“如果…”
在Python中,用 if 表示“如果”:
# 模拟:如果下雨,就带伞
is_raining = True
if is_raining:
print("带上雨伞")
关键点:
if后面跟着一个条件(这里是变量is_raining)- 冒号
:表示“接下来要做的事情” - 缩进(通常4个空格)表示“属于这个if要做的事情”
第二步:加上“否则…”
用 else 表示“否则”:
is_raining = False
if is_raining:
print("带上雨伞")
else:
print("不用带伞")
运行结果会是:不用带伞
第三步:更复杂的“否则如果…”
用 elif(else if的缩写)表示“否则如果”:
temperature = 25
if temperature > 30:
print("太热了,穿短袖")
elif temperature > 20: # 20 < temperature ≤ 30
print("天气凉爽,穿长袖")
elif temperature > 10: # 10 < temperature ≤ 20
print("有点凉,加件外套")
else:
print("很冷,穿羽绒服")
第四步:理解“条件”的本质
条件其实就是个问题,回答只能是 True(真/是) 或 False(假/否)。
# 比较产生True/False
age = 18
print(age >= 18) # 输出:True
# 可以组合条件
is_weekend = False
has_money = True
if is_weekend and has_money: # 必须是周末 AND 有钱
print("去逛街")
if not is_weekend: # 不是周末
print("要上班")
第八课:重复的力量——循环(for和while)
第一种循环:for循环(已知次数的循环)
场景:我要说5次“你好”
# 笨方法
print("你好")
print("你好")
print("你好")
print("你好")
print("你好")
# 聪明方法:for循环
for i in range(5):
print("你好")
range(5)产生一个数字序列:[0, 1, 2, 3, 4]for i in意思是“依次取序列中的每个数字,暂时叫它 i”- 然后执行缩进的代码块,每次 i 的值都不同
实际应用:处理列表中的每个学生
students = ["张三", "李四", "王五"]
for student in students:
print(f"正在处理学生:{student}")
输出:
正在处理学生:张三
正在处理学生:李四
正在处理学生:王五
第二种循环:while循环(满足条件就继续)
场景:搅拌酱汁,直到变浓稠
# 假设sauce_thickness表示酱汁浓稠度(0-100)
sauce_thickness = 20
while sauce_thickness < 80: # 当酱汁不够浓稠时
print("搅拌一圈...")
sauce_thickness = sauce_thickness + 10 # 每搅拌一次浓稠度增加
print(f"当前浓稠度:{sauce_thickness}")
print("酱汁已浓稠,可以出锅了!")
无限循环的陷阱:
# 危险!这会永远执行下去
# count = 0
# while count < 5: # 条件永远为真,因为count没有增加
# print("陷入循环...")
循环的控制:break和continue
break:立刻跳出整个循环continue:跳过本次循环,继续下一次
# 找第一个大于10的数字
numbers = [3, 7, 11, 5, 15]
for num in numbers:
if num > 10:
print(f"找到了第一个大于10的数:{num}")
break # 找到后就退出循环
else:
print(f"{num} 不大于10,继续找...")
第九课:控制流的“思维体操”
练习1:理解嵌套
weather = "晴天"
temperature = 28
if weather == "晴天":
if temperature > 30:
print("晴天且炎热,去游泳")
else:
print("晴天但凉爽,去公园")
else:
print("不是晴天,在家休息")
练习2:循环中的条件
# 打印1-10中所有的偶数
for number in range(1, 11):
if number % 2 == 0: # % 是求余数,偶数的余数为0
print(f"{number} 是偶数")
练习3:while与用户交互
# 简单的密码检查(模拟版)
correct_password = "123456"
attempts = 0
max_attempts = 3
while attempts < max_attempts:
user_input = input("请输入密码:")
if user_input == correct_password:
print("登录成功!")
break
else:
attempts = attempts + 1
remaining = max_attempts - attempts
print(f"密码错误,还剩{remaining}次尝试机会")
if attempts == max_attempts:
print("尝试次数过多,账户已锁定")
第十课:不同语言的对比(if和for)
C语言的写法
// if语句
int age = 18;
if (age >= 18) {
printf("成年人\n");
} else {
printf("未成年人\n");
}
// for循环
for (int i = 0; i < 5; i++) {
printf("Hello\n");
}
特点:
- 条件必须用括号
()括起来 - 代码块用花括号
{}表示 - for循环三部分:初始化(
int i=0); 条件(i<5); 更新(i++)
Java语言的写法
// 与C语言几乎相同
int age = 18;
if (age >= 18) {
System.out.println("成年人");
} else {
System.out.println("未成年人");
}
// for循环也一样
for (int i = 0; i < 5; i++) {
System.out.println("Hello");
}
JavaScript的写法
// if语句
let age = 18;
if (age >= 18) {
console.log("成年人");
} else {
console.log("未成年人");
}
// for循环(两种)
// 1. 传统for循环
for (let i = 0; i < 5; i++) {
console.log("Hello");
}
// 2. for...of循环(类似Python的for)
let students = ["张三", "李四", "王五"];
for (let student of students) {
console.log(student);
}
共同的核心逻辑
虽然语法不同,但所有语言的流程控制都基于相同的逻辑结构:
条件判断:
if (条件为真):
做A
else:
做B
循环:
重复执行某些代码
直到条件不再满足
教学总结:控制流的核心概念
- 顺序执行是基础:默认情况下,代码从上到下一条条执行。
- 分支让程序有选择:
if/elif/else根据条件选择不同路径- 条件必须是能得出True/False的问题
- 循环让程序能重复:
for循环:知道要重复多少次时使用while循环:不知道具体次数,只知道条件时使用- 小心无限循环!
- 嵌套是常态:条件中可以嵌套循环,循环中可以嵌套条件,就像俄罗斯套娃。
- 所有语言大同小异:掌握了一种语言的控制流,其他语言只是语法不同,逻辑完全相通。
现在我们已经学会了:
- 变量(存放数据的盒子)
- 控制流(让程序做选择和重复)
接下来很自然的问题是:“当我们的代码越来越长,怎么避免重复写同样的代码段?怎么组织代码让它更清晰?” 这就引出了 函数(Function) 的概念。
第十一课:为什么要用函数?——避免重复劳动
想象一下,你每天早上都要做同样的事情:
- 起床
- 刷牙
- 吃早餐
- 出门
如果让你写一个“早上例行程序”的代码,你可能会这样写:
python
# 星期一
print("起床")
print("刷牙")
print("吃早餐")
print("出门")
# 星期二
print("起床")
print("刷牙")
print("吃早餐")
print("出门")
# 星期三
print("起床")
print("刷牙")
print("吃早餐")
print("出门")
这样写不仅重复,而且如果要修改(比如刷牙前要先洗脸),就要修改每一个地方。
我们想要一种方法,把这一系列动作打包成一个“例行程序”,然后每天调用这个程序即可。这就是函数。
第十二课:函数的本质——打包一组操作
第一步:定义一个函数
在Python中,我们用 def 来定义一个函数:
python
def morning_routine():
print("起床")
print("刷牙")
print("吃早餐")
print("出门")
def是“定义”的缩写morning_routine是函数名(我们给这个“例行程序”取的名字)- 括号
()里面可以放一些东西(后面会讲) - 冒号
:表示函数内容的开始 - 缩进的部分是函数体(函数要执行的操作)
第二步:调用函数
定义函数不会执行它,就像写下一个菜谱不会自动做出菜一样。我们需要“调用”函数来执行它:
python
morning_routine() # 调用函数,执行里面的代码
这样,我们就可以在需要的地方重复使用这段代码:
python
# 星期一 morning_routine() # 星期二 morning_routine() # 星期三 morning_routine()
如果需要修改,只需要修改函数定义,所有调用它的地方都会自动更新。
第十三课:让函数更灵活——参数
现在的早晨例行程序是固定的,但如果有时候我想吃不同的早餐呢?我们可以让函数接受一些变化的信息,这些信息叫做参数。
带参数的函数
python
def morning_routine(breakfast):
print("起床")
print("刷牙")
print(f"吃{breakfast}") # 使用参数
print("出门")
# 调用时传入不同的早餐
morning_routine("面包")
morning_routine("粥")
morning_routine("麦片")
这样,函数就变得灵活了。
多个参数
python
def morning_routine(wake_up_time, breakfast):
print(f"{wake_up_time}点起床")
print("刷牙")
print(f"吃{breakfast}")
print("出门")
morning_routine(7, "面包")
morning_routine(8, "粥")
第十四课:函数给我们结果——返回值
有时候,我们不仅希望函数执行一些操作,还希望它给我们一个结果。比如,我们有一个函数用来计算两个数的和:
python
def add(a, b):
result = a + b
return result # 返回结果
# 调用函数,并将返回值赋给变量
sum_result = add(3, 5)
print(sum_result) # 输出:8
# 也可以直接使用返回值
print(add(10, 20)) # 输出:30
return语句将结果从函数中送出来。- 如果没有
return,函数默认返回None(空值)。
一个常见的误解
python
def add_no_return(a, b):
result = a + b
x = add_no_return(3, 5)
print(x) # 输出:None,因为函数没有返回值
第十五课:函数的组合使用
函数可以调用其他函数,就像我们生活中的任务可以分解成子任务一样。
python
def brush_teeth():
print("挤牙膏")
print("刷牙")
print("漱口")
def eat_breakfast(food):
print(f"准备{food}")
print(f"吃{food}")
print("洗碗")
def morning_routine(breakfast):
print("起床")
brush_teeth() # 调用刷牙函数
eat_breakfast(breakfast) # 调用吃早餐函数
print("出门")
morning_routine("面包")
这样,每个函数负责一个小的任务,整个程序结构清晰,易于维护。
第十六课:不同语言的函数语法对比
Python
python
def greet(name):
return f"Hello, {name}"
message = greet("Alice")
print(message)
C语言
c
#include <stdio.h>
// 函数声明(告诉编译器有这个函数)
void greet(char name[]) {
printf("Hello, %s\n", name);
}
int main() {
greet("Alice");
return 0;
}
特点:
- 函数必须声明返回值类型(
void表示不返回任何值) - 参数也要有类型(
char name[]表示字符串) - 函数要在调用之前定义,或者先声明
Java
java
public class Main {
// 方法(Java中函数叫方法)必须放在类里面
public static void greet(String name) {
System.out.println("Hello, " + name);
}
public static void main(String[] args) {
greet("Alice");
}
}
特点:
- 函数(方法)必须放在类中
- 有访问修饰符(
public)、静态标识(static)、返回值类型、参数类型
JavaScript
javascript
// 函数定义
function greet(name) {
return "Hello, " + name;
}
// 调用
let message = greet("Alice");
console.log(message);
第十七课:函数的重要概念
1. 参数传递
- 位置参数:按照位置传递,比如
morning_routine(7, "面包") - 关键字参数:指定参数名,可以不按顺序,比如
morning_routine(breakfast="面包", wake_up_time=7)
2. 作用域
函数内部定义的变量是局部变量,只在函数内部有效。
python
def my_function():
x = 10 # 局部变量
print(x)
my_function()
# print(x) # 这里会报错,因为x只在函数内部有效
3. 返回值
- 函数可以返回多个值(实际上返回一个元组)
python
def swap(a, b):
return b, a
x, y = swap(3, 5)
print(x, y) # 输出:5 3
第十八课:函数的思维体操
练习1:理解函数调用过程
python
def double(x):
return x * 2
def add(a, b):
return a + b
result = add(double(3), double(4))
# 分步:
# 1. double(3) 返回 6
# 2. double(4) 返回 8
# 3. add(6, 8) 返回 14
print(result) # 输出:14
练习2:函数与循环结合
python
def print_multiple_times(message, times):
for i in range(times):
print(message)
print_multiple_times("你好", 3)
练习3:返回值的使用
python
def is_even(number):
if number % 2 == 0:
return True
else:
return False
# 或者更简洁:return number % 2 == 0
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if is_even(num):
print(f"{num} 是偶数")
else:
print(f"{num} 是奇数")
教学总结:函数的核心概念
- 函数的目的是封装代码:将一段常用的代码打包,便于重复使用和组织。
- 函数的基本结构:
- 函数名:用来调用函数
- 参数:让函数可以接受外部数据
- 函数体:执行的操作
- 返回值:将结果返回给调用者
- 函数的优势:
- 避免重复代码
- 提高代码可读性
- 便于维护和调试
- 模块化设计,分解复杂问题
- 所有语言的函数思想相同:只是语法细节有差异。
现在我们已经掌握了编程的三个核心基础:
- 变量(存放数据)
- 控制流(控制执行顺序)
- 函数(组织代码块)
接下来,我们可以讨论数据结构——如何组织和管理多个数据。比如,如何管理一个班级所有学生的成绩?这就要用到列表(数组)、字典(对象)等。
我们已经理解了变量、控制流和函数的基本概念。现在让我们进入编程中最有趣、最实用的部分——数据结构。
第十九课:为什么需要数据结构?——从单个盒子到储物柜
到目前为止,我们处理的都是单个变量:
python
student1 = "张三" student2 = "李四" student3 = "王五"
但想象一下,如果一个班有50个学生呢?我们要创建50个变量吗?这显然不现实。我们需要一种方式来组织和管理一组相关的数据。
这就是数据结构的用武之地。它就像从单个“盒子”升级到“储物柜”、“书架”或“文件柜”。
第二十课:最简单的数据结构——列表(数组)
第一步:理解列表——一排编号的盒子
列表就像一个一排有编号的储物柜:
- 每个格子可以放一样东西
- 格子有编号(索引),从0开始
- 可以随时往里面放东西或取东西
python
# 创建一个空列表 empty_list = [] # 创建一个有初始内容的列表 students = ["张三", "李四", "王五", "赵六"]
想象一下这4个名字分别放在储物柜的0、1、2、3号格子里。
第二步:访问列表元素——通过编号找到格子
python
# 获取第一个学生(索引从0开始!) first_student = students[0] print(first_student) # 输出:张三 # 获取第三个学生 third_student = students[2] print(third_student) # 输出:王五
第三步:修改列表内容——替换格子里的东西
python
# 修改第二个学生的名字 students[1] = "李四四" # 注意:索引1是第二个元素 print(students) # 输出:['张三', '李四四', '王五', '赵六']
第四步:列表的基本操作
python
# 1. 添加元素到末尾
students.append("孙七")
print(students) # ['张三', '李四四', '王五', '赵六', '孙七']
# 2. 插入元素到指定位置
students.insert(1, "钱八") # 插入到索引1的位置
print(students) # ['张三', '钱八', '李四四', '王五', '赵六', '孙七']
# 3. 删除元素
students.remove("王五") # 删除指定元素
del students[0] # 删除索引0的元素
print(students) # ['钱八', '李四四', '赵六', '孙七']
# 4. 获取列表长度
count = len(students)
print(f"现在有{count}个学生") # 现在有4个学生
第五步:列表的遍历——检查每个格子
python
# 方法1:直接遍历元素
for student in students:
print(f"学生:{student}")
# 方法2:同时获取索引和元素
for i, student in enumerate(students):
print(f"第{i}号学生:{student}")
第二十一课:键值对结构——字典(对象/映射)
列表很好,但有时候我们不想用数字编号,而想用有意义的名字来找东西。就像现实中的字典:通过”单词”查找”解释”。
第一步:理解字典——有标签的储物柜
字典就像一个储物柜,但每个格子都有自己的名字标签(键),而不是数字编号。
python
# 创建一个字典存储学生信息
student_info = {
"name": "张三",
"age": 18,
"score": 95,
"class": "三年级二班"
}
第二步:访问字典元素——通过标签找到格子
python
# 通过键(key)获取值(value)
name = student_info["name"]
age = student_info["age"]
print(f"姓名:{name},年龄:{age}")
# 安全的获取方式(避免键不存在时报错)
score = student_info.get("score", 0) # 如果"score"不存在,返回0
第三步:修改和添加字典元素
python
# 修改已有键的值 student_info["score"] = 98 # 添加新的键值对 student_info["gender"] = "男" print(student_info)
第四步:字典的遍历
python
# 遍历所有键
for key in student_info:
print(f"键:{key},值:{student_info[key]}")
# 同时遍历键和值
for key, value in student_info.items():
print(f"{key}: {value}")
第二十二课:集合——没有重复的袋子
有时候我们只关心东西在不在袋子里,不关心顺序,也不允许重复。这就是集合。
python
# 创建一个集合
unique_numbers = {1, 2, 3, 4, 5}
print(unique_numbers)
# 添加元素
unique_numbers.add(6)
unique_numbers.add(3) # 重复的不会添加
print(unique_numbers) # {1, 2, 3, 4, 5, 6}
# 集合运算(像数学中的集合)
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
print(set_a | set_b) # 并集:{1, 2, 3, 4, 5, 6}
print(set_a & set_b) # 交集:{3, 4}
print(set_a - set_b) # 差集:{1, 2}
第二十三课:数据结构的选择——用什么工具解决什么
| 数据结构 | 比喻 | 适用场景 | 特点 |
|---|---|---|---|
| 列表/数组 | 一排编号的储物柜 | 有序的数据集合,需要按位置访问 | 有顺序,可重复,通过索引访问 |
| 字典/对象 | 有标签的储物柜 | 键值对数据,通过名字快速查找 | 无顺序(Python 3.7+有序),键唯一 |
| 集合 | 不重复的袋子 | 检查成员是否存在,去重,集合运算 | 无序,元素唯一 |
| 元组 | 上锁的盒子 | 固定不变的数据集合 | 一旦创建不能修改 |
元组示例(Python中不可变的列表):
python
# 创建元组 coordinates = (10, 20) print(coordinates[0]) # 10 # coordinates[0] = 5 # 错误!元组不能修改
第二十四课:不同语言中的数据结构
Python
python
# 列表
numbers = [1, 2, 3]
# 字典
person = {"name": "Alice", "age": 25}
# 集合
unique = {1, 2, 3}
# 元组
point = (10, 20)
JavaScript
javascript
// 数组(类似Python列表)
let numbers = [1, 2, 3];
// 对象(类似Python字典)
let person = {name: "Alice", age: 25};
// 集合(ES6新增)
let unique = new Set([1, 2, 3, 3]); // 自动去重:{1, 2, 3}
Java
java
// 数组
int[] numbers = {1, 2, 3};
// 列表(ArrayList)
import java.util.ArrayList;
ArrayList<String> students = new ArrayList<>();
students.add("张三");
// 映射(HashMap,类似字典)
import java.util.HashMap;
HashMap<String, Integer> scores = new HashMap<>();
scores.put("张三", 95);
// 集合(HashSet)
import java.util.HashSet;
HashSet<Integer> uniqueNumbers = new HashSet<>();
uniqueNumbers.add(1);
C语言
c
// 数组(固定大小)
int numbers[5] = {1, 2, 3, 4, 5};
// 结构体(struct,类似简单对象)
struct Student {
char name[50];
int age;
float score;
};
struct Student s1;
strcpy(s1.name, "张三");
s1.age = 18;
// C没有内置的字典、集合,需要自己实现或使用第三方库
第二十五课:数据结构实战——学生成绩管理系统
让我们用学到的数据结构来构建一个小系统:
python
# 用字典存储班级信息,每个学生也是一个字典
class_3_2 = {
"students": [
{
"id": 1,
"name": "张三",
"scores": {"math": 95, "english": 88, "chinese": 92}
},
{
"id": 2,
"name": "李四",
"scores": {"math": 87, "english": 91, "chinese": 85}
}
],
"teacher": "王老师",
"class_name": "三年级二班"
}
# 计算每个学生的平均分
for student in class_3_2["students"]:
scores = student["scores"].values() # 获取所有分数
average = sum(scores) / len(scores)
student["average"] = average # 添加平均分到学生信息中
print(f"{student['name']}的平均分:{average:.1f}")
# 查找特定学生
def find_student_by_name(students, name):
for student in students:
if student["name"] == name:
return student
return None
zhangsan = find_student_by_name(class_3_2["students"], "张三")
if zhangsan:
print(f"找到学生:{zhangsan['name']},数学成绩:{zhangsan['scores']['math']}")
第二十六课:数据结构的思维体操
练习1:统计单词出现次数
python
text = "苹果 香蕉 苹果 橙子 香蕉 苹果 葡萄"
words = text.split() # 分割成单词列表
# 方法1:使用字典统计
word_count = {}
for word in words:
if word in word_count:
word_count[word] += 1
else:
word_count[word] = 1
print(word_count) # {'苹果': 3, '香蕉': 2, '橙子': 1, '葡萄': 1}
# 方法2:使用集合和列表方法
unique_words = set(words)
for word in unique_words:
print(f"{word}出现了{words.count(word)}次")
练习2:列表推导式(Python特有,但思想通用)
python
# 传统方法:筛选出所有偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = []
for num in numbers:
if num % 2 == 0:
even_numbers.append(num)
# 列表推导式:一行代码完成
even_numbers_v2 = [num for num in numbers if num % 2 == 0]
print(even_numbers_v2) # [2, 4, 6, 8, 10]
# 创建平方数列表
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
教学总结:数据结构的核心概念
- 组织数据的重要性:当数据量变大时,需要结构化的方式来管理。
- 核心数据结构三剑客:
- 列表/数组:有序集合,适合按位置访问
- 字典/对象:键值对,适合快速查找
- 集合:无序唯一集合,适合去重和成员检查
- 选择合适的数据结构:
- 需要保持顺序吗?→ 列表
- 需要通过名字快速查找吗?→ 字典
- 需要确保没有重复吗?→ 集合
- 组合使用:现实中的数据结构往往是嵌套的,比如列表中的字典,字典中的列表。
- 语言间的差异:
- Python的列表和字典非常灵活
- Java需要明确指定类型
- C语言需要自己管理更多细节
- JavaScript的对象和数组很灵活
现在我们已经掌握了编程的四个核心基础:
- 变量(存放数据)
- 控制流(控制执行顺序)
- 函数(组织代码块)
- 数据结构(组织数据)
这四者构成了编程的基础。掌握了这些,你已经能够解决很多实际问题了!
接下来我们可以讨论文件操作和异常处理(如何与外部世界交互)。
文件操作和异常处理:与外部世界的安全交互
第二十七课:为什么需要文件操作和异常处理?
到目前为止,我们的程序都在内存中运行。但内存是临时存储——程序关闭,数据就没了。这就像在黑板上写字,一擦就没了。
而文件是持久存储——就像把重要信息写在本子上,可以长期保存。
但和外部世界(文件、网络、用户)交互时,总会有意外发生:
- 文件可能不存在
- 磁盘可能满了
- 网络可能断开
- 用户可能输入错误数据
没有准备好的程序会直接崩溃。我们需要两样东西:
- 文件操作:读写持久化数据
- 异常处理:优雅地应对意外
第二十八课:文件操作基础——读和写
第一步:理解文件——电脑里的笔记本
一个文件就像一本笔记本:
- 可以写(记录信息)
- 可以读(查看信息)
- 可以追加(在末尾添加新信息)
第二步:Python的文件操作三部曲
基本模式:
# 1. 打开笔记本(指定要操作哪本笔记本,以及怎么操作)
file = open("notes.txt", "w", encoding="utf-8")
# 2. 操作笔记本
file.write("今天学习编程\n")
file.write("学会了变量和函数\n")
# 3. 合上笔记本(非常重要!不然会丢失内容)
file.close()
文件模式说明:
"r":只读(Read)——只能看,不能改"w":写入(Write)——从头开始写,会覆盖原来的内容"a":追加(Append)——在末尾添加,不覆盖"r+":读写(Read+Write)——既能看又能改
第三步:安全地操作文件——使用with语句
手动关文件很麻烦,而且容易忘记。Python提供了更安全的方式:
# 使用with语句,文件会自动关闭
with open("notes.txt", "w", encoding="utf-8") as file:
file.write("第一行内容\n")
file.write("第二行内容\n")
# 离开with代码块后,文件自动关闭
第四步:读取文件内容
# 读取整个文件
with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
print("整个文件内容:")
print(content)
# 逐行读取(更常用)
with open("notes.txt", "r", encoding="utf-8") as file:
print("逐行读取:")
for line in file:
print(f"行内容:{line.strip()}") # strip()去掉换行符
第五步:实际应用——学生数据保存
# 保存学生数据到文件
students = [
{"name": "张三", "score": 95},
{"name": "李四", "score": 88},
{"name": "王五", "score": 92}
]
# 写入文件
with open("students.txt", "w", encoding="utf-8") as file:
for student in students:
# 把每个学生写成一行:姓名,成绩
line = f"{student['name']},{student['score']}\n"
file.write(line)
# 从文件读取
with open("students.txt", "r", encoding="utf-8") as file:
loaded_students = []
for line in file:
if line.strip(): # 跳过空行
name, score = line.strip().split(",")
loaded_students.append({
"name": name,
"score": int(score) # 转换为整数
})
print("从文件加载的学生:")
for student in loaded_students:
print(f"{student['name']}: {student['score']}")
第二十九课:异常处理——当意外发生时
第一步:什么是异常?
异常就是程序运行时发生的意外情况,比如:
- 除以零:
10 / 0 - 文件不存在:
open("不存在的文件.txt") - 列表索引越界:
list[10](列表只有3个元素) - 类型错误:
"abc" + 123(字符串不能加数字)
没有异常处理,程序遇到异常会直接崩溃,显示红色错误信息。
第二步:Python的异常处理——try-except
# 没有异常处理(会崩溃)
number = int(input("请输入数字:")) # 如果输入"abc",程序崩溃
# 有异常处理(优雅处理)
try:
number = int(input("请输入数字:"))
print(f"你输入的数字是:{number}")
except ValueError: # 专门处理值错误
print("错误:请输入有效的数字!")
第三步:处理多种异常
try:
# 可能出错的操作1
num1 = int(input("请输入被除数:"))
# 可能出错的操作2
num2 = int(input("请输入除数:"))
# 可能出错的操作3
result = num1 / num2
print(f"结果是:{result}")
except ValueError:
print("错误:请输入有效的数字!")
except ZeroDivisionError:
print("错误:除数不能为零!")
except Exception as e: # 捕获所有其他异常
print(f"发生了未知错误:{type(e).__name__} - {e}")
第四步:完整的异常处理结构
try:
# 尝试执行这些代码
file = open("data.txt", "r")
content = file.read()
number = int(content)
except FileNotFoundError:
print("文件不存在!")
except ValueError:
print("文件内容不是有效数字!")
else:
# 如果没有发生异常,执行这里
print(f"成功读取数字:{number}")
finally:
# 无论是否发生异常,都会执行这里
print("清理工作...")
# 通常在这里关闭文件、释放资源等
第五步:抛出异常——主动报告错误
def check_age(age):
"""检查年龄是否合法"""
if age < 0:
raise ValueError("年龄不能为负数!") # 主动抛出异常
if age > 150:
raise ValueError("年龄不能超过150岁!")
return True
# 使用
try:
check_age(-5)
except ValueError as e:
print(f"年龄检查失败:{e}")
第三十课:不同语言的文件操作对比
Python(最简单直观)
# 写文件
with open("data.txt", "w", encoding="utf-8") as f:
f.write("Hello, 世界!")
# 读文件
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
Java(需要更多代码)
import java.io.*;
public class FileExample {
public static void main(String[] args) {
// 写文件
try {
FileWriter writer = new FileWriter("data.txt");
writer.write("Hello, 世界!");
writer.close(); // 必须手动关闭
} catch (IOException e) {
System.out.println("写文件出错: " + e.getMessage());
}
// 读文件
try {
FileReader reader = new FileReader("data.txt");
BufferedReader br = new BufferedReader(reader);
String line = br.readLine();
System.out.println(line);
br.close();
} catch (IOException e) {
System.out.println("读文件出错: " + e.getMessage());
}
}
}
C语言(最底层,最麻烦)
#include <stdio.h>
int main() {
// 写文件
FILE *file = fopen("data.txt", "w");
if (file == NULL) {
printf("无法打开文件!\n");
return 1;
}
fprintf(file, "Hello, World!");
fclose(file); // 必须手动关闭
// 读文件
file = fopen("data.txt", "r");
if (file == NULL) {
printf("无法打开文件!\n");
return 1;
}
char buffer[100];
fgets(buffer, 100, file);
printf("%s", buffer);
fclose(file);
return 0;
}
JavaScript(Node.js环境)
const fs = require('fs');
// 写文件
fs.writeFile('data.txt', 'Hello, World!', 'utf8', (err) => {
if (err) {
console.error('写文件出错:', err);
return;
}
console.log('文件写入成功');
});
// 读文件(同步方式,简单示例)
try {
const content = fs.readFileSync('data.txt', 'utf8');
console.log(content);
} catch (err) {
console.error('读文件出错:', err);
}
第三十一课:不同语言的异常处理对比
Python
try:
result = 10 / 0
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"其他错误:{e}")
finally:
print("无论如何都会执行")
Java
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("不能除以零: " + e.getMessage());
} catch (Exception e) {
System.out.println("其他错误: " + e.getMessage());
} finally {
System.out.println("无论如何都会执行");
}
C语言(没有真正的异常处理)
C语言没有内建的异常处理,通常通过返回值判断:
#include <stdio.h>
int divide(int a, int b, int *result) {
if (b == 0) {
return -1; // 返回错误码
}
*result = a / b;
return 0; // 返回0表示成功
}
int main() {
int result;
if (divide(10, 0, &result) == 0) {
printf("结果是: %d\n", result);
} else {
printf("错误:除数不能为零!\n");
}
return 0;
}
JavaScript
try {
let result = 10 / 0;
if (!isFinite(result)) {
throw new Error("除以零了!");
}
console.log("结果是:", result);
} catch (error) {
console.log("捕获到错误:", error.message);
} finally {
console.log("无论如何都会执行");
}
第三十二课:实战项目——学生管理系统(文件持久化版)
让我们创建一个完整的学生管理系统,支持数据保存到文件:
import json # 使用JSON格式保存复杂数据
class StudentManager:
def __init__(self, filename="students.json"):
self.filename = filename
self.students = self.load_students()
def load_students(self):
"""从文件加载学生数据"""
try:
with open(self.filename, "r", encoding="utf-8") as file:
return json.load(file) # 从JSON格式读取
except FileNotFoundError:
print("文件不存在,创建新的空列表")
return []
except json.JSONDecodeError:
print("文件格式错误,创建新的空列表")
return []
except Exception as e:
print(f"加载数据时出错:{e}")
return []
def save_students(self):
"""保存学生数据到文件"""
try:
with open(self.filename, "w", encoding="utf-8") as file:
json.dump(self.students, file,
ensure_ascii=False, # 保证中文正常显示
indent=2) # 缩进,让文件更易读
print("数据保存成功!")
except Exception as e:
print(f"保存数据时出错:{e}")
def add_student(self):
"""添加学生"""
try:
name = input("请输入学生姓名:")
age = int(input("请输入学生年龄:"))
score = float(input("请输入学生成绩:"))
student = {
"name": name,
"age": age,
"score": score
}
self.students.append(student)
self.save_students()
print(f"添加学生 {name} 成功!")
except ValueError:
print("输入错误:年龄必须是整数,成绩必须是数字")
except Exception as e:
print(f"添加学生时出错:{e}")
def list_students(self):
"""显示所有学生"""
if not self.students:
print("暂无学生信息")
return
print("\n" + "="*40)
print("学生列表:")
print("="*40)
for i, student in enumerate(self.students, 1):
print(f"{i:2d}. 姓名:{student['name']:8s} "
f"年龄:{student['age']:3d} "
f"成绩:{student['score']:5.1f}")
print("="*40)
def run(self):
"""运行管理系统"""
while True:
print("\n=== 学生成绩管理系统 ===")
print("1. 添加学生")
print("2. 查看学生")
print("3. 删除学生")
print("4. 保存并退出")
try:
choice = input("请选择操作 (1-4): ")
if choice == "1":
self.add_student()
elif choice == "2":
self.list_students()
elif choice == "3":
self.delete_student()
elif choice == "4":
self.save_students()
print("谢谢使用,再见!")
break
else:
print("无效选择,请输入1-4之间的数字")
except KeyboardInterrupt:
print("\n程序被中断,正在保存数据...")
self.save_students()
break
except Exception as e:
print(f"发生错误:{e}")
def delete_student(self):
"""删除学生"""
self.list_students()
try:
index = int(input("请输入要删除的学生编号:")) - 1
if 0 <= index < len(self.students):
student = self.students.pop(index)
print(f"已删除学生:{student['name']}")
self.save_students()
else:
print("无效的学生编号")
except ValueError:
print("请输入有效的数字")
except Exception as e:
print(f"删除学生时出错:{e}")
# 启动系统
if __name__ == "__main__":
manager = StudentManager()
manager.run()
第三十三课:最佳实践和常见错误
1. 文件操作最佳实践
import os
def safe_file_operation(filename):
"""安全的文件操作示例"""
# 检查文件是否存在
if not os.path.exists(filename):
print(f"文件 {filename} 不存在")
return None
try:
# 检查文件大小(避免读取超大文件)
file_size = os.path.getsize(filename)
if file_size > 10 * 1024 * 1024: # 大于10MB
print(f"文件太大 ({file_size} bytes),可能影响性能")
return None
# 使用with语句确保文件关闭
with open(filename, "r", encoding="utf-8") as file:
return file.read()
except PermissionError:
print(f"没有权限读取文件 {filename}")
except UnicodeDecodeError:
print(f"文件编码错误,请检查文件格式")
except Exception as e:
print(f"读取文件时出错:{e}")
return None
2. 异常处理最佳实践
def get_user_input():
"""获取用户输入的最佳实践"""
while True:
try:
age = int(input("请输入年龄(0-120):"))
if 0 <= age <= 120:
return age
else:
print("年龄必须在0-120之间")
except ValueError:
print("请输入有效的数字")
except KeyboardInterrupt:
print("\n用户取消输入")
return None
except Exception as e:
print(f"发生未知错误:{e}")
# 可以记录日志,但不直接显示给用户
# logger.error(f"获取用户输入时出错: {e}")
return None
3. 避免的常见错误
# 错误1:忘记关闭文件
file = open("data.txt", "w")
file.write("一些内容")
# 忘记 file.close() # 可能导致数据丢失
# 错误2:捕获所有异常但不处理
try:
# 很多代码
pass
except:
pass # 静默失败,不知道发生了什么
# 错误3:在循环中重复打开关闭文件
for i in range(100):
with open("data.txt", "a") as f: # 每次循环都打开关闭
f.write(f"行 {i}\n") # 应该一次性打开,写入所有内容
# 更好的方式
with open("data.txt", "w") as f:
for i in range(100):
f.write(f"行 {i}\n")
第三十四课:思维体操
练习1:备份文件
def backup_file(source_path, backup_dir="backups"):
"""备份文件到指定目录"""
import os
import shutil
from datetime import datetime
try:
# 检查源文件是否存在
if not os.path.exists(source_path):
raise FileNotFoundError(f"源文件 {source_path} 不存在")
# 创建备份目录(如果不存在)
if not os.path.exists(backup_dir):
os.makedirs(backup_dir)
# 生成备份文件名(包含时间戳)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.basename(source_path)
backup_name = f"{filename}.backup_{timestamp}"
backup_path = os.path.join(backup_dir, backup_name)
# 复制文件
shutil.copy2(source_path, backup_path)
print(f"备份成功:{source_path} -> {backup_path}")
return True
except PermissionError:
print("错误:没有文件操作权限")
except Exception as e:
print(f"备份失败:{e}")
return False
练习2:配置文件读取器
def read_config(config_file="config.txt"):
"""读取配置文件"""
config = {}
try:
with open(config_file, "r", encoding="utf-8") as file:
for line_num, line in enumerate(file, 1):
line = line.strip()
# 跳过空行和注释
if not line or line.startswith("#"):
continue
# 解析键值对
if "=" in line:
key, value = line.split("=", 1)
key = key.strip()
value = value.strip()
config[key] = value
else:
print(f"警告:第{line_num}行格式错误:{line}")
except FileNotFoundError:
print(f"配置文件 {config_file} 不存在,使用默认配置")
except Exception as e:
print(f"读取配置文件时出错:{e}")
return config
# 使用示例
config = read_config()
print(f"服务器地址:{config.get('server', 'localhost')}")
print(f"端口:{config.get('port', '8080')}")
教学总结:文件操作和异常处理的核心
- 文件操作三步骤:
- 打开文件:指定文件名和模式
- 操作文件:读写内容
- 关闭文件:确保数据保存
- 异常处理四部分:
try:尝试执行的代码except:捕获和处理异常else:没有异常时执行finally:无论是否异常都执行
- 重要原则:
- 总是使用with语句操作文件
- 不要捕获所有异常而不处理
- 给用户友好的错误提示
- 记录重要的异常信息
- 跨语言差异:
- Python:异常处理最完善,文件操作最简单
- Java:强制异常处理,代码较繁琐
- C:没有真正的异常处理,需要手动检查
- JavaScript:异步操作需要特殊处理
你已经掌握了编程的核心基础! 现在你可以:
- 用变量存储数据
- 用控制流做决策和循环
- 用函数组织代码
- 用数据结构管理复杂数据
- 用文件操作保存数据
- 用异常处理应对错误
这些是编程的基石。接下来,你可以深入学习:面向对象编程



