我们为什么需要“变量”?
本文最后更新于15 天前,其中的信息可能已经过时,如有错误请发送邮件到184874483@qq.com

完全从零开始。忘掉所有语言的名字,像第一次观察世界一样,来认识编程中最基础、最重要的概念——变量

第一课:我们为什么需要“变量”?

想象一个简单的任务:请你计算 (5 + 3) * 2 的结果。

你心算一下,得到 16。程序可以写成:

print( (5 + 3) * 2 )

直接写数字,也能完成。

但现实世界要复杂得多。比如,我们要计算一个会变化的东西,比如用户的游戏分数

第一局,用户得了 5 分。
第二局,他又得了 3 分。
我们想计算他的总分,再奖励双倍。

如果直接写数字:

# 第一局后
total = 5
# 第二局后,我们需要把新的分数 3 加进去... 怎么办?
# 我们无法修改 “5” 这个数字本身。

你会发现,写死的数字(比如 5)是“死”的,它无法记录变化的状态。我们需要的,是一个可以存放会变化的数据的容器。

这个容器,就是 “变量”


第二课:用现实世界理解变量——“标签”和“盒子”

这是理解变量的最佳比喻:

  1. 变量是一个“盒子”:在计算机的内存里,开辟出一个小空间,用来存放数据(一个数字、一段文字等)。
  2. 变量名是“标签”:我们给这个盒子贴上一个独一无二的标签(比如 score),这样我们就不用记住盒子在内存中复杂难记的“地址”(比如 0x7ffeeb4c),而只要通过这个友好的标签名,就能找到它,并使用里面的数据。

核心操作只有三个:

  1. 创建盒子并贴标签(声明/定义变量)
  2. 往盒子里放东西(赋值)
  3. 看着标签,说出盒子里是什么(使用变量的值)

第三课:动手体验——用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 如果没有其他标签指向它,就会被计算机的清洁工(垃圾回收机制)清理掉。

重点:标签(变量名)永远指向最新的那个值。


第四课:变量的“变”与“不变”

  1. 什么在“变”?
    • 标签所指向的 “值” 可以变。score 可以从 100 变成 150
    • 这个能力,让我们能够记录变化的状态(比如不断增加的游戏分数、实时变化的股价)。
  2. 什么“不变”?
    • 标签(变量名)本身的意义 在程序运行中最好不变。score 就应该始终代表“分数”,如果你突然让它代表“用户名”,就会让读代码的人(包括未来的你自己)非常困惑。
    • 编程好习惯:给变量起一个清晰、有意义的名字。
      • x -> score (不好 vs 好)
      • n -> student_count (不好 vs 好)
      • a -> is_logged_in (不好 vs 好)

第五课:一个思维体操

看这段代码,猜猜最后 ab 的值是什么?

a = 10
b = 20
a = b

不要往下看,先在心里想一个答案。

解析:

  1. a = 10:标签 a 指向盒子 10
  2. b = 20:标签 b 指向盒子 20
  3. 关键步骤 a = b:这行代码的意思是 “让标签a指向标签b当前指向的那个东西”
    • 计算机先去找 b 指向什么?找到了,是 20
    • 然后,把标签 a 从原来的 10 上撕下来,贴到 20 这个盒子上。
    • 所以最终结果是:ab 现在都指向了同一个值 20
    • 盒子 10 现在没有标签了,会被清理。

用图像表示:

初始: a → 10, b → 20
执行 a = b 后: a ↘
                20
              b ↗

所以,最后 print(a)print(b) 都会输出 20


小结:我们目前学了什么?

  1. 变量是什么:一个可以存放变化数据的、有名字的容器(盒子+标签)。
  2. 核心价值:用来记录和跟踪程序运行中变化的状态。
  3. 核心操作
    • 变量名 = 值:赋予变量一个值(贴标签,放东西)。
    • 使用 变量名:获取它当前代表的值(看标签,找东西)。
  4. 最重要的概念
    • = 是“赋值”操作(放进去/指向),不是数学等号。
    • 变量名应该清晰易懂。

这个基础认知,适用于几乎所有的编程语言。 就像学会了“开车”的基本原理(方向盘、油门、刹车),无论换什么牌子的车,你都能快速上手。不同语言只是在这些盒子的“材质”(类型)、贴标签的“规矩”(语法)上有所不同。


如果这个概念已经清晰了,我们就可以进入下一个最自然的问题:“我们可以往这个‘盒子’里放哪些不同种类的‘东西’?” —— 也就是 “数据类型”

第一课:盒子里能放什么?——认识“数据类型”

上一课我们把变量比作一个盒子。现在我们要问:盒子里能放哪些东西?

在现实生活中,盒子可以放书、放水果、放衣服。在编程世界里,盒子(变量)里能放的东西也有不同的种类,我们称之为 “数据类型”

为什么要有数据类型?

  1. 合理分配空间:就像冰箱放食物,衣柜放衣服,不同的东西需要不同大小的空间。数字、文字、真假值,它们在计算机内存中占用的空间是不同的。
  2. 规定能做什么操作:数字可以进行加减乘除,文字可以进行拼接、查找,真假值可以进行逻辑判断。不同类型的数据,能进行的操作是不同的。

第二课:基本数据类型初识

我们先用一种最直观的分类,来看最常见的几种数据类型。不要怕,我们先只看三种最基础的。

1. 整数(Integer)

  • 是什么:没有小数部分的数字。比如:-501002024
  • 能做什么:加减乘除、比较大小等数学运算。
  • 例子:游戏分数、年龄、数量。

python

# 在Python中,整数用 int 表示
score = 100
age = 18

2. 浮点数(Floating-point number)

  • 是什么:有小数部分的数字。比如:3.14-0.52.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”无法转换成整数。


小结:数据类型我们学了什么?

  1. 数据类型是什么:变量盒子里能放的不同种类的东西(整数、浮点数、字符串等)。
  2. 为什么要有类型
    • 合理利用内存空间。
    • 规定数据能进行的操作。
  3. 两大类型系统
    • 动态类型(如Python):变量可以随时改变类型,灵活但可能隐藏错误。
    • 静态类型(如C/Java):变量必须先声明类型,安全但不够灵活。
  4. 常见类型
    • 整数(int)、浮点数(float)、字符串(str)是三个最基础的类型。
    • 布尔值(bool)用于逻辑判断。
    • 列表(list)用于存放多个数据。
  5. 类型转换:可以在一定条件下将一种类型转换为另一种。

重要理念:数据类型是数据的“分类”,不同的类型有不同的用途和操作方式。在编程时,要时刻注意你正在处理的数据是什么类型,就像在生活中要知道你手里拿的是水果还是书本一样。


接下来,我们可以继续探讨:当数据有了类型,我们如何用它们进行更复杂的操作?比如,如何把数据组合起来?如何根据不同的数据做出判断?——这就是 “数据结构” 和 “控制流” 的开始了。

好的!我们继续按照这个思路,循序渐进地学习。现在我们已经理解了变量是存放数据的“盒子”,接下来自然会问:“这些盒子在程序里是怎么互动、怎么决定程序走向的?”

这就引出了编程的另一个核心概念——控制流


第六课:让程序“活”起来——控制流的基本思想

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

循环:
    重复执行某些代码
    直到条件不再满足

教学总结:控制流的核心概念

  1. 顺序执行是基础:默认情况下,代码从上到下一条条执行。
  2. 分支让程序有选择
  • if/elif/else 根据条件选择不同路径
  • 条件必须是能得出True/False的问题
  1. 循环让程序能重复
  • for 循环:知道要重复多少次时使用
  • while 循环:不知道具体次数,只知道条件时使用
  • 小心无限循环!
  1. 嵌套是常态:条件中可以嵌套循环,循环中可以嵌套条件,就像俄罗斯套娃。
  2. 所有语言大同小异:掌握了一种语言的控制流,其他语言只是语法不同,逻辑完全相通。

现在我们已经学会了:

  1. 变量(存放数据的盒子)
  2. 控制流(让程序做选择和重复)

接下来很自然的问题是:“当我们的代码越来越长,怎么避免重复写同样的代码段?怎么组织代码让它更清晰?” 这就引出了 函数(Function) 的概念。

第十一课:为什么要用函数?——避免重复劳动

想象一下,你每天早上都要做同样的事情:

  1. 起床
  2. 刷牙
  3. 吃早餐
  4. 出门

如果让你写一个“早上例行程序”的代码,你可能会这样写:

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} 是奇数")

教学总结:函数的核心概念

  1. 函数的目的是封装代码:将一段常用的代码打包,便于重复使用和组织。
  2. 函数的基本结构
    • 函数名:用来调用函数
    • 参数:让函数可以接受外部数据
    • 函数体:执行的操作
    • 返回值:将结果返回给调用者
  3. 函数的优势
    • 避免重复代码
    • 提高代码可读性
    • 便于维护和调试
    • 模块化设计,分解复杂问题
  4. 所有语言的函数思想相同:只是语法细节有差异。

现在我们已经掌握了编程的三个核心基础:

  1. 变量(存放数据)
  2. 控制流(控制执行顺序)
  3. 函数(组织代码块)

接下来,我们可以讨论数据结构——如何组织和管理多个数据。比如,如何管理一个班级所有学生的成绩?这就要用到列表(数组)、字典(对象)等。

我们已经理解了变量、控制流和函数的基本概念。现在让我们进入编程中最有趣、最实用的部分——数据结构

第十九课:为什么需要数据结构?——从单个盒子到储物柜

到目前为止,我们处理的都是单个变量:

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]

教学总结:数据结构的核心概念

  1. 组织数据的重要性:当数据量变大时,需要结构化的方式来管理。
  2. 核心数据结构三剑客
    • 列表/数组:有序集合,适合按位置访问
    • 字典/对象:键值对,适合快速查找
    • 集合:无序唯一集合,适合去重和成员检查
  3. 选择合适的数据结构
    • 需要保持顺序吗?→ 列表
    • 需要通过名字快速查找吗?→ 字典
    • 需要确保没有重复吗?→ 集合
  4. 组合使用:现实中的数据结构往往是嵌套的,比如列表中的字典,字典中的列表。
  5. 语言间的差异
    • Python的列表和字典非常灵活
    • Java需要明确指定类型
    • C语言需要自己管理更多细节
    • JavaScript的对象和数组很灵活

现在我们已经掌握了编程的四个核心基础:

  1. 变量(存放数据)
  2. 控制流(控制执行顺序)
  3. 函数(组织代码块)
  4. 数据结构(组织数据)

这四者构成了编程的基础。掌握了这些,你已经能够解决很多实际问题了!

接下来我们可以讨论文件操作和异常处理(如何与外部世界交互)。

文件操作和异常处理:与外部世界的安全交互

第二十七课:为什么需要文件操作和异常处理?

到目前为止,我们的程序都在内存中运行。但内存是临时存储——程序关闭,数据就没了。这就像在黑板上写字,一擦就没了。

而文件是持久存储——就像把重要信息写在本子上,可以长期保存。

但和外部世界(文件、网络、用户)交互时,总会有意外发生:

  • 文件可能不存在
  • 磁盘可能满了
  • 网络可能断开
  • 用户可能输入错误数据

没有准备好的程序会直接崩溃。我们需要两样东西:

  1. 文件操作:读写持久化数据
  2. 异常处理:优雅地应对意外

第二十八课:文件操作基础——读和写

第一步:理解文件——电脑里的笔记本

一个文件就像一本笔记本:

  • 可以(记录信息)
  • 可以(查看信息)
  • 可以追加(在末尾添加新信息)

第二步: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')}")

教学总结:文件操作和异常处理的核心

  1. 文件操作三步骤
  • 打开文件:指定文件名和模式
  • 操作文件:读写内容
  • 关闭文件:确保数据保存
  1. 异常处理四部分
  • try:尝试执行的代码
  • except:捕获和处理异常
  • else:没有异常时执行
  • finally:无论是否异常都执行
  1. 重要原则
  • 总是使用with语句操作文件
  • 不要捕获所有异常而不处理
  • 给用户友好的错误提示
  • 记录重要的异常信息
  1. 跨语言差异
  • Python:异常处理最完善,文件操作最简单
  • Java:强制异常处理,代码较繁琐
  • C:没有真正的异常处理,需要手动检查
  • JavaScript:异步操作需要特殊处理

你已经掌握了编程的核心基础! 现在你可以:

  1. 用变量存储数据
  2. 用控制流做决策和循环
  3. 用函数组织代码
  4. 用数据结构管理复杂数据
  5. 用文件操作保存数据
  6. 用异常处理应对错误

这些是编程的基石。接下来,你可以深入学习:面向对象编程

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇