如何在Python字典中检查多键?Telegram机器人KeyError问题求助
Telegram机器人消息提取:处理
message/edited_message键的KeyError问题 问题背景
用Python开发Telegram机器人时,原列表推导式用于筛选目标用户的新消息,但遇到编辑后的消息(键为edited_message)导致KeyError。
原代码
useful_messages = [i["message"] for i in response["result"] if i["message"]["from"]["id"] == int(chat_id) and i["message"]["date"] > last_time]
报错信息
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <listcomp> KeyError: 'message'
边缘情况
返回的更新列表中存在带edited_message键的条目:
[i.keys() for i in response["result"]] [dict_keys(['update_id', 'message']), dict_keys(['update_id', 'message']), dict_keys(['update_id', 'edited_message']), dict_keys(['update_id', 'message'])]
需要实现多键检查(同时兼容message和edited_message),优先一行代码的列表推导式方案,或其他优化逻辑。
解决方案
方案1:列表推导式+海象运算符(Python3.8+,一行式)
利用dict.get()获取消息对象,结合海象运算符:=提前绑定变量,避免重复查找:
useful_messages = [msg for i in response["result"] if (msg := i.get("message") or i.get("edited_message")) and msg["from"]["id"] == int(chat_id) and msg["date"] > last_time]
解释:
i.get("message")尝试获取message键,不存在则返回None;- 若
message不存在,or会继续尝试i.get("edited_message"); - 海象运算符
:=把获取到的消息对象赋值给msg,后续直接用msg做条件判断和属性访问; - 先判断
msg不为空,再检查用户ID和消息日期。
如果觉得一行太长,换行成多行更易读:
useful_messages = [ msg for i in response["result"] if (msg := i.get("message") or i.get("edited_message")) and msg["from"]["id"] == int(chat_id) and msg["date"] > last_time ]
方案2:兼容旧Python版本的列表推导式
如果使用Python3.7及以下,不支持海象运算符,可以用内部临时迭代实现:
useful_messages = [msg for i in response["result"] for msg in [i.get("message") or i.get("edited_message")] if msg and msg["from"]["id"] == int(chat_id) and msg["date"] > last_time]
解释:
- 通过
for msg in [i.get("message") or i.get("edited_message")]创建一个只有一个元素的临时列表,把消息对象赋值给msg; - 后续逻辑和方案1一致,先判断
msg不为空,再检查条件。
方案3:提取辅助函数(可读性优先,适合新手)
如果觉得推导式逻辑复杂,把消息提取逻辑封装成函数,代码更清晰易维护:
def extract_message(update): # 优先取message,不存在则取edited_message return update.get("message") or update.get("edited_message") useful_messages = [ msg for i in response["result"] if (msg := extract_message(i)) and msg["from"]["id"] == int(chat_id) and msg["date"] > last_time ]
解释:
- 辅助函数
extract_message专门处理消息提取,后续如果Telegram API新增其他消息类型(如channel_post),只需修改这个函数; - 主推导式逻辑更直观,新手更容易理解和调试。
方案4:扩展兼容更多消息类型(长期项目推荐)
如果机器人需要处理更多Telegram更新类型(比如频道帖子、回调查询等),可以定义所有支持的消息键,用next()查找第一个存在的键:
SUPPORTED_MESSAGE_KEYS = ["message", "edited_message", "channel_post", "edited_channel_post"] useful_messages = [ msg for i in response["result"] if (msg := next((i[key] for key in SUPPORTED_MESSAGE_KEYS if key in i), None)) and msg["from"]["id"] == int(chat_id) and msg["date"] > last_time ]
解释:
(i[key] for key in SUPPORTED_MESSAGE_KEYS if key in i)是一个生成器,遍历所有支持的键,返回第一个存在的键对应的值;next(..., None)表示如果没有找到任何支持的键,返回None;- 后续条件判断和前面一致,确保
msg有效后再检查用户ID和日期。
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 方案1 | 简洁,一行完成 | 依赖Python3.8+语法 | 短期脚本、Python版本较新的项目 |
| 方案2 | 兼容旧Python版本 | 推导式稍显啰嗦 | 旧版本Python环境 |
| 方案3 | 可读性强,易维护 | 多了一个函数定义 | 新手项目、需要长期维护的代码 |
| 方案4 | 扩展性强,兼容更多消息类型 | 逻辑稍复杂 | 长期迭代的机器人项目 |
内容的提问来源于stack exchange,提问作者PavoDive
相关产品推荐
相关产品推荐

