字典传递给我错误的键值



我正在开发电报机器人。我的机器人帮助用户记住他们要做的事情。所以问题是,用户可以创建许多类型的内容:每天、每周、每天几次、一年一次等等。我的机器人有一个命令,显示用户的记录。为了正确地做到这一点,我写了一个函数,使答案的文本(例如,如果类型是"everyday"然后bot每天在HH:MM"回答,如果类型是"每周"然后他说"每个星期一在HH: mm")。
我的问题是,要做到这一点,我做了一个字典,其中键是这样的记录的类型,值是文本,机器人可能会告诉用户。但是这个字典不能正确工作:当我传递记录类型&;month&;或";everyday"或者其他的函数它总是得到键值&;week&;虽然它应该得到键值"月"或";everyday"。我得到KeyError,因为它

代码:
显示记录命令的主要功能:

@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 = 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

类记录:

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]

错误信息:

File "C:Userspizhlo21DesktopFolderpythontg_bot_remindercontroller.py", line 121, in show_reminder
await message.answer(make_record_text(item))
File "C:Userspizhlo21DesktopFolderpythontg_bot_remindercontroller.py", line 146, in make_record_text
'week': f'{days_of_week_dict[record.time]}',
KeyError: '25'

为什么当我通过"month"时,会发生这种情况?

问题是,在知道record.time值在这种时间段内是否有效之前,您正在构建整个periods字典,并且评估f'{days_of_week_dict[record.time]}'会让Python尝试访问days_of_week_dict["25"],这不会飞。

我把你的namedtuple换成了下面的dataclass,因为它感觉更准确,但实际的修复是match语句,它只格式化适合type的人类可读周期。(如果你的Python版本早于3.10并且没有match,你可以用if self.type == "year"替换它,等等)

import dataclasses
import datetime
from typing import Union, Literal, Optional
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",
}

@dataclasses.dataclass()
class Record:
user: int
title: str
date: Union[datetime.datetime, str]
time: Union[datetime.datetime, str]
type: Literal[
"everyday", "few_times_a_day", "every_few_days", "week", "month", "year", "once"
]
need_delete: bool
id: Optional[int]
def format_period(self) -> str:
match self.type:
case 'year':
return f'every year {self.time}'
case 'once':
return self.date
case 'week':
return f'{days_of_week_dict[self.time]}'
case 'month':
return f'every month on {self.time}'
case 'several_min':
return f'every {self.time} minutes'
case 'everyday':
return f'everyday at {self.time}'
case 'several_hours':
return f'every {self.time} hours'
case 'every_few_days':
return f'every {self.time} days'
case _:
raise ValueError(f'Unknown record type: {self.type}')

def make_record_text(record: Record) -> str:
return f"{record=}; {record.format_period()}"

print(
make_record_text(
Record(
user=297850814,
title="month",
date="month",
time="25",
type="month",
need_delete=False,
id=1,
)
)
)

这个输出

record=Record(user=297850814, title='month', date='month', time='25', type='month', need_delete=False, id=1);
every month on 25

出现这个问题是因为:

  1. 对days_of_week_dict的调用将在创建periods
  2. 时被评估
  3. 您使用了可能不存在的字典键的括号表示法

您可以通过将括号符号更改为.get()字典方法来修复此问题,如果键不存在(或指定其他值),则将计算为None

periods的赋值改为:

periods = {'year': f'every year {record.time}',
'once': record.date,
'week': f'{days_of_week_dict.get(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',
}

应该能解决这个问题。

最新更新