diff -r b7a4c076ba40 Lib/copy.py --- a/Lib/copy.py Tue Jun 07 01:08:48 2016 +0000 +++ b/Lib/copy.py Tue Jun 07 19:18:34 2016 +0300 @@ -113,7 +113,8 @@ def _copy_immutable(x): for t in (type(None), int, float, bool, complex, str, tuple, bytes, frozenset, type, range, slice, types.BuiltinFunctionType, type(Ellipsis), type(NotImplemented), - types.FunctionType, weakref.ref): + types.FunctionType, weakref.ref, + type({}.keys()), type({}.values()), type({}.items())): d[t] = _copy_immutable t = getattr(types, "CodeType", None) if t is not None: @@ -243,6 +244,25 @@ d[dict] = _deepcopy_dict if PyStringMap is not None: d[PyStringMap] = _deepcopy_dict +def _deepcopy_dict_keys(x, memo, deepcopy=deepcopy): + y = {deepcopy(key, memo) for key in x} + try: + return memo[id(x)] + except KeyError: + pass + return frozenset(y) +d[type({}.keys())] = _deepcopy_dict_keys +d[type({}.values())] = _deepcopy_tuple + +def _deepcopy_dict_items(x, memo, deepcopy=deepcopy): + y = {deepcopy(key, memo): deepcopy(value, memo) for key, value in x} + try: + return memo[id(x)] + except KeyError: + pass + return y.items() +d[type({}.items())] = _deepcopy_dict_items + def _deepcopy_method(x, memo): # Copy instance methods return type(x)(x.__func__, deepcopy(x.__self__, memo)) d[types.MethodType] = _deepcopy_method diff -r b7a4c076ba40 Lib/test/test_copy.py --- a/Lib/test/test_copy.py Tue Jun 07 01:08:48 2016 +0000 +++ b/Lib/test/test_copy.py Tue Jun 07 19:18:34 2016 +0300 @@ -1,5 +1,6 @@ """Unit tests for the copy module.""" +import collections.abc import copy import copyreg import weakref @@ -95,11 +96,13 @@ class TestCopy(unittest.TestCase): pass class WithMetaclass(metaclass=abc.ABCMeta): pass + d = {1: [], 'a': memoryview(b'a')} tests = [None, ..., NotImplemented, 42, 2**100, 3.14, True, False, 1j, "hello", "hello\u1234", f.__code__, b"world", bytes(range(256)), range(10), slice(1, 10, 2), - NewStyle, Classic, max, WithMetaclass] + NewStyle, Classic, max, WithMetaclass, + d.keys(), d.values(), d.items()] for x in tests: self.assertIs(copy.copy(x), x) @@ -424,6 +427,36 @@ class TestCopy(unittest.TestCase): self.assertIs(y['foo'], y) self.assertEqual(len(y), 1) + def test_deepcopy_dict_keys(self): + d = {"foo": [1, 2], "bar": 3} + x = d.keys() + y = copy.deepcopy(x) + self.assertEqual(y, {'foo', 'bar'}) + self.assertIsInstance(y, collections.abc.Set) + self.assertIn('foo', y) + del d['foo'] + self.assertIn('foo', y) + + def test_deepcopy_dict_values(self): + d = {"foo": [1, 2], "bar": 3} + x = d.values() + y = copy.deepcopy(x) + self.assertCountEqual(y, ([1, 2], 3)) + self.assertIsInstance(y, collections.abc.Sequence) + self.assertIn([1, 2], y) + del d['foo'] + self.assertIn([1, 2], y) + + def test_deepcopy_dict_values(self): + d = {"foo": [1, 2], "bar": 3} + x = d.items() + y = copy.deepcopy(x) + self.assertCountEqual(y, (('foo', [1, 2]), ('bar', 3))) + self.assertIsInstance(y, collections.abc.Set) + self.assertIn(('foo', [1, 2]), y) + del d['foo'] + self.assertIn(('foo', [1, 2]), y) + def test_deepcopy_keepalive(self): memo = {} x = []