diff -r 8e838598eed1 Lib/collections/__init__.py --- a/Lib/collections/__init__.py Tue Jul 02 09:07:53 2013 -0400 +++ b/Lib/collections/__init__.py Wed Jul 03 18:47:38 2013 +0300 @@ -574,10 +574,18 @@ def copy(self): 'Return a shallow copy.' - return self.__class__(self) + inst_dict = vars(self).copy() + for k in vars(self.__class__()): + inst_dict.pop(k, None) + copy = self.__class__(self) + copy.__dict__.update(inst_dict) + return copy def __reduce__(self): - return self.__class__, (dict(self),) + inst_dict = vars(self).copy() + for k in vars(self.__class__()): + inst_dict.pop(k, None) + return self.__class__, (dict(self),), inst_dict or None def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' diff -r 8e838598eed1 Lib/test/test_collections.py --- a/Lib/test/test_collections.py Tue Jul 02 09:07:53 2013 -0400 +++ b/Lib/test/test_collections.py Wed Jul 03 18:47:38 2013 +0300 @@ -916,34 +916,39 @@ # Check that counters are copyable, deepcopyable, picklable, and #have a repr/eval round-trip words = Counter('which witch had which witches wrist watch'.split()) - update_test = Counter() - update_test.update(words) - for i, dup in enumerate([ - words.copy(), - copy.copy(words), - copy.deepcopy(words), - pickle.loads(pickle.dumps(words, 0)), - pickle.loads(pickle.dumps(words, 1)), - pickle.loads(pickle.dumps(words, 2)), - pickle.loads(pickle.dumps(words, -1)), - eval(repr(words)), - update_test, - Counter(words), - ]): - msg = (i, dup, words) + words.a = 42 + def check1(dup): self.assertTrue(dup is not words) self.assertEqual(dup, words) self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + check1(eval(repr(words))) + update_test = Counter() + update_test.update(words) + check1(update_test) + check1(Counter(words)) + def check2(dup): + check1(dup) + self.assertTrue(hasattr(dup, 'a')) + self.assertEqual(dup.a, 42) + check2(words.copy()) + check2(copy.copy(words)) + check2(copy.deepcopy(words)) + check2(pickle.loads(pickle.dumps(words, 0))) + check2(pickle.loads(pickle.dumps(words, 1))) + check2(pickle.loads(pickle.dumps(words, 2))) + check2(pickle.loads(pickle.dumps(words, -1))) def test_copy_subclass(self): class MyCounter(Counter): pass c = MyCounter('slartibartfast') + c.a = 42 d = c.copy() self.assertEqual(d, c) self.assertEqual(len(d), len(c)) self.assertEqual(type(d), type(c)) + self.assertEqual(d.a, 42) def test_conversions(self): # Convert to: set, list, dict