[Python-checkins] cpython (2.7): Issue #22609: Constructors and update methods of mapping classes in the

serhiy.storchaka python-checkins at python.org
Thu Nov 27 18:05:28 CET 2014


https://hg.python.org/cpython/rev/3dfe4f0c626b
changeset: 93623:3dfe4f0c626b
branch: 2.7
parent: 93618:ac65f90c1214
user: Serhiy Storchaka <storchaka at gmail.com>
date: Thu Nov 27 19:02:56 2014 +0200
summary:
 Issue #22609: Constructors and update methods of mapping classes in the
collections module now accept the self keyword argument.
files:
 Lib/_abcoll.py | 34 ++++++++++--------
 Lib/collections.py | 38 ++++++++++++++++++--
 Lib/test/test_collections.py | 43 ++++++++++++++++++++++-
 Misc/NEWS | 3 +
 4 files changed, 95 insertions(+), 23 deletions(-)
diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py
--- a/Lib/_abcoll.py
+++ b/Lib/_abcoll.py
@@ -548,23 +548,25 @@
 If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v
 In either case, this is followed by: for k, v in F.items(): D[k] = v
 '''
- if len(args) > 2:
- raise TypeError("update() takes at most 2 positional "
- "arguments ({} given)".format(len(args)))
- elif not args:
- raise TypeError("update() takes at least 1 argument (0 given)")
+ if not args:
+ raise TypeError("descriptor 'update' of 'MutableMapping' object "
+ "needs an argument")
 self = args[0]
- other = args[1] if len(args) >= 2 else ()
-
- if isinstance(other, Mapping):
- for key in other:
- self[key] = other[key]
- elif hasattr(other, "keys"):
- for key in other.keys():
- self[key] = other[key]
- else:
- for key, value in other:
- self[key] = value
+ args = args[1:]
+ if len(args) > 1:
+ raise TypeError('update expected at most 1 arguments, got %d' %
+ len(args))
+ if args:
+ other = args[0]
+ if isinstance(other, Mapping):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, "keys"):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
 for key, value in kwds.items():
 self[key] = value
 
diff --git a/Lib/collections.py b/Lib/collections.py
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -35,12 +35,17 @@
 # The sentinel element never gets deleted (this simplifies the algorithm).
 # Each link is stored as a list of length three: [PREV, NEXT, KEY].
 
- def __init__(self, *args, **kwds):
+ def __init__(*args, **kwds):
 '''Initialize an ordered dictionary. The signature is the same as
 regular dictionaries, but keyword arguments are not recommended because
 their insertion order is arbitrary.
 
 '''
+ if not args:
+ raise TypeError("descriptor '__init__' of 'OrderedDict' object "
+ "needs an argument")
+ self = args[0]
+ args = args[1:]
 if len(args) > 1:
 raise TypeError('expected at most 1 arguments, got %d' % len(args))
 try:
@@ -438,7 +443,7 @@
 # http://code.activestate.com/recipes/259174/
 # Knuth, TAOCP Vol. II section 4.6.3
 
- def __init__(self, iterable=None, **kwds):
+ def __init__(*args, **kwds):
 '''Create a new, empty Counter object. And if given, count elements
 from an input iterable. Or, initialize the count from another mapping
 of elements to their counts.
@@ -449,8 +454,15 @@
 >>> c = Counter(a=4, b=2) # a new counter from keyword args
 
 '''
+ if not args:
+ raise TypeError("descriptor '__init__' of 'Counter' object "
+ "needs an argument")
+ self = args[0]
+ args = args[1:]
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
 super(Counter, self).__init__()
- self.update(iterable, **kwds)
+ self.update(*args, **kwds)
 
 def __missing__(self, key):
 'The count of elements not in the Counter is zero.'
@@ -501,7 +513,7 @@
 raise NotImplementedError(
 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
 
- def update(self, iterable=None, **kwds):
+ def update(*args, **kwds):
 '''Like dict.update() but add counts instead of replacing them.
 
 Source can be an iterable, a dictionary, or another Counter instance.
@@ -521,6 +533,14 @@
 # contexts. Instead, we implement straight-addition. Both the inputs
 # and outputs are allowed to contain zero and negative counts.
 
+ if not args:
+ raise TypeError("descriptor 'update' of 'Counter' object "
+ "needs an argument")
+ self = args[0]
+ args = args[1:]
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ iterable = args[0] if args else None
 if iterable is not None:
 if isinstance(iterable, Mapping):
 if self:
@@ -536,7 +556,7 @@
 if kwds:
 self.update(kwds)
 
- def subtract(self, iterable=None, **kwds):
+ def subtract(*args, **kwds):
 '''Like dict.update() but subtracts counts instead of replacing them.
 Counts can be reduced below zero. Both the inputs and outputs are
 allowed to contain zero and negative counts.
@@ -552,6 +572,14 @@
 -1
 
 '''
+ if not args:
+ raise TypeError("descriptor 'subtract' of 'Counter' object "
+ "needs an argument")
+ self = args[0]
+ args = args[1:]
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ iterable = args[0] if args else None
 if iterable is not None:
 self_get = self.get
 if isinstance(iterable, Mapping):
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -905,6 +905,28 @@
 self.assertEqual(c.setdefault('e', 5), 5)
 self.assertEqual(c['e'], 5)
 
+ def test_init(self):
+ self.assertEqual(list(Counter(self=42).items()), [('self', 42)])
+ self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)])
+ self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)])
+ self.assertRaises(TypeError, Counter, 42)
+ self.assertRaises(TypeError, Counter, (), ())
+ self.assertRaises(TypeError, Counter.__init__)
+
+ def test_update(self):
+ c = Counter()
+ c.update(self=42)
+ self.assertEqual(list(c.items()), [('self', 42)])
+ c = Counter()
+ c.update(iterable=42)
+ self.assertEqual(list(c.items()), [('iterable', 42)])
+ c = Counter()
+ c.update(iterable=None)
+ self.assertEqual(list(c.items()), [('iterable', None)])
+ self.assertRaises(TypeError, Counter().update, 42)
+ self.assertRaises(TypeError, Counter().update, {}, {})
+ self.assertRaises(TypeError, Counter.update)
+
 def test_copying(self):
 # Check that counters are copyable, deepcopyable, picklable, and
 #have a repr/eval round-trip
@@ -1006,6 +1028,16 @@
 c.subtract('aaaabbcce')
 self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1))
 
+ c = Counter()
+ c.subtract(self=42)
+ self.assertEqual(list(c.items()), [('self', -42)])
+ c = Counter()
+ c.subtract(iterable=42)
+ self.assertEqual(list(c.items()), [('iterable', -42)])
+ self.assertRaises(TypeError, Counter().subtract, 42)
+ self.assertRaises(TypeError, Counter().subtract, {}, {})
+ self.assertRaises(TypeError, Counter.subtract)
+
 class TestOrderedDict(unittest.TestCase):
 
 def test_init(self):
@@ -1019,8 +1051,11 @@
 c=3, e=5).items()), pairs) # mixed input
 
 # make sure no positional args conflict with possible kwdargs
- self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args,
- ['self'])
+ self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)])
+ self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)])
+ self.assertRaises(TypeError, OrderedDict, 42)
+ self.assertRaises(TypeError, OrderedDict, (), ())
+ self.assertRaises(TypeError, OrderedDict.__init__)
 
 # Make sure that direct calls to __init__ do not clear previous contents
 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
@@ -1065,6 +1100,10 @@
 self.assertEqual(list(d.items()),
 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
 
+ self.assertRaises(TypeError, OrderedDict().update, 42)
+ self.assertRaises(TypeError, OrderedDict().update, (), ())
+ self.assertRaises(TypeError, OrderedDict.update)
+
 def test_abc(self):
 self.assertIsInstance(OrderedDict(), MutableMapping)
 self.assertTrue(issubclass(OrderedDict, MutableMapping))
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,9 @@
 Library
 -------
 
+- Issue #22609: Constructors and update methods of mapping classes in the
+ collections module now accept the self keyword argument.
+
 
 What's New in Python 2.7.9 release candidate 1?
 ===============================================
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /