diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index cec6c9781a15e0..06196d1a3922b5 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -973,10 +973,17 @@ def __delitem__(self, key): del self.data[key] def __iter__(self): return iter(self.data) - # Modify __contains__ to work correctly when __missing__ is present + # Modify __contains__ and get() to work like dict + # does when __missing__ is present. def __contains__(self, key): return key in self.data + def get(self, key, default=None): + if key in self: + return self[key] + return default + + # Now, add the methods in dicts but not in MutableMapping def __repr__(self): return repr(self.data) def __copy__(self): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 92520b09bb8f26..a5859bff09ad35 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -70,6 +70,14 @@ def test_dict_copy(self): obj[123] = "abc" self._copy_test(obj) + def test_dict_missing(self): + class A(UserDict): + def __missing__(self, key): + return 456 + self.assertEqual(A()[123], 456) + # get() ignores __missing__ on dict + self.assertIs(A().get(123), None) + ################################################################################ ### ChainMap (helper class for configparser and the string module) diff --git a/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst b/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst new file mode 100644 index 00000000000000..5f9ffdffce5c26 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-01-09-01-57-12.bpo-39264.GsBL9-.rst @@ -0,0 +1,3 @@ +Fixed :meth:`collections.UserDict.get` to not call +:meth:`__missing__` when a value is not found. This matches the behavior of +:class:`dict`. Patch by Bar Harel.