Skip to content

Commit efdc9d6

Browse files
gh-87995: Make MappingProxyType hashable (GH-94252)
1 parent 71d5299 commit efdc9d6

File tree

5 files changed

+28
-1
lines changed

5 files changed

+28
-1
lines changed

Doc/library/types.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,12 @@ Standard names are defined for the following types:
417417

418418
.. versionadded:: 3.9
419419

420+
.. describe:: hash(proxy)
421+
422+
Return a hash of the underlying mapping.
423+
424+
.. versionadded:: 3.12
425+
420426

421427
Additional Utility Classes and Functions
422428
----------------------------------------

Doc/whatsnew/3.12.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ New Features
7979
Other Language Changes
8080
======================
8181

82+
* :class:`types.MappingProxyType` instances are now hashable if the underlying
83+
mapping is hashable.
84+
(Contributed by Serhiy Storchaka in :gh:`87995`.)
8285

8386

8487
New Modules

Lib/test/test_types.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,16 @@ def test_union(self):
12031203
self.assertDictEqual(mapping, {'a': 0, 'b': 1, 'c': 2})
12041204
self.assertDictEqual(other, {'c': 3, 'p': 0})
12051205

1206+
def test_hash(self):
1207+
class HashableDict(dict):
1208+
def __hash__(self):
1209+
return 3844817361
1210+
view = self.mappingproxy({'a': 1, 'b': 2})
1211+
self.assertRaises(TypeError, hash, view)
1212+
mapping = HashableDict({'a': 1, 'b': 2})
1213+
view = self.mappingproxy(mapping)
1214+
self.assertEqual(hash(view), hash(mapping))
1215+
12061216

12071217
class ClassCreationTests(unittest.TestCase):
12081218

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`types.MappingProxyType` instances are now hashable if the underlying
2+
mapping is hashable.

Objects/descrobject.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,12 @@ mappingproxy_getiter(mappingproxyobject *pp)
11781178
return PyObject_GetIter(pp->mapping);
11791179
}
11801180

1181+
static Py_hash_t
1182+
mappingproxy_hash(mappingproxyobject *pp)
1183+
{
1184+
return PyObject_Hash(pp->mapping);
1185+
}
1186+
11811187
static PyObject *
11821188
mappingproxy_str(mappingproxyobject *pp)
11831189
{
@@ -1901,7 +1907,7 @@ PyTypeObject PyDictProxy_Type = {
19011907
&mappingproxy_as_number, /* tp_as_number */
19021908
&mappingproxy_as_sequence, /* tp_as_sequence */
19031909
&mappingproxy_as_mapping, /* tp_as_mapping */
1904-
0, /* tp_hash */
1910+
(hashfunc)mappingproxy_hash, /* tp_hash */
19051911
0, /* tp_call */
19061912
(reprfunc)mappingproxy_str, /* tp_str */
19071913
PyObject_GenericGetAttr, /* tp_getattro */

0 commit comments

Comments
 (0)