第1章 1.3 变量、声明与作用域
上 一章我们折腾了半天开发者工具,终于能看懂浏览器在背后偷偷摸摸搞的那些事儿了——控制台打印、Network 抓包、Elements 审查,这些工具就像是给你的代码装了一双透视眼。但光会看还不够,咱们得学会「存放数据」,不然程序运行完啥都没留下,那跟看完电影就忘剧情有啥区别?
这一章我们要解决一个问题:怎么让电脑记住你的数据,并且想用的时候能随时调用? 学完之后,你就能写出真正「有记忆」的程序了。
🎯 开场 3 分钟:为什么要学这个?
场景引入
想象你去超市买东西。进门推了个购物车(变量),你往里面放了一瓶牛奶(数据),然后继续逛。如果不问收银台牛奶多少钱,你怎么知道车里放的是牛奶还是可乐?
程序也一样——你得先「声明」一个变量,告诉电脑「我要存东西了」,然后往里面放数据,之后才能取出来用。
痛点问题
你是不是遇到过这种情况:
- ❌ 写了个计算器,输入
a + b,结果出来个莫名其妙的数字 - ❌ 想修改变量值,结果 Python 报
NameErro\n\n\n\n\n\nr: name 'x' is not defined - ❌ 写了两个
count变量,不知道哪个覆盖了哪个
这些问题,全是变量和作用域没搞明白惹的祸。
学完能解决
- ✅ 正确声明和赋值变量
- ✅ 搞懂局部变量和全局变量的区别
- ✅ 写出不会互相「打架」的代码
🧱 基础 25 分钟:核心概念
1. 变量是什么?
生活类比:变量就像是一个带标签的收纳盒。你在盒子上贴个标签(变量名),里面放东西(数据)。下次想拿东西,直接喊标签名字就行。
为什么要用:程序运行需要记忆,变量就是记忆的载体。没有变量,你每写一个数字都要重复输入,太麻烦了。
怎么用:
# 声明一个变量,给它起个名字
name = "小明"
age = 18
price = 19.9
print(name)
print(age)
运行结果:
小明
18
name、age、price 就是变量名,= 是赋值符号,意思是「把右边的值放进左边的盒子里」。
注意!Python 的变量不需要声明类型,你直接写 name = "小明" 就 OK 了,计算机会自动记住这是字符串。比起 JavaScript 的 var/let/const,Python 简洁多了。
2. 变量命名规则(新手必看)
生活类比:变量名就像是给宠物起名字,总不能叫「汪汪 123」吧?虽然能叫,但听起来不太正经。
规则:
# ✅ 合法的变量名
user_name = "张三" # 下划线连接
userAge = 25 # 驼峰命名(Python不推荐但能用)
_private = "隐藏的" # 以下划线开头,有特殊含义
# ❌ 非法的变量名(会报错!)
# 2nd_place = "第二名" # 不能以数字开头
# user-name = "李四" # 不能用中划线
# user name = "王五" # 不能有空格
Python 惯例:Python 社区约定俗成用小写字母 + 下划线,比如 max_value、user_name。看到这种命名风格,你就知道这是正经 Python 代码。
3. 变量的数据类型(先混个脸熟)
Python 里变量有几种「类型」,先知道 3 个最常用的:
# 字符串 - 文字
greeting = "你好,世界"
# 整数 - 整数
count = 42
# 浮点数 - 小数
price = 19.99
print(type(greeting)) # <class 'str'>
print(type(count)) # <class 'int'>
print(type(price)) # <class 'float'>
type() 函数能查看一个变量的「类型」。这就好比收纳盒也分塑料盒、纸盒、玻璃盒——虽然都能装东西,但用途不同。
4. 赋值与修改变量
生活类比:你往盒子里放了个苹果,想换成香蕉?直接把苹果拿出来,放进香蕉就行了。变量赋值就是这样,覆盖式替换。
# 第一次赋值
score = 100
print(score) # 100
# 第二次赋值,覆盖掉第一次的值
score = 90
print(score) # 90
# 基于原来的值做修改
score = score + 10 # 相当于取出100,加10,再放回去
print(score) # 110
简写形式:
score = 100
score += 10 # 等价于 score = score + 10
print(score) # 110
5. 多个变量同时赋值
# 交换两个变量的值(经典面试题)
a = 1
b = 2
a, b = b, a # Python 特有语法,一行搞定交换
print(a, b) # 2 1
# 链式赋值(多个变量指向同一个值)
x = y = z = 0
print(x, y, z) # 0 0 0
6. 作用域:变量在哪儿「看得见」
生活类比:想象公司组织架构——部门内部的事,只有那个部门的人知道;全公司的事,所有人都能用。程序也一样,有些变量只能在一个函数里用,有些变量整个程序都能用。
全局变量 vs 局部变量
# 全局变量 - 定义在函数外面的变量
total = 1000 # 整个程序都能看见它
def calculate():
# 局部变量 - 只在函数内部有效
discount = 0.8
result = total * discount # 这里能用 total
print(f"函数内部:discount = {discount}")
calculate()
print(f"函数外部:total = {total}")
# print(discount) # ❌ 这行会报错!因为 discount 是局部变量
运行结果:
函数内部:discount = 0.8
函数外部:total = 1000
global 关键字:我要在函数里改全局变量
count = 0 # 全局变量
def increment():
global count # 声明我要用外面的 count
count += 1
print(f"函数里:count = {count}")
increment()
increment()
print(f"函数外:count = {count}")
运行结果:
函数里:count = 1
函数里:count = 2
函数外:count = 2
注意! global 虽香,但新手尽量少用,因为会让代码难调试。更好的做法是通过参数传递、返回值来处理。
🔥 实战 35 分钟:3 个递进的小项目
项目 1(5 分钟):个人信息存储与展示
场景:做一个简单的「名片生成器」,存储并展示个人信息。
完整代码:
# 名片信息
name = "李明"
job = "Python 讲师"
company = "代码大学"
email = "liming@codecollege.com"
years_experience = 5
# 打印名片
print("=" * 30)
print("【名片】")
print(f"姓名:{name}")
print(f"职位:{job}")
print(f"公司:{company}")
print(f"邮箱:{email}")
print(f"工龄:{years_experience} 年")
print("=" * 30)
预期输出:
==============================
【名片】
姓名:李明
职位:Python 讲师
公司:代码大学
邮箱:liming@codecollege.com
工龄:5 年
==============================
解释:我们把个人信息存进变量,然后用 f-string(格式化字符串)把它们拼到一句话里。f"姓名:{name}" 的 {name} 会被变量的实际值替换。
项目 2(15 分钟):学生成绩统计
场景:读取一份学生成绩数据,计算平均分、最高分、最低分。
完整代码:
# 学生成绩数据(模拟从 CSV 读取的效果)
scores = [85, 92, 78, 96, 67, 88, 73, 95, 81, 70]
# 统计数据
total = sum(scores) # 总分
average = total / len(scores) # 平均分
max_score = max(scores) # 最高分
min_score = min(scores) # 最低分
# 找出最高分和最低分对应的学生(假设学号就是索引+1)
top_student = scores.index(max_score) + 1
bottom_student = scores.index(min_score) + 1
# 打印报告
print("【期末成绩统计报告】")
print(f"参赛人数:{len(scores)} 人")
print(f"平均分:{average:.2f} 分") # :.2f 表示保留两位小数
print(f"最高分:{max_score} 分(学号:{top_student})")
print(f"最低分:{min_score} 分(学号:{bottom_student})")
print(f"成绩分布:{scores}")
预期输出:
【期末成绩统计报告】
参赛人数:10 人
平均分:82.50 分
最高分:96 分(学号:4)
最低分:67 分(学号:5)
成绩分布:[85, 92, 78, 96, 67, 88, 73, 95, 81, 70]
解释:这个项目展示了变量的实际用途——把零散的数据存进列表,用 sum()、max()、min() 这些函数做统计。变量 total、average 存储的是「计算结果」,方便后续使用和打印。
项目 3(15 分钟):待办事项管理器
场景:做一个命令行待办清单,能添加、查看、完成事项。
完整代码:
# 待办清单数据
todos = []
def show_menu():
print("\n【待办清单 v1.0】")
print("1. 查看待办")
print("2. 添加待办")
print("3. 完成待办")
print("4. 退出")
def add_todo():
item = input("请输入新事项:")
todos.append(item)
print(f"✅ 已添加:{item}")
def show_todos():
if not todos:
print("📭 清单是空的")
else:
print(f"\n📋 共 {len(todos)} 项待办:")
for i, todo in enumerate(todos, 1):
print(f" {i}. {todo}")
def complete_todo():
show_todos()
if todos:
choice = int(input("请输入要完成的事项编号:"))
if 1 <= choice <= len(todos):
completed = todos.pop(choice - 1)
print(f"🎉 已完成:{completed}")
# 主程序循环
while True:
show_menu()
choice = input("请选择操作(1-4):")
if choice == "1":
show_todos()
elif choice == "2":
add_todo()
elif choice == "3":
complete_todo()
elif choice == "4":
print("👋 再见!")
break
else:
print("⚠️ 无效选择,请重试")
预期输出(交互示例):
【待办清单 v1.0】
1. 查看待办
2. 添加待办
3. 完成待办
4. 退出
请选择操作(1-4):2
请输入新事项:买牛奶
✅ 已添加:买牛奶
请选择操作(1-4):2
请输入新事项:写代码
✅ 已添加:写代码
请选择操作(1-4):1
📋 共 2 项待办:
1. 买牛奶
2. 写代码
请选择操作(1-4):3
1. 买牛奶
2. 写代码
请输入要完成的事项编号:1
🎉 已完成:买牛奶
请选择操作(1-4):4
👋 再见!
解释:todos 是全局变量,存储所有待办事项。add_todo() 用 append() 添加,complete_todo() 用 pop() 移除。列表是可变变量,所以在函数里直接修改 todos 是有效的。
💪 进阶 20 分钟:常见坑 + 性能小贴士
坑 1:变量未初始化就使用
# ❌ 错误示例
print(result) # 还没赋值就用,报错:NameError
result = 100
# ✅ 正确示例
result = 100
print(result) # 先赋值,后使用
坑 2:全局变量和局部变量混淆
# ❌ 错误示例
count = 10
def increment():
count = count + 1 # 这里 count 被当成局部变量,但还没赋值!
print(count)
increment() # 报错:UnboundLocalError
# ✅ 正确示例 1:用 global
count = 10
def increment():
global count
count = count + 1
print(count)
increment() # 11
# ✅ 正确示例 2:通过参数和返回值(推荐)
count = 10
def increment(val):
return val + 1
count = increment(count)
print(count) # 11
坑 3:变量名拼写错误(大小写敏感)
# ❌ 错误示例
UserName = "张三"
print(user_name) # 大小写不对,报错
# ✅ 正确示例
user_name = "张三"
print(user_name) # 正常
Python 的变量名是大小写敏感的,user_name 和 User_Name 是两个完全不同的变量!
坑 4:以为修改了全局变量(其实没有)
# ❌ 错误示例
greetings = ["你好", "hello"]
def add_greeting():
greetings.append("hola") # 这个确实改了全局变量
add_greeting()
print(greetings) # ['你好', 'hello', 'hola'] 改了?
# 但是这样:
def replace_greeting():
greetings = ["ni hao"] # 这是新建了一个局部变量!
replace_greeting()
print(greetings) # ['你好', 'hello', 'hola'] 没变!
# ✅ 正确做法:如果要重新赋值整个列表,用 global
def replace_greeting_correct():
global greetings
greetings = ["ni hao"]
replace_greeting_correct()
print(greetings) # ['ni hao']
记住:list.append()、list.remove() 这种原地修改的方法会影响到全局变量,但直接用 = 赋值是创建新局部变量。
坑 5:循环变量泄漏到全局
# ❌ 警告示例
for i in range(5):
print(i)
print(f"循环结束后 i = {i}") # i = 4,变量泄漏了!
# ✅ 正确做法:明确变量的作用域
def process():
for i in range(5):
print(i)
# i 只在函数内部有效
process()
# print(i) # 这里访问不到 i,安全!
调试技巧:print 大法
# 简单粗暴但有效的调试方法
def buggy_function(x, y):
print(f"进入函数:x={x}, y={y}") # 打印输入
result = x / y
print(f"计算结果:result={result}") # 打印中间结果
return result
buggy_function(10, 2)
# 输出:
# 进入函数:x=10, y=2
# 计算结果:result=5.0
print() 调试就像给程序加监控摄像头,哪里不对打哪里,简单但实用。
✏️ 练习题
练习 1(2 分钟):变量赋值
- 输入:无
- 预期输出:
Hello, Python! - 提示:
message变量存字符串,用print()打印
练习 2(2 分钟):计算圆的面积
- 输入:
radius = 5(半径) - 预期输出:
面积是 78.54(保留两位小数,π 取 3.14159) - 提示:面积公式
πr²,用f"{area:.2f}"格式化
练习 3(3 分钟):成绩等级判断
- 输入:
score = 85 - 预期输出:
等级是 B(90 以上 A,80-89 是 B,70-79 是 C,70 以下 D) - 提示:用
if/elif/else判断,在项目 2 的代码基础上改
练习 4(5 分钟):列表元素统计
- 输入:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - 预期输出:
奇数有 5 个,偶数有 5 个 - 提示:用循环遍历列表,if 判断奇偶,累加计数
练习 5(5 分钟):找出报错原因
- 输入:以下代码
def test():
value = 100
print(value)
print(value) # 这行报错
- 预期输出:说明为什么报错,如何修复
- 提示:作用域问题,
value是局部变量
作业:做一个「个人账本工具」
需求描述:命令行账本,能记录收入和支出,查询余额。
功能点:
1. 添加收入/支出(金额 + 说明)
2. 查看当前余额
3. 查看收支明细(列出所有记录)
4. 退出
加分项:
1. 收支记录带时间戳
2. 能删除某条记录
验收标准:
- 程序能正常运行
- 余额计算正确
- 代码有适当注释
提交方式:评论区贴代码或 GitHub 链接
📚 总结 + 资源
一句话总结:变量是程序的「记忆」,声明变量用 = 赋值,作用域决定变量在哪儿「看得见」——局部变量只在函数内有效,全局变量整个程序都能用。
延伸学习资源:
- Python 官方文档:数据模型-变量 —— 权威、全面,但有点枯燥
- 《Python编程:从入门到实践》第二章 —— 循序渐进,适合小白
- 视频:B站 - Python 变量与数据类型 —— 视觉化学习更友好
互动钩子:你在写代码时,因为变量作用域踩过什么坑?是全局变量被覆盖了,还是局部变量取不出来?评论区聊聊,老粉优先回复!
💡 下章剧透:学会了存放数据,下一章我们要聊聊这些数据都有哪些「类型」——字符串、数字、布尔值……还有它们之间怎么互相转换。数据类型搞错了,程序会闹笑话的哦~

评论(0)