2727]
2828
2929import _collections_abc
30- import heapq as _heapq
3130import sys as _sys
3231
3332from itertools import chain as _chain
5655 from ._defaultdict import defaultdict
5756
5857
59- def __getattr__ (name ):
60- # For backwards compatibility, continue to make the collections ABCs
61- # through Python 3.6 available through the collections module.
62- # Note, no new collections ABCs were added in Python 3.7
63- if name in _collections_abc .__all__ :
64- obj = getattr (_collections_abc , name )
65- import warnings
66- warnings .warn ("Using or importing the ABCs from 'collections' instead "
67- "of from 'collections.abc' is deprecated since Python 3.3, "
68- "and in 3.10 it will stop working" ,
69- DeprecationWarning , stacklevel = 2 )
70- globals ()[name ] = obj
71- return obj
72- raise AttributeError (f'module { __name__ !r} has no attribute { name !r} ' )
73-
74-
7558################################################################################
7659### OrderedDict
7760################################################################################
@@ -111,25 +94,18 @@ class OrderedDict(dict):
11194 # Individual links are kept alive by the hard reference in self.__map.
11295 # Those hard references disappear when a key is deleted from an OrderedDict.
11396
114- def __init__ (* args , ** kwds ):
97+ def __init__ (self , other = (), / , ** kwds ):
11598 '''Initialize an ordered dictionary. The signature is the same as
11699 regular dictionaries. Keyword argument order is preserved.
117100 '''
118- if not args :
119- raise TypeError ("descriptor '__init__' of 'OrderedDict' object "
120- "needs an argument" )
121- self , * args = args
122- if len (args ) > 1 :
123- raise TypeError ('expected at most 1 arguments, got %d' % len (args ))
124-
125101 try :
126102 self .__root
127103 except AttributeError :
128104 self .__hardroot = _Link ()
129105 self .__root = root = _proxy (self .__hardroot )
130106 root .prev = root .next = root
131107 self .__map = {}
132- self .__update (* args , ** kwds )
108+ self .__update (other , ** kwds )
133109
134110 def __setitem__ (self , key , value ,
135111 dict_setitem = dict .__setitem__ , proxy = _proxy , Link = _Link ):
@@ -455,8 +431,8 @@ def _make(cls, iterable):
455431 _make .__func__ .__doc__ = (f'Make a new { typename } object from a sequence '
456432 'or iterable' )
457433
458- def _replace (_self , / , ** kwds ):
459- result = _self ._make (_map (kwds .pop , field_names , _self ))
434+ def _replace (self , / , ** kwds ):
435+ result = self ._make (_map (kwds .pop , field_names , self ))
460436 if kwds :
461437 raise ValueError (f'Got unexpected field names: { list (kwds )!r} ' )
462438 return result
@@ -500,6 +476,7 @@ def __getnewargs__(self):
500476 '__repr__' : __repr__ ,
501477 '_asdict' : _asdict ,
502478 '__getnewargs__' : __getnewargs__ ,
479+ '__match_args__' : field_names ,
503480 }
504481 for index , name in enumerate (field_names ):
505482 doc = _sys .intern (f'Alias for field number { index } ' )
@@ -589,7 +566,7 @@ class Counter(dict):
589566 # http://code.activestate.com/recipes/259174/
590567 # Knuth, TAOCP Vol. II section 4.6.3
591568
592- def __init__ (* args , ** kwds ):
569+ def __init__ (self , iterable = None , / , ** kwds ):
593570 '''Create a new, empty Counter object. And if given, count elements
594571 from an input iterable. Or, initialize the count from another mapping
595572 of elements to their counts.
@@ -600,20 +577,18 @@ def __init__(*args, **kwds):
600577 >>> c = Counter(a=4, b=2) # a new counter from keyword args
601578
602579 '''
603- if not args :
604- raise TypeError ("descriptor '__init__' of 'Counter' object "
605- "needs an argument" )
606- self , * args = args
607- if len (args ) > 1 :
608- raise TypeError ('expected at most 1 arguments, got %d' % len (args ))
609- super (Counter , self ).__init__ ()
610- self .update (* args , ** kwds )
580+ super ().__init__ ()
581+ self .update (iterable , ** kwds )
611582
612583 def __missing__ (self , key ):
613584 'The count of elements not in the Counter is zero.'
614585 # Needed so that self[missing_item] does not raise KeyError
615586 return 0
616587
588+ def total (self ):
589+ 'Sum of the counts'
590+ return sum (self .values ())
591+
617592 def most_common (self , n = None ):
618593 '''List the n most common elements and their counts from the most
619594 common to the least. If n is None, then list all element counts.
@@ -625,7 +600,10 @@ def most_common(self, n=None):
625600 # Emulate Bag.sortedByCount from Smalltalk
626601 if n is None :
627602 return sorted (self .items (), key = _itemgetter (1 ), reverse = True )
628- return _heapq .nlargest (n , self .items (), key = _itemgetter (1 ))
603+
604+ # Lazy import to speedup Python startup time
605+ import heapq
606+ return heapq .nlargest (n , self .items (), key = _itemgetter (1 ))
629607
630608 def elements (self ):
631609 '''Iterator over elements repeating each as many times as its count.
@@ -663,7 +641,7 @@ def fromkeys(cls, iterable, v=None):
663641 raise NotImplementedError (
664642 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.' )
665643
666- def update (* args , ** kwds ):
644+ def update (self , iterable = None , / , ** kwds ):
667645 '''Like dict.update() but add counts instead of replacing them.
668646
669647 Source can be an iterable, a dictionary, or another Counter instance.
@@ -683,14 +661,6 @@ def update(*args, **kwds):
683661 # contexts. Instead, we implement straight-addition. Both the inputs
684662 # and outputs are allowed to contain zero and negative counts.
685663
686- if not args :
687- raise TypeError ("descriptor 'update' of 'Counter' object "
688- "needs an argument" )
689- self , * args = args
690- if len (args ) > 1 :
691- raise TypeError ('expected at most 1 arguments, got %d' % len (args ))
692- iterable = args [0 ] if args else None
693-
694664 if iterable is not None :
695665 if isinstance (iterable , _collections_abc .Mapping ):
696666 if self :
@@ -699,13 +669,13 @@ def update(*args, **kwds):
699669 self [elem ] = count + self_get (elem , 0 )
700670 else :
701671 # fast path when counter is empty
702- super (Counter , self ).update (iterable )
672+ super ().update (iterable )
703673 else :
704674 _count_elements (self , iterable )
705675 if kwds :
706676 self .update (kwds )
707677
708- def subtract (* args , ** kwds ):
678+ def subtract (self , iterable = None , / , ** kwds ):
709679 '''Like dict.update() but subtracts counts instead of replacing them.
710680 Counts can be reduced below zero. Both the inputs and outputs are
711681 allowed to contain zero and negative counts.
@@ -721,14 +691,6 @@ def subtract(*args, **kwds):
721691 -1
722692
723693 '''
724- if not args :
725- raise TypeError ("descriptor 'subtract' of 'Counter' object "
726- "needs an argument" )
727- self , * args = args
728- if len (args ) > 1 :
729- raise TypeError ('expected at most 1 arguments, got %d' % len (args ))
730- iterable = args [0 ] if args else None
731-
732694 if iterable is not None :
733695 self_get = self .get
734696 if isinstance (iterable , _collections_abc .Mapping ):
@@ -752,6 +714,42 @@ def __delitem__(self, elem):
752714 if elem in self :
753715 super ().__delitem__ (elem )
754716
717+ def __eq__ (self , other ):
718+ 'True if all counts agree. Missing counts are treated as zero.'
719+ if not isinstance (other , Counter ):
720+ return NotImplemented
721+ return all (self [e ] == other [e ] for c in (self , other ) for e in c )
722+
723+ def __ne__ (self , other ):
724+ 'True if any counts disagree. Missing counts are treated as zero.'
725+ if not isinstance (other , Counter ):
726+ return NotImplemented
727+ return not self == other
728+
729+ def __le__ (self , other ):
730+ 'True if all counts in self are a subset of those in other.'
731+ if not isinstance (other , Counter ):
732+ return NotImplemented
733+ return all (self [e ] <= other [e ] for c in (self , other ) for e in c )
734+
735+ def __lt__ (self , other ):
736+ 'True if all counts in self are a proper subset of those in other.'
737+ if not isinstance (other , Counter ):
738+ return NotImplemented
739+ return self <= other and self != other
740+
741+ def __ge__ (self , other ):
742+ 'True if all counts in self are a superset of those in other.'
743+ if not isinstance (other , Counter ):
744+ return NotImplemented
745+ return all (self [e ] >= other [e ] for c in (self , other ) for e in c )
746+
747+ def __gt__ (self , other ):
748+ 'True if all counts in self are a proper superset of those in other.'
749+ if not isinstance (other , Counter ):
750+ return NotImplemented
751+ return self >= other and self != other
752+
755753 def __repr__ (self ):
756754 if not self :
757755 return f'{ self .__class__ .__name__ } ()'
@@ -772,12 +770,30 @@ def __repr__(self):
772770 # To strip negative and zero counts, add-in an empty counter:
773771 # c += Counter()
774772 #
775- # Rich comparison operators for multiset subset and superset tests
776- # are deliberately omitted due to semantic conflicts with the
777- # existing inherited dict equality method. Subset and superset
778- # semantics ignore zero counts and require that p≤q ∧ p≥q → p=q;
779- # however, that would not be the case for p=Counter(a=1, b=0)
780- # and q=Counter(a=1) where the dictionaries are not equal.
773+ # Results are ordered according to when an element is first
774+ # encountered in the left operand and then by the order
775+ # encountered in the right operand.
776+ #
777+ # When the multiplicities are all zero or one, multiset operations
778+ # are guaranteed to be equivalent to the corresponding operations
779+ # for regular sets.
780+ # Given counter multisets such as:
781+ # cp = Counter(a=1, b=0, c=1)
782+ # cq = Counter(c=1, d=0, e=1)
783+ # The corresponding regular sets would be:
784+ # sp = {'a', 'c'}
785+ # sq = {'c', 'e'}
786+ # All of the following relations would hold:
787+ # set(cp + cq) == sp | sq
788+ # set(cp - cq) == sp - sq
789+ # set(cp | cq) == sp | sq
790+ # set(cp & cq) == sp & sq
791+ # (cp == cq) == (sp == sq)
792+ # (cp != cq) == (sp != sq)
793+ # (cp <= cq) == (sp <= sq)
794+ # (cp < cq) == (sp < sq)
795+ # (cp >= cq) == (sp >= sq)
796+ # (cp > cq) == (sp > sq)
781797
782798 def __add__ (self , other ):
783799 '''Add counts from two counters.
@@ -1006,12 +1022,15 @@ def copy(self):
10061022
10071023 __copy__ = copy
10081024
1009- def new_child (self , m = None ): # like Django's Context.push()
1025+ def new_child (self , m = None , ** kwargs ): # like Django's Context.push()
10101026 '''New ChainMap with a new map followed by all previous maps.
10111027 If no map is provided, an empty dict is used.
1028+ Keyword arguments update the map or new empty dict.
10121029 '''
10131030 if m is None :
1014- m = {}
1031+ m = kwargs
1032+ elif kwargs :
1033+ m .update (kwargs )
10151034 return self .__class__ (m , * self .maps )
10161035
10171036 @property
@@ -1073,34 +1092,16 @@ def __ror__(self, other):
10731092class UserDict (_collections_abc .MutableMapping ):
10741093
10751094 # Start by filling-out the abstract methods
1076- def __init__ (* args , ** kwargs ):
1077- if not args :
1078- raise TypeError ("descriptor '__init__' of 'UserDict' object "
1079- "needs an argument" )
1080- self , * args = args
1081- if len (args ) > 1 :
1082- raise TypeError ('expected at most 1 arguments, got %d' % len (args ))
1083- if args :
1084- dict = args [0 ]
1085- elif 'dict' in kwargs :
1086- dict = kwargs .pop ('dict' )
1087- import warnings
1088- warnings .warn ("Passing 'dict' as keyword argument is deprecated" ,
1089- DeprecationWarning , stacklevel = 2 )
1090- else :
1091- dict = None
1095+ def __init__ (self , dict = None , / , ** kwargs ):
10921096 self .data = {}
10931097 if dict is not None :
10941098 self .update (dict )
1095- if len ( kwargs ) :
1099+ if kwargs :
10961100 self .update (kwargs )
10971101
10981102 def __len__ (self ):
10991103 return len (self .data )
11001104
1101- def __bool__ (self ):
1102- return bool (self .data )
1103-
11041105 def __getitem__ (self , key ):
11051106 if key in self .data :
11061107 return self .data [key ]
@@ -1153,9 +1154,6 @@ def __copy__(self):
11531154 inst .__dict__ ["data" ] = self .__dict__ ["data" ].copy ()
11541155 return inst
11551156
1156- def __sizeof__ (self ):
1157- return _sys .getsizeof (self .data )
1158-
11591157 def copy (self ):
11601158 if self .__class__ is UserDict :
11611159 return UserDict (self .data .copy ())
@@ -1222,9 +1220,6 @@ def __contains__(self, item):
12221220 def __len__ (self ):
12231221 return len (self .data )
12241222
1225- def __bool__ (self ):
1226- return bool (self .data )
1227-
12281223 def __getitem__ (self , i ):
12291224 if isinstance (i , slice ):
12301225 return self .__class__ (self .data [i ])
@@ -1276,9 +1271,6 @@ def __copy__(self):
12761271 inst .__dict__ ["data" ] = self .__dict__ ["data" ][:]
12771272 return inst
12781273
1279- def __sizeof__ (self ):
1280- return _sys .getsizeof (self .data )
1281-
12821274 def append (self , item ):
12831275 self .data .append (item )
12841276
@@ -1381,9 +1373,6 @@ def __contains__(self, char):
13811373 char = char .data
13821374 return char in self .data
13831375
1384- def __bool__ (self ):
1385- return bool (self .data )
1386-
13871376 def __len__ (self ):
13881377 return len (self .data )
13891378
@@ -1413,9 +1402,6 @@ def __mod__(self, args):
14131402 def __rmod__ (self , template ):
14141403 return self .__class__ (str (template ) % self )
14151404
1416- def __sizeof__ (self ):
1417- return _sys .getsizeof (self .data )
1418-
14191405 # the following methods are defined in alphabetical order:
14201406 def capitalize (self ):
14211407 return self .__class__ (self .data .capitalize ())
@@ -1571,4 +1557,4 @@ def upper(self):
15711557 return self .__class__ (self .data .upper ())
15721558
15731559 def zfill (self , width ):
1574- return self .__class__ (self .data .zfill (width ))
1560+ return self .__class__ (self .data .zfill (width ))
0 commit comments