检查Python字典中的任一键。

huangapple go评论66阅读模式
英文:

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循环,检查两个键(messageedited_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[&quot;message&quot;] for i in response[&quot;result&quot;] if i[&quot;message&quot;][&quot;from&quot;][&quot;id&quot;] == int(chat_id) and i[&quot;message&quot;][&quot;date&quot;] &gt; last_time]

Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;listcomp&gt;
KeyError: &#39;message&#39;

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[&quot;result&quot;]]

[dict_keys([&#39;update_id&#39;, &#39;message&#39;]), 
 dict_keys([&#39;update_id&#39;, &#39;message&#39;]), 
 dict_keys([&#39;update_id&#39;, &#39;edited_message&#39;]), 
 dict_keys([&#39;update_id&#39;, &#39;message&#39;])]

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&gt;=3.8` 中,你可以使用海象运算符

useful_messages = [x for i in response[&quot;result&quot;]
                   if (x := i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;)))[&quot;from&quot;][&quot;id&quot;] == int(chat_id)
                   and x[&quot;date&quot;] &gt; last_time]

---

# 没有它的话性能会更差

你可以使用 `i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;))`,但保持列表理解意味着要重复它三次而不是一次这在性能上不是很好除非你没有许多项目不是成百上千的))

useful_messages = [i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;)) for i in response[&quot;result&quot;] 
                   if i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;))[&quot;from&quot;][&quot;id&quot;] == int(chat_id) 
                   and i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;))[&quot;date&quot;] &gt; last_time]

---

# 一个for循环会更加清晰,一个更干净和高效的代码比一个短小的代码更有价值

```python
useful_messages = []

for i in response[&quot;result&quot;]:
    msg = i.get(&quot;message&quot;)
    if msg is None:
        msg = i[&quot;edited_message&quot;]

    if msg[&quot;from&quot;][&quot;id&quot;] == int(chat_id) and msg[&quot;date&quot;] &gt; last_time:
        useful_messages.append(msg)
英文:

With python&gt;=3.8 you can use the walrus operator

useful_messages = [x for i in response[&quot;result&quot;]
                   if (x := i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;)))[&quot;from&quot;][&quot;id&quot;] == int(chat_id)
                   and x[&quot;date&quot;] &gt; last_time]

Without it would be less performant

You could do i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;)) 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(&quot;message&quot;, i.get(&quot;edited_message&quot;)) for i in response[&quot;result&quot;] 
                   if i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;))[&quot;from&quot;][&quot;id&quot;] == int(chat_id) 
                   and i.get(&quot;message&quot;, i.get(&quot;edited_message&quot;))[&quot;date&quot;] &gt; 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[&quot;result&quot;]:
    msg = i.get(&quot;message&quot;)
    if msg is None:
        msg = i[&quot;edited_message&quot;]

    if msg[&quot;from&quot;][&quot;id&quot;] == int(chat_id) and msg[&quot;date&quot;] &gt; 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 = [
    {&#39;message&#39;: {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;new&#39;}},
    {&#39;message&#39;: {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;val&#39;}},
    {&#39;edited_message&#39;: {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;new&#39;}},
    {&#39;edited_message&#39;: {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;val&#39;}},
    {&#39;garbage&#39;: {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;val&#39;}},
    ]

useful_messages = [
    message[key]
    for message in messages
    for key in message
    if key in (&#39;message&#39;, &#39;edited_message&#39;)
    and message[key][&#39;from&#39;][&#39;id&#39;] == 1
    and message[key][&#39;date&#39;] == &#39;val&#39;
    ]

output:

[{&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;val&#39;}, {&#39;from&#39;: {&#39;id&#39;: 1}, &#39;date&#39;: &#39;val&#39;}]

huangapple
  • 本文由 发表于 2023年6月9日 04:26:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76435474.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定