You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Telegram提醒机器人字典取值异常:传入month触发week的KeyError

问题:为何type为'month'的Record会触发KeyError: '25'?

我正在开发一款Telegram提醒机器人,帮助用户管理各类待办提醒,支持每日、每周、每月等多种重复类型。机器人提供/reminders命令用于展示用户的提醒记录,为了生成对应的回复文本,我编写了make_record_text函数,通过一个periods字典根据提醒类型匹配对应的文本格式。但遇到一个问题:当传入type为'month'的Record对象时,函数总是触发KeyError: '25',该错误来自week类型对应的days_of_week_dict[record.time]操作,而我本应获取month对应的字典值。

相关代码

主命令函数

@dp.message_handler(commands=['reminders'], state="*")
async def show_reminder(message: types.Message):
    """
    Shows user's records
    """
    records = get_records(int(message.from_user.id))
    if records:
        await message.answer(messages.show_records_message)
        for item in records:
            await message.answer(make_record_text(item))
    else:
        ###

生成文本的函数

def make_record_text(record: Record) -> str:
    """
    Creates an answer with user's record using Record
    """
    days_of_week_dict = {
        'monday': "every monday",
        'tuesday': "every tuesday",
        'wednesday': "every wednesday",
        'thursday': "every thursday",
        'friday': "every friday",
        'saturday': "every saturday",
        'sunday': "every sunday",
    }
    print(f'record = {record}')
    print(f'record type = {record.type}')
    print(f'record date = {record.date}')
    print(f'record time = {record.time}')

    periods = {'year': f'every year {record.time}',
               'once': record.date,
               'week': f'{days_of_week_dict[record.time]}',
               'month': f'every month on {record.time}',
               'several_min': f'every {record.time} minutes',
               'everyday': f'everyday at {record.time}',
               'several_hours': f'every {record.time} hours',
               'every_few_days': f'every {record.time} days',
               }

    return messages.list_records_message.format(title=record.title,
                                                date=periods[record.type],
                                                id=record.id)

Record类定义

class Record(NamedTuple):
    user: int
    title: str
    date: Union[type(datetime.datetime), str]
    time: Union[type(datetime.datetime), str]
    type: Literal['everyday', 'few_times_a_day', 'every_few_days',
                  'week', 'month', 'year', 'once']
    need_delete: bool
    id: Optional[int]

输出日志

record = Record(user=1234, title='month', date='month', time='25', type='month', need_delete=0, id=1)
record type = month
record date = month
record time = 25

错误信息

File "C:\Users\pizhlo21\Desktop\Folder\python\tg_bot_reminder\controller.py", line 121, in show_reminder
    await message.answer(make_record_text(item))
  File "C:\Users\pizhlo21\Desktop\Folder\python\tg_bot_reminder\controller.py", line 146, in make_record_text
    'week': f'{days_of_week_dict[record.time]}',
KeyError: '25'

解答

原因很直接:Python在创建字典时,会立即计算所有键对应的值,不管你后续会不会用到这个键。

你写的periods字典里,每个键的值都是提前计算好的——哪怕当前处理的是type为'month'的record,Python还是会执行f'{days_of_week_dict[record.time]}'这行代码来生成'week'键对应的值。而此时record.time是'25',这个值不在days_of_week_dict的键列表里,所以直接触发了KeyError。

解决办法

方法1:改用条件判断生成对应文本

这种方式最直观,只在需要的时候计算对应类型的文本,避免提前执行所有分支:

def make_record_text(record: Record) -> str:
    days_of_week_dict = {
        'monday': "every monday",
        'tuesday': "every tuesday",
        'wednesday': "every wednesday",
        'thursday': "every thursday",
        'friday': "every friday",
        'saturday': "every saturday",
        'sunday': "every sunday",
    }

    # 根据提醒类型生成对应的日期文本
    if record.type == 'year':
        date_text = f'every year {record.time}'
    elif record.type == 'once':
        date_text = record.date
    elif record.type == 'week':
        date_text = days_of_week_dict[record.time]
    elif record.type == 'month':
        date_text = f'every month on {record.time}'
    elif record.type == 'several_min':
        date_text = f'every {record.time} minutes'
    elif record.type == 'everyday':
        date_text = f'everyday at {record.time}'
    elif record.type == 'several_hours':
        date_text = f'every {record.time} hours'
    elif record.type == 'every_few_days':
        date_text = f'every {record.time} days'
    else:
        date_text = '未知提醒类型'  # 处理未定义的类型,避免报错

    return messages.list_records_message.format(title=record.title,
                                                date=date_text,
                                                id=record.id)

方法2:用lambda延迟计算字典值

把字典里的值改成lambda函数,这样只有当你调用对应的lambda时才会计算值,避免提前执行所有分支:

def make_record_text(record: Record) -> str:
    days_of_week_dict = {
        'monday': "every monday",
        'tuesday': "every tuesday",
        'wednesday': "every wednesday",
        'thursday': "every thursday",
        'friday': "every friday",
        'saturday': "every saturday",
        'sunday': "every sunday",
    }

    periods = {
        'year': lambda: f'every year {record.time}',
        'once': lambda: record.date,
        'week': lambda: days_of_week_dict[record.time],
        'month': lambda: f'every month on {record.time}',
        'several_min': lambda: f'every {record.time} minutes',
        'everyday': lambda: f'everyday at {record.time}',
        'several_hours': lambda: f'every {record.time} hours',
        'every_few_days': lambda: f'every {record.time} days',
    }

    # 调用对应lambda计算文本
    date_text = periods[record.type]()
    return messages.list_records_message.format(title=record.title,
                                                date=date_text,
                                                id=record.id)

内容的提问来源于stack exchange,提问作者pizhlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 01:35:23