查看全课大纲(第 27 / 51 节)
  1. 1.为什么人人都该学点编程?
  2. 2.计算机与程序设计:你的电脑到底在“想”什么?
  3. 3.Python 这门语言,到底有什么魔力?
  4. 4.Python 开发环境配置:如何拥有你的第一个“编程工具箱”?
  5. 5.如何安装一个更强大的代码编辑器?
  6. 6.汇率兑换1.0:你的第一个“钱生钱”小程序
  7. 7.你的第一行代码,藏着哪些秘密?
  8. 8.汇率兑换2.0(上):让程序看懂“CNY”和“USD”
  9. 9.汇率兑换程序,如何让它“聪明”地判断币种?
  10. 10.汇率兑换程序能一直运行,直到我喊停吗?
  11. 11.汇率兑换4.0:如何把“算钱”功能打包成积木?
  12. 12.汇率兑换5.0:给你的程序穿上“结构化”的西装
  13. 13.怎么用 Python 画一个会动的五角星?
  14. 14.如何让程序自动画出不同大小的五角星?
  15. 15.函数自己调用自己,会发生什么?
  16. 16.用递归画出神奇的分形树
  17. 17.Python 怎么计算你一天躺着不动能消耗多少热量?
  18. 18.如何让程序“活”起来,持续为你服务?
  19. 19.如何让 BMR 计算器更“聪明”?
  20. 20.当程序遇到“不按套路出牌”的用户怎么办?
  21. 21.怎么用 Python 模拟一个“滚雪球”式的存钱计划?
  22. 22.如何用列表记录每一周的存款?
  23. 23.如何让程序自己数数?—— 用 for 循环解放你的双手
  24. 24.52周存钱挑战4.0:你的存款计算器能有多灵活?
  25. 25.52周存钱挑战:怎么根据日期自动查存款?
  26. 26.Python 怎么判断一年中的第几天?
  27. 27.列表 vs 元组:哪个更适合存储月份天数?
  28. 28.用集合给月份分个队,换个思路算天数
  29. 29.把月份和天数“锁”在一起:用字典给数据配个对
  30. 30.Python 怎么判断密码强弱?
  31. 31.Python 怎么给密码设置“防沉迷”系统?
  32. 32.Python 怎么把密码保存到文件里?
  33. 33.Python 怎么读取文件里的密码?
  34. 34.Python 怎么把密码检查工具“打包”起来?
  35. 35.Python 怎么把文件操作也“打包”起来?
  36. 36.计算机怎么“扔骰子”?——用Python模拟随机事件
  37. 37.如何用 Python 模拟掷两个骰子?
  38. 38.怎么用 Python 把骰子轨迹画出来?
  39. 39.骰子点数分布长啥样?用直方图一眼看穿!
  40. 40.用科学计算库让骰子程序“起飞”
  41. 41.空气质量指数怎么算?手把手教你写一个AQI计算器
  42. 42.空气质量指数计算:从零开始,让程序看懂空气
  43. 43.如何读取空气质量数据文件并找出空气质量最好的五个监测点?
  44. 44.JSON 数据怎么变成 Excel 表格?—— 让数据换个“马甲”
  45. 45.Python 怎么让程序自己判断文件类型?
  46. 46.如何让程序自己上网查空气质量?
  47. 47.用美味的汤来解析网页:Beautiful Soup 入门
  48. 48.如何让爬虫自动抓取全国所有城市的空气质量?
  49. 49.爬到的数据怎么存下来?—— 把全国空气质量数据保存为CSV文件
  50. 50.用 pandas 玩转空气质量数据:找出全国空气最好和最差的城市
  51. 51.空气质量数据怎么“洗”干净,还能画成图?

列表 vs 元组:哪个更适合存储月份天数?

约 10 分钟

小象实战讲义 · Python 入门:8 个小项目边玩边学

还记得上一节我们做的「日期计算器」吗?我们用一个「元组」来存储每个月的天数。今天我们要做一件特别酷的事:用「列表」替换掉「元组」。听起来只是换个容器?但你会发现,这个小小的改变,让我们的程序变得更灵活、更聪明了!

💡 核心导读

  • 本节只做一件事:把存储月份天数的「元组」换成「列表」
  • 为什么换:列表可以修改,元组不能修改——这个区别决定了我们写代码的方式
  • 会学到:如何写一个判断闰年的函数,让代码更整洁
  • 有趣发现:原来列表的「可变性」能让闰年判断变得如此简单
  • 最终成果:一个更优雅、更灵活的日期计算器

从臃肿到清爽:先给代码做个「瘦身」

在换容器之前,我们先看看上一节的代码。说实话,它有点「臃肿」——判断闰年的逻辑和计算天数的逻辑混在一起,看着不太舒服。

怎么让它变清爽呢?很简单:模块化!把判断闰年这个独立的功能,单独写成一个函数。

from datetime import datetime

def is_leap_year(year):
    """
    判断year是否为闰年
    是,返回True
    否,返回False
    """
    is_leap = False  # 先默认不是闰年
    
    # 闰年判断条件:四年一闰,百年不闰,四百年再闰
    if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
        is_leap = True  # 满足条件就改成True
        
    return is_leap  # 返回最终判断结果

# 测试一下我们的函数
print("2000年是闰年吗?", is_leap_year(2000))  # 应该是True
print("1900年是闰年吗?", is_leap_year(1900))  # 应该是False
print("2024年是闰年吗?", is_leap_year(2024))  # 应该是True
2000年是闰年吗? True
1900年是闰年吗? False
2024年是闰年吗? True

看到这个函数的妙处了吗?我们只用了一个变量 is_leap,先默认是 False(不是闰年),如果满足闰年条件就改成 True,最后返回这个变量的值。

这种写法只在函数末尾用一个 return 返回结果(称为「单一出口」),逻辑顺着一条线走下来,初学者读起来很清晰。它和在 if/else 里各写一个 return(提前返回)都是很常见的风格,没有绝对的高下之分;本课程为了方便你理解,统一采用这种单一出口的写法。

列表登场:可变的力量

好了,热身完毕!现在进入正题:用列表替换元组。

还记得元组的特点吗?一旦创建就不能修改。而列表正好相反:可以随时修改。这个区别,在我们处理闰年2月天数时,会带来完全不同的编程思路。

from datetime import datetime

def is_leap_year(year):
    """判断是否为闰年"""
    is_leap = False
    if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
        is_leap = True
    return is_leap

# 主程序开始
input_date_str = '2000/03/01'  # 原程序用input(),这里用固定值方便演示
input_date = datetime.strptime(input_date_str, '%Y/%m/%d')

year = input_date.year
month = input_date.month
day = input_date.day

# 关键变化在这里!用列表代替元组
days_in_month_list = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

# 如果是闰年,直接把2月的28天改成29天
if is_leap_year(year):
    days_in_month_list[1] = 29  # 列表索引从0开始,所以1代表2月

# 计算总天数:前面月份的天数总和 + 当月的天数
days = sum(days_in_month_list[:month - 1]) + day

print(f'{year}年{month}月{day}日是{year}年的第{days}天。')
2000年3月1日是2000年的第61天。

是不是很酷? 用列表后,处理闰年的逻辑变得超级简单:

  1. 先创建一个平年的月份天数列表(2月是28天)
  2. 如果是闰年,直接修改列表:days_in_month_list[1] = 29
  3. 然后正常计算天数

对比一下元组的做法:我们需要在计算时额外判断「如果是闰年且月份大于2,就加1天」。列表的方法更直观:我直接把数据改对,后面的计算就不用操心了。

列表 vs 元组:不只是「能不能改」

现在你知道了列表和元组最明显的区别:可变 vs 不可变。但它们的区别不止于此,了解这些能帮你更好地选择用哪个。

# 列表通常存放「相同类型」的数据
month_days_list = [31, 28, 31, 30]  # 全是数字,表示顺序(1月、2月...的天数)

# 元组通常存放「不同类型但相关」的数据,表示一个结构
person_info_tuple = ('张三', 25, '北京')  # 姓名、年龄、城市,构成一个人的信息

# 当然,Python很灵活,你也可以反着用(但不推荐)
mixed_list = [31, '二月', True]  # 能运行,但看着别扭
mixed_tuple = (31, 28, 31)  # 能运行,但更适合用列表

print("列表示例:", month_days_list)
print("元组示例:", person_info_tuple)
列表示例: [31, 28, 31, 30]
元组示例: ('张三', 25, '北京')

简单总结一下:

特性列表 (List)元组 (Tuple)
可变性✅ 可以修改❌ 创建后不能修改
典型用途相同类型数据的顺序集合不同类型数据的固定结构
表示什么顺序(如:1月、2月、3月…)结构(如:(姓名, 年龄, 城市))
语法方括号 []圆括号 ()(逗号是关键)

一个实用的选择原则:

  • 如果你的数据需要频繁修改,用列表
  • 如果你的数据是固定不变的(比如配置信息、坐标点),用元组
  • 如果你不确定,先用列表——以后需要不可变性时再改成元组

完整代码:优雅的日期计算器

让我们把所有的改进整合起来,看看2.0版本的完整代码:

from datetime import datetime

def is_leap_year(year):
    """
    判断year是否为闰年
    是,返回True
    否,返回False
    """
    is_leap = False
    
    if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
        is_leap = True
        
    return is_leap

def main():
    """
    主函数:计算某一天是当年的第几天
    """
    # 原程序用 input('请输入日期(yyyy/mm/dd):'),这里用固定值演示
    input_date_str = '2012/03/05'
    input_date = datetime.strptime(input_date_str, '%Y/%m/%d')
    
    year = input_date.year
    month = input_date.month
    day = input_date.day
    
    # 使用列表存储月份天数
    days_in_month_list = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    
    # 如果是闰年,修改2月的天数
    if is_leap_year(year):
        days_in_month_list[1] = 29
    
    # 计算总天数
    days = sum(days_in_month_list[:month - 1]) + day
    
    print(f'{year}年{month}月{day}日是{year}年的第{days}天。')

# 运行程序
main()
2012年3月5日是2012年的第65天。

验证一下:2012年是闰年,1月31天 + 2月29天 + 3月5天 = 65天,完全正确!

思维拓展:如果数据更多呢?

现在想象一下,如果我们要处理的不是12个月,而是:

  • 365天的每日天气数据
  • 1000个学生的成绩
  • 一年中每天的股票价格

用列表就太合适了!你可以随时:

  • 添加新数据:data.append(新值)
  • 修改错误数据:data[索引] = 新值
  • 删除无效数据:del data[索引]

这种灵活性在实际编程中非常有用。比如你写了一个游戏,用列表存储玩家的装备,玩家获得新装备就 append(),卖掉装备就删除,更换装备就修改——多方便!

📝 动手练一练

  1. 改一改,试一试:把上面的完整代码复制到你的Python环境中,把 input_date_str 的值改成你自己的生日,看看你的生日是那年的第几天?

  2. 列表的威力:假设你要记录一周7天的步数,用列表该怎么写?如果周三你多走了1000步,怎么修改这个列表?

👉 点击查看参考答案

第1题:直接把 input_date_str 改成你的生日日期就行,注意格式要是 yyyy/mm/dd。

# 把你的生日放在这里
input_date_str = '1995/08/20'  # 示例:1995年8月20日

第2题:用列表记录步数,并修改周三的数据。

# 记录一周步数:周一 ~ 周日
daily_steps = [5000, 6000, 7000, 5500, 8000, 3000, 4000]

print("原始步数:", daily_steps)

# 周三(索引2)多走了1000步
daily_steps[2] += 1000

print("修改后步数:", daily_steps)
print("周三走了", daily_steps[2], "步")

# 计算一周总步数
total_steps = sum(daily_steps)
print("一周总步数:", total_steps)
原始步数: [5000, 6000, 7000, 5500, 8000, 3000, 4000]
修改后步数: [5000, 6000, 8000, 5500, 8000, 3000, 4000]
周三走了 8000 步
一周总步数: 39500

看到列表的方便了吗?想改哪个数据,直接通过索引找到它,然后赋值就行!

本章小结

今天我们完成了一个重要的升级:用列表替换元组。虽然只是换了个容器,但带来的编程思路变化是巨大的:

📋 行动清单

  • 运行今天的完整代码,输入几个不同的日期,验证计算结果
  • 尝试修改代码:如果把列表改回元组,程序还能运行吗?试试看!
  • 思考一个场景:在你的生活或工作中,有哪些数据适合用列表存储?哪些适合用元组?

关键收获:

  1. 列表是可变的,创建后可以修改其中的元素
  2. 元组是不可变的,创建后就不能改了
  3. 列表适合存储同类型、需要修改的数据序列
  4. 元组适合存储不同类型、固定不变的数据结构
  5. 把独立功能写成函数(如 is_leap_year),能让代码更清晰、更易维护

列表的「可变性」就像给你的数据装上了「可调节旋钮」——需要的时候随时调整。而元组的「不可变性」则像给你的数据加了「保护锁」——确保它不会被意外修改。

下一节,我们要认识第三种容器:集合。它和数学里的集合概念很像,能帮我们解决一些列表和元组不太擅长的问题。比如:如何快速找出两个名单中重复的名字?集合有妙招!

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第6章代码包:判断第几天(含全部版本 4 个 .py)
    ZIP · 3KB
    下载
看图文没弄懂?展开看本节视频讲解(约 10 分钟)
📺 正在播放小象学院官方高清录播(支持倍速与清晰度调节)