Python基础语法练习题(59-原始版本与优化版本)

今天来记录一下第五十九题的内容,分了两个版本,一个是原始版本,一个是优化版本。

首先是原始版本:

复制代码
#编写一个程序,要求用户输入年份和月份,打印该月份对应的日历

#导入日历模块 calendar

import calendar

#提示用户输入年份并将其转换为整型

year = int(input('请输入年份:'))

#提示用户输入月份并将其转换为整型

month = int(input('请输入月份:'))

print(calendar.month(year, month))

这个代码非常简单,甚至有些简陋,下面是这个代码块的思路:

题目要求:用户输入年份和月份,打印该月对应的日历。

我的思路:造日历这事儿,早有人替我写好了

第一眼曾想过要不要自己算"某年某月1号是星期几、这个月有几天"------那得动用取余、闰年判断一堆数学。但立刻想起 48 题以来的老规矩:先翻翻标准库有没有轮子。果然有:calendar 模块,而且是 Python 自带、不用 pip 安装的官方轮子(和 58 题的 dateutil 那种第三方不同)。

程序短到就三步:问年份、问月份、交给 calendar.month()。前两步还是老熟人 int(input())------输入必须转整数才能进日历函数的"门槛";最后这个函数直接返回一张排版整齐的多行日历字符串,外面套一层 print 就是成品,星期表头、日期对齐全都不用我操心。

我发现的两个小彩蛋

一是 calendar.month() 是"哑巴"------它不打印,只返回字符串,所以我必须自己套 print;模块里另有个 prmonth(p 代表 print)会直接打印,两种风格二选一。二是它默认把星期一排在表头第一个,和国外周日开头的习惯不同,这背后是 Python 的"周从周一记起"约定。

隐患照旧:裸奔的输入

这题又双叒没做验证:输月份 13,calendar.month 会直接抛 IllegalMonthError 崩给你看。从 49 题验证码到 53 题区间、再到今天,"功能一行流、输入零防护"已是这批题目的通病。真要加固,43/44 题的 while True + try/except 加一条 1 <= month <= 12 的范围检查就是标准答案------模块轮子再好用,也替不了你把关进门输入。

接下来是优化版本:

复制代码
# 编写一个程序,要求用户输入年份和月份,打印该月份对应的日历(优化版)
# 优化点1:输入验证——非整数、越界年份/月份都不再崩溃,而是重新提示输入
# 优化点2:支持连续查询——打印完日历后可选择继续查询或退出程序

# 导入日历模块

import calendar

# 定义函数:反复询问直到用户输入一个合法整数(沿用43题 while True + try/except 模式)

def get_int(prompt):
    """
    获取用户输入并验证是否为整数
    :param prompt: 提示文字
    :return: 合法整数
    """
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            print('输入错误,请输入一个整数。')

# 定义函数:获取年份,并检查合理范围

def get_year():
    while True:
        year = get_int('请输入年份(如 2026):')
        if 1 <= year <= 9999:      # calendar 模块只支持有效年份,越界会报错
            return year
        print('年份越界,请输入 1 到 9999 之间的年份。')

# 定义函数:获取月份,并检查 1-12 范围(修复原版输 13 直接崩溃的缺陷)

def get_month():
    while True:
        month = get_int('请输入月份(1-12):')
        if 1 <= month <= 12:
            return month
        print('月份应在 1 到 12 之间,请重新输入。')

# 外层循环支撑多次查询(沿用56优化版的菜单常驻模式)

while True:

    year = get_year()
    month = get_month()

    print(calendar.month(year, month))

    choice = input('是否继续查询其他月份?(按 y 继续 / 按 n 结束):')
    if choice.lower() != 'y':
        break

print('感谢使用,再见!')

这个优化版本的代码量对比原始版本确实多了非常多,下面是一些思路分析:

优化目标:修复原版"输入什么都敢直接算、查一次就退出"的两个缺陷。

原版的两块短板

原版代码只有干净三行:问年份、问月份、把结果塞给 calendar.month() 打印。它在我输得规规矩矩时确实好用,但我一试就露馅:输入字母,int() 当场抛 ValueError 掀桌;输入 13 月,calendar 抛 IllegalMonthError 照样崩;而且查完一个月程序就走完了,想看下一月得重新运行。

所以我的优化不碰"画日历"这件本身已经交给标准库的事,只补输入这一环和用完这一环。

优化一:把 43/44 题的验证套路抽成可复用函数

我没有在外面写一堆 if 保护,而是把"非要问你拿到一个合法整数不可"封装成 get_int():循环里 try 住转换,失败就提示后自然进入下一轮,成功才 return 结束循环。这正是 43 题那套 while True + try/except,只是这次我把它当零件用,年、月两处都能调,不必复制粘贴验证代码。

关键是范围检查单独用 if 放在 try/except 之外------这是 44 题的教训:能转成整数和数字合不合规矩是两道关卡,混在一个 try 里容易误伤。于是 get_month() 卡 1~12,get_year() 卡 1~9999(calendar 支持的合法年份),越界就重新问,永远不把非法值送进日历函数去炸。

优化二:外层循环当菜单,查完不用重启

结构上我套了一层大循环,把"问年月 → 打日历 → 问要不要继续"做成常驻菜单,选继续就 continue 回到开头,选结束才 break 走人。这和 56 题优化版的秒表菜单是同一个思路:该反复做的流程用外层循环兜住,而不是让用户反复运行程序。

判断继续与否时,我把条件写成"不是 y 就退出",而不是"是 y 才继续"。因为用户很可能顺手敲回车或输别的字符,负向判断能让所有意外输入统一落到"安全结束"那一侧,不会卡在循环里莫名其妙。

顺带的结构收益

原版是三行流水账,优化后拆成了三个小函数,每个只管"获取 + 验证"一件事。这一步其实提前摸到了第四章函数化的门道:把重复的逻辑封装起来,主流程读起来就只剩"取值、打印、问续用"三步,验证的脏活累活全藏在函数里。

相关推荐
ASS-ASH1 小时前
从力学与机械原理角度深度剖析:尊界V800刹车踏板支架断裂事件的技术逻辑
人工智能·python·数据可视化·机械工程·汽车安全·物理仿真·制动系统
xhy_07071 小时前
AI 读了 .env,密钥会原样发给大模型吗?WES Code 的密钥打码(附实测)
人工智能·python·数据挖掘·flask·ai编程·wes code
2401_888859711 小时前
STM32H733 MPU、AXI、FMC学习
java·开发语言·stm32·spring
泡海椒1 小时前
JQuick-Excel 实战:用 STYLE 配置单元格与区域样式
开发语言·python·excel
威联通网络存储1 小时前
TS-h1283XU-RP 在医药批记录与检验场景的部署
网络·python
Patrick在香港1 小时前
时间戳凭空早了 8 小时:datetime.utcnow() 弃用实测与漂移复盘
数据库·python·标准库·datetime·时区·弃用
东莞市云毅网络有限公司8 小时前
AI 引用句逐条回指原文:让回答可回溯的校验实现
python·数据清洗·rag·企业知识库·文档解析
Sarvartha10 小时前
final 关键字
java·开发语言
数字融合10 小时前
透明化视频三维矿山井下照明重建技术
人工智能·python·数码相机