Python基础语法练习题(64)

今天继续记录一题的内容,共有三个版本。

第六十四题,日期减法练习:

1.首先是最原初的版本:

复制代码
#定义一个函数,该函数接收两个参数:一个遵循‘YYYY-MM-DD’格式的日期字符串pdate以及一个整数days。该函数的任务是计算出从给定日期向前days后的新日期

#导入datetime模块

import datetime

#定义函数

def calculate_previous_date(pdate, days):
    """
    计算从给定日期向前days后的日期
    :param pdate: 遵循'YYYY-MM-DD'格式的日期字符串
    :param days: 整数,表示天数
    :return: 从给定日期向前days后的日期字符串,遵循'YYYY-MM-DD'格式
    """
    pdate_obj = datetime.datetime.strptime(pdate, '%Y-%m-%d')
    time_gap = datetime.timedelta(days=days)
    new_date = pdate_obj - time_gap
    return new_date.strftime('%Y-%m-%d')

#调用函数并接收返回值

original_date = '2023-04-01'
days = 5
result_date = calculate_previous_date(original_date, days)
print(f"从 {original_date} 往前推 {days} 天后的日期是:{result_date}")

这个是最原始版本的代码,完成了基本需求但也仅限如此,思路分析如下:

题目要求:写一个函数,接收 YYYY-MM-DD 日期字符串和天数,算出往前推 N 天后的日期。

我的思路:把 63 题的"加法"反过来用"减法"

63 题我用 日期 + timedelta 往后挪,这题就是往前推,所以核心一行改成 pdate_obj - time_gap。整个计算我拆成四步流水线:字符串转对象 → 造时长 → 相减 → 转回字符串,最后 return 一个排好 YYYY-MM-DD 格式的结果。

关键设计:计算逻辑封装进函数

这题我没把减法直接写在主程序里,而是抽成 calculate_previous_date(pdate, days),参数和返回值都清楚。好处是主程序只负责"喂进去、拿回来",怎么算的全藏在函数体内。唯一的小遗憾是:日期和天数是我在代码里写死的常量('2023-04-01'、5),换个数就得改代码重跑。

2.接下来是优化版本的代码:

复制代码
# 定义一个函数,该函数接收两个参数:一个遵循'YYYY-MM-DD'格式的日期字符串pdate以及一个整数days。
# 该函数的任务是计算出从给定日期向前days天后的新日期

# 导入datetime模块

import datetime


# 定义函数

def calculate_previous_date(pdate, days):
    """
    计算从给定日期向前days天后的日期
    :param pdate: 遵循'YYYY-MM-DD'格式的日期字符串
    :param days: 整数,表示天数
    :return: 从给定日期向前days天后的日期字符串,遵循'YYYY-MM-DD'格式
    """
    pdate_obj = datetime.datetime.strptime(pdate, '%Y-%m-%d')
    time_gap = datetime.timedelta(days=days)
    new_date = pdate_obj - time_gap
    return new_date.strftime('%Y-%m-%d')


# 输入日期,并校验格式是否正确(YYYY-MM-DD)

while True:
    original_date = input("请输入一个日期(格式:YYYY-MM-DD,例如 2023-04-01):").strip()
    try:
        datetime.datetime.strptime(original_date, '%Y-%m-%d')
        break
    except ValueError:
        print("日期格式不正确,请按照 YYYY-MM-DD 的格式重新输入!")

# 输入要往前推的天数,并校验是否为正整数

while True:
    days_input = input("请输入要往前推的天数(正整数):").strip()
    try:
        days = int(days_input)
        if days < 0:
            print("天数不能为负数,请重新输入!")
            continue
        break
    except ValueError:
        print("输入无效,请输入一个整数!")

# 调用函数并输出结果

result_date = calculate_previous_date(original_date, days)
print(f"从 {original_date} 往前推 {days} 天后的日期是:{result_date}")

可以看到代码量有了明显的提升,代码思路分析如下:

优化目标:把原版写死的日期/天数改成交互输入,并防止用户乱输导致崩溃。

核心计算一字没改,改的全在"入口"

函数 calculate_previous_date 我原封不动沿用,这次动的是怎么拿到那俩参数。原版是写死的常量,这版换成了两段 while True + try/except 的验证关卡,正是 43/44 题和 62 优化版练熟的老手艺。

两道输入关卡

第一关验日期格式。 用 strptime(输入, '%Y-%m-%d') 试探------能解析就 break 放行,报 ValueError 就说明写法不对,提示后自然进下一轮重输。第二关验天数更讲究,要过两道:先 int() 试转换接住字母,再用独立的 if days < 0 判负数。这里我特意记住 44 题的教训:范围检查必须放在 try/except 之外单独做,否则正常数字会绕过检查;而负数命中时用 continue 明确"打回重填"。

3.再接下来是最终优化的版本:

复制代码
# 定义一个函数,该函数接收两个参数:一个遵循'YYYY-MM-DD'格式的日期字符串pdate以及一个整数days。
# 该函数的任务是计算出从给定日期向前days天后的新日期

# 本版本在“优化版”的基础上,进一步放宽了日期输入的要求:
# 借助 dateutil.parser 自动识别多种日期写法(例如 2023-04-01、2023/4/1、2023年4月1日、
# Apr 1 2023、04-01-2023 等),用户不必严格按照固定格式输入也能完成计算。

# 导入datetime模块

import datetime

# 导入dateutil的parser模块,用于灵活解析多种日期输入格式

from dateutil import parser


# 定义函数

def calculate_previous_date(pdate, days):
    """
    计算从给定日期向前days天后的日期
    :param pdate: 遵循'YYYY-MM-DD'格式的日期字符串
    :param days: 整数,表示天数
    :return: 从给定日期向前days天后的日期字符串,遵循'YYYY-MM-DD'格式
    """
    pdate_obj = datetime.datetime.strptime(pdate, '%Y-%m-%d')
    time_gap = datetime.timedelta(days=days)
    new_date = pdate_obj - time_gap
    return new_date.strftime('%Y-%m-%d')


# 输入日期:使用 dateutil.parser 自动识别多种格式,
# 解析成功后统一转换成标准的 YYYY-MM-DD 字符串,无法识别时提示重新输入

while True:
    date_input = input("请输入一个日期(支持多种写法,例如 2023-04-01、2023/4/1、2023年4月1日、Apr 1 2023):").strip()
    try:
        parsed_date_obj = parser.parse(date_input)
        original_date = parsed_date_obj.strftime('%Y-%m-%d')
        break
    except (ValueError, parser.parser.ParserError):
        print("无法识别该日期,请重新输入一个有效的日期!")

# 输入要往前推的天数,并校验是否为正整数

while True:
    days_input = input("请输入要往前推的天数(正整数):").strip()
    try:
        days = int(days_input)
        if days < 0:
            print("天数不能为负数,请重新输入!")
            continue
        break
    except ValueError:
        print("输入无效,请输入一个整数!")

# 调用函数并输出结果

result_date = calculate_previous_date(original_date, days)
print(f"从 {original_date} 往前推 {days} 天后的日期是:{result_date}")

代码思路分析如下:

优化目标:在优化版基础上彻底放宽日期输入,用户怎么写都能识别。

核心矛盾没变:只升级"日期关卡"

函数计算、天数验证这两块我都没动,唯一升级的是第一道日期关卡------把"死磕一种格式"换成了"谁来都能认"。

关键改动:用第三方 dateutil.parser 替我"识格式"

优化版之所以只认 YYYY-MM-DD,是因为 strptime 有个死规矩:我必须亲手报一张一模一样的格式模板。而用户的写法千奇百怪(2023/4/1、2023年4月1日、Apr 1 2023......),我不可能把所有模板都列全。

于是这版请出 58 题见过的第三方模块 dateutil 的 parser.parse():把整颗字符串丢进去,它自己认------月份缩写、分隔符、中文年月日都能识破,我不再需要指定格式。识别成功后我立刻用 strftime 统一折算回标准 YYYY-MM-DD 字符串,这样后面喂给原封不动的计算函数时依然对得上。失败时我多接了一个 ParserError 异常来兜底乱码输入。

三级进化的总结

回头看这三版,我做的其实是同一件事的三次加固:原版只能算写死的值 → 优化版能问用户要、但只认一种格式 → 再优化版连格式都不挑、怎么输都认。计算逻辑从头到尾没变过,一路优化的全是"程序对用户输入的包容度"。这也印证了我越来越深的一个体会:程序能不能跑是及格线,扛不扛得住用户的各种"乱输",才是它好不好用的真正分水岭。

相关推荐
fanjiu20201 小时前
flask接收消息
python·flask
外收内放1 小时前
Python基础语法练习题(65)
开发语言·python
努力努力再努力FFF1 小时前
题目:2026AI 证书选购指南:不同基础、不同诉求如何抉择
学习
iReachers1 小时前
Termux:把安卓手机变成随身的命令行工具箱
python·安卓·termux·命令行·实用工具
xy_zoe1 小时前
揭秘市面上那些热门的SEO优化服务机构!
python·facebook
Python图像识别1 小时前
43-【2027毕设】YOLO11暴力检测识别系统 - Python完整源码+PyQt5界面+训练模型+数据集
python·qt·课程设计
卷无止境1 小时前
如何让AI Agent老老实实遵守公司代码规范——以Pi Agent为例
后端·python
只愿云淡风清2 小时前
正则表达式学习笔记-01 正则表达式的来源
笔记·学习·正则表达式
计算机编程指导师2 小时前
计算机毕设怎么做?基于Hadoop+Spark的商场商铺数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·spark·毕业设计·课程设计·商场商铺