This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: Document dict behavior when setting equal but not identical key
Type: behavior Stage: needs patch
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: JelleZijlstra, docs@python, malthe, methane, potiuk, rhettinger
Priority: normal Keywords:

Created on 2022-03-04 23:25 by malthe, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 31685 malthe, 2022-03-04 23:25
Messages (9)
msg414554 - (view) Author: Malthe Borch (malthe) * Date: 2022-03-04 23:25
When a key that is equal to an existing key (but not the same object identity) is used to set a new value, the key itself is not replaced.

This manifests perhaps most clearly in `weakref.WeakKeyDictionary` where keys can mysteriously disappear.

Consider two equal keys, k1 and k2:

d = WeakKeyDictionary()
d[k1] = 1
d[k2] = 2
del k1

We would expect the dictionary to have a single entry k2 => 2. But in fact it is empty now.
msg414560 - (view) Author: Jelle Zijlstra (JelleZijlstra) * (Python committer) Date: 2022-03-05 03:31
As @methane also said on the PR, this is a backward compatibility break and we can't just change the behavior. I'd be opposed to a change here: the proposed behavior isn't clearly better than the existing behavior (sometimes you want one behavior, sometimes another), and it will be difficult to find and adjust code that relies on the existing behavior.
msg414562 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2022-03-05 03:53
I concur with Jelle and Methane that we can't do this without breaking code.

Also if you don't care about dict order, the work around is easy.  Just remove the old key:

    d.pop(k); d[k] = v
msg414572 - (view) Author: Jarek Potiuk (potiuk) Date: 2022-03-05 09:28
How about if we make PR instead to the documentation about this behaviour? 

I think this behaviour is a little surprising (you need to know the internals of how WeakKeyDict keys are constructed and checked) and while I understand you do not want breaking change, maybe this should be explained to the users and example given how to apply the workaround?

Just following the "least surprise" principle.
msg414581 - (view) Author: Jelle Zijlstra (JelleZijlstra) * (Python committer) Date: 2022-03-05 15:18
Agree, I couldn't find a place where this behavior is documented. The second paragraph in comes close. Reopening as a documentation issue.
msg414586 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2022-03-05 16:49
The weakref docs in particular should point out the OP's example and highlight the workaround.
msg414607 - (view) Author: Malthe Borch (malthe) * Date: 2022-03-06 08:19
Java's HashMap has also the (current) Python behavior. An existing same key is not replaced.
msg414636 - (view) Author: Inada Naoki (methane) * (Python committer) Date: 2022-03-07 04:28
I don't know much about Java, but Java's WeakHashMap is same to Python's WeakKeyDictionary.

This class is intended primarily for use with key objects whose equals methods test for object identity using the == operator. Once such a key is discarded it can never be recreated, so it is impossible to do a lookup of that key in a WeakHashMap at some later time and be surprised that its entry has been removed. This class will work perfectly well with key objects whose equals methods are not based upon object identity, such as String instances. With such recreatable key objects, however, the automatic removal of WeakHashMap entries whose keys have been discarded may prove to be confusing.
msg414652 - (view) Author: Jarek Potiuk (potiuk) Date: 2022-03-07 10:13
Yeah. Sounds like adding docs is indeed needed :)
Date User Action Args
2022-04-11 14:59:56adminsetgithub: 91081
2022-03-07 10:13:25potiuksetmessages: + msg414652
2022-03-07 04:28:25methanesetnosy: + methane
messages: + msg414636
2022-03-06 08:19:15malthesetmessages: + msg414607
2022-03-05 16:49:54rhettingersetmessages: + msg414586
2022-03-05 15:18:47JelleZijlstrasetstatus: closed -> open

assignee: docs@python
stage: resolved -> needs patch
title: Replace key if not identical to old key in dict -> Document dict behavior when setting equal but not identical key
nosy: + docs@python
versions: + Python 3.9, Python 3.10, Python 3.11
messages: + msg414581
components: + Documentation, - Library (Lib)
resolution: rejected ->
2022-03-05 09:28:11potiuksetnosy: + potiuk
messages: + msg414572
2022-03-05 03:53:04rhettingersetstatus: open -> closed

nosy: + rhettinger
messages: + msg414562

resolution: rejected
stage: resolved
2022-03-05 03:31:27JelleZijlstrasetnosy: + JelleZijlstra
messages: + msg414560
2022-03-04 23:25:53malthecreate