英文:
Check for either key in python dictionary
问题
我有以下代码来使用Python从Telegram机器人获取一些消息:
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'
chat_id
是我感兴趣的用户的ID,而last_time
用于避免读取与用户的整个聊天。
它在过去的几个月里都运行正常,直到今天出现了一个“边界情况”:
[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
,导致了上面的KeyError
。
我知道我可以使用for循环,检查两个键(message
或edited_message
),然后继续消息的验证(日期和ID)和提取。但我想知道是否有可能在字典中检查两个键,从而保持列表/字典推导(一行解决方案将是理想的)。
我也考虑过,如果存在,将edited_message
键替换为此问题的答案中显示的任何程序之一。不幸的是,它们几乎都不是一行解决方案,所以for循环似乎是一个不那么冗长和复杂的解决方案。
当然,我愿意接受任何其他能够改进代码的解决方案(或编程逻辑)。
我还是Python的新手,如果提供复杂的解决方案,我将感激您提供详细的解释。
英文:
I have a the following code to get some messages from a telegram bot with python:
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'
chat_id
is the id of the user I'm interested in, and last_time
is used to avoid reading the whole chat with the user.
It worked for some months until today I hit an "edge case":
[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'])]
As you can see, one of the messages was edited, and its key is no longer message
but edited_message
, causing the KeyError
above.
I know I can use a for loop, check for either key (message
or edited_message
) and continue with the message validation (date and id) and extraction. But I wondered if it is possible to check for either key in the dictionary, thus keeping the list/dictionary comprehension (a one-liner solution would be ideal).
I also thought of replacing the edited_message
key, if present, by following any of the procedures shown in the answers to this question. Sadly they are hardly one-liners, so the for loop seems to be a less verbose and convoluted solution.
Of course, I'm open to any other solution (or programming logic) that will result in better code.
I'm still new to python, so I'd appreciate your detailed explanations, if complex solutions are offered.
答案1
得分: 1
# 在 `python>=3.8` 中,你可以使用海象运算符
useful_messages = [x for i in response["result"]
if (x := i.get("message", i.get("edited_message")))["from"]["id"] == int(chat_id)
and x["date"] > last_time]
---
# 没有它的话性能会更差
你可以使用 `i.get("message", i.get("edited_message"))`,但保持列表理解意味着要重复它三次,而不是一次,这在性能上不是很好(除非你没有许多项目(不是成百上千的))
useful_messages = [i.get("message", i.get("edited_message")) for i in response["result"]
if i.get("message", i.get("edited_message"))["from"]["id"] == int(chat_id)
and i.get("message", i.get("edited_message"))["date"] > last_time]
---
# 一个for循环会更加清晰,一个更干净和高效的代码比一个短小的代码更有价值
```python
useful_messages = []
for i in response["result"]:
msg = i.get("message")
if msg is None:
msg = i["edited_message"]
if msg["from"]["id"] == int(chat_id) and msg["date"] > last_time:
useful_messages.append(msg)
英文:
With python>=3.8
you can use the walrus operator
useful_messages = [x for i in response["result"]
if (x := i.get("message", i.get("edited_message")))["from"]["id"] == int(chat_id)
and x["date"] > last_time]
Without it would be less performant
You could do i.get("message", i.get("edited_message"))
but keeping the list comprehension would mean repeat it 3 times instead of one, which isn't very performant (unless you don't have many items (not millions))
useful_messages = [i.get("message", i.get("edited_message")) for i in response["result"]
if i.get("message", i.get("edited_message"))["from"]["id"] == int(chat_id)
and i.get("message", i.get("edited_message"))["date"] > last_time]
A for loop would be cleaner then, a cleaner and performant code values more than a short code
useful_messages = []
for i in response["result"]:
msg = i.get("message")
if msg is None:
msg = i["edited_message"]
if msg["from"]["id"] == int(chat_id) and msg["date"] > last_time:
useful_messages.append(msg)
答案2
得分: 0
messages = [
{'message': {'from': {'id': 1}, 'date': 'new'}},
{'message': {'from': {'id': 1}, 'date': 'val'}},
{'edited_message': {'from': {'id': 1}, 'date': 'new'}},
{'edited_message': {'from': {'id': 1}, 'date': 'val'}},
{'garbage': {'from': {'id': 1}, 'date': 'val'}},
]
useful_messages = [
message[key]
for message in messages
for key in message
if key in ('message', 'edited_message')
and message[key]['from']['id'] == 1
and message[key]['date'] == 'val'
]
output:
[{'from': {'id': 1}, 'date': 'val'}, {'from': {'id': 1}, 'date': 'val'}]
英文:
for nested comprehension I like to separate lines, but you can one-line it if you don't care.
messages = [
{'message': {'from': {'id': 1}, 'date': 'new'}},
{'message': {'from': {'id': 1}, 'date': 'val'}},
{'edited_message': {'from': {'id': 1}, 'date': 'new'}},
{'edited_message': {'from': {'id': 1}, 'date': 'val'}},
{'garbage': {'from': {'id': 1}, 'date': 'val'}},
]
useful_messages = [
message[key]
for message in messages
for key in message
if key in ('message', 'edited_message')
and message[key]['from']['id'] == 1
and message[key]['date'] == 'val'
]
output:
[{'from': {'id': 1}, 'date': 'val'}, {'from': {'id': 1}, 'date': 'val'}]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论