bpo-27141: Fix collections.UserList and UserDict shallow copy. (GH-4094) · python/cpython@3645d29 (original) (raw)
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1036,6 +1036,13 @@ def __contains__(self, key): | ||
1036 | 1036 | |
1037 | 1037 | # Now, add the methods in dicts but not in MutableMapping |
1038 | 1038 | def __repr__(self): return repr(self.data) |
1039 | +def __copy__(self): | |
1040 | +inst = self.__class__.__new__(self.__class__) | |
1041 | +inst.__dict__.update(self.__dict__) | |
1042 | +# Create a copy and avoid triggering descriptors | |
1043 | +inst.__dict__["data"] = self.__dict__["data"].copy() | |
1044 | +return inst | |
1045 | + | |
1039 | 1046 | def copy(self): |
1040 | 1047 | if self.__class__ is UserDict: |
1041 | 1048 | return UserDict(self.data.copy()) |
@@ -1048,6 +1055,7 @@ def copy(self): | ||
1048 | 1055 | self.data = data |
1049 | 1056 | c.update(self) |
1050 | 1057 | return c |
1058 | + | |
1051 | 1059 | @classmethod |
1052 | 1060 | def fromkeys(cls, iterable, value=None): |
1053 | 1061 | d = cls() |
@@ -1112,6 +1120,12 @@ def __mul__(self, n): | ||
1112 | 1120 | def __imul__(self, n): |
1113 | 1121 | self.data *= n |
1114 | 1122 | return self |
1123 | +def __copy__(self): | |
1124 | +inst = self.__class__.__new__(self.__class__) | |
1125 | +inst.__dict__.update(self.__dict__) | |
1126 | +# Create a copy and avoid triggering descriptors | |
1127 | +inst.__dict__["data"] = self.__dict__["data"][:] | |
1128 | +return inst | |
1115 | 1129 | def append(self, item): self.data.append(item) |
1116 | 1130 | def insert(self, i, item): self.data.insert(i, item) |
1117 | 1131 | def pop(self, i=-1): return self.data.pop(i) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -38,6 +38,20 @@ def _superset_test(self, a, b): | ||
38 | 38 | b=b.__name__, |
39 | 39 | ), |
40 | 40 | ) |
41 | + | |
42 | +def _copy_test(self, obj): | |
43 | +# Test internal copy | |
44 | +obj_copy = obj.copy() | |
45 | +self.assertIsNot(obj.data, obj_copy.data) | |
46 | +self.assertEqual(obj.data, obj_copy.data) | |
47 | + | |
48 | +# Test copy.copy | |
49 | +obj.test = [1234] # Make sure instance vars are also copied. | |
50 | +obj_copy = copy.copy(obj) | |
51 | +self.assertIsNot(obj.data, obj_copy.data) | |
52 | +self.assertEqual(obj.data, obj_copy.data) | |
53 | +self.assertIs(obj.test, obj_copy.test) | |
54 | + | |
41 | 55 | def test_str_protocol(self): |
42 | 56 | self._superset_test(UserString, str) |
43 | 57 | |
@@ -47,6 +61,16 @@ def test_list_protocol(self): | ||
47 | 61 | def test_dict_protocol(self): |
48 | 62 | self._superset_test(UserDict, dict) |
49 | 63 | |
64 | +def test_list_copy(self): | |
65 | +obj = UserList() | |
66 | +obj.append(123) | |
67 | +self._copy_test(obj) | |
68 | + | |
69 | +def test_dict_copy(self): | |
70 | +obj = UserDict() | |
71 | +obj[123] = "abc" | |
72 | +self._copy_test(obj) | |
73 | + | |
50 | 74 | |
51 | 75 | ################################################################################ |
52 | 76 | ### ChainMap (helper class for configparser and the string module) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
1 | +Added a ``__copy__()`` to ``collections.UserList`` and | |
2 | +``collections.UserDict`` in order to correctly implement shallow copying of | |
3 | +the objects. Patch by Bar Harel. |