27
27
]
28
28
29
29
import _collections_abc
30
- import heapq as _heapq
31
30
import sys as _sys
32
31
33
32
from itertools import chain as _chain
56
55
from ._defaultdict import defaultdict
57
56
58
57
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
-
75
58
################################################################################
76
59
### OrderedDict
77
60
################################################################################
@@ -111,25 +94,18 @@ class OrderedDict(dict):
111
94
# Individual links are kept alive by the hard reference in self.__map.
112
95
# Those hard references disappear when a key is deleted from an OrderedDict.
113
96
114
- def __init__ (* args , ** kwds ):
97
+ def __init__ (self , other = (), / , ** kwds ):
115
98
'''Initialize an ordered dictionary. The signature is the same as
116
99
regular dictionaries. Keyword argument order is preserved.
117
100
'''
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
-
125
101
try :
126
102
self .__root
127
103
except AttributeError :
128
104
self .__hardroot = _Link ()
129
105
self .__root = root = _proxy (self .__hardroot )
130
106
root .prev = root .next = root
131
107
self .__map = {}
132
- self .__update (* args , ** kwds )
108
+ self .__update (other , ** kwds )
133
109
134
110
def __setitem__ (self , key , value ,
135
111
dict_setitem = dict .__setitem__ , proxy = _proxy , Link = _Link ):
@@ -455,8 +431,8 @@ def _make(cls, iterable):
455
431
_make .__func__ .__doc__ = (f'Make a new { typename } object from a sequence '
456
432
'or iterable' )
457
433
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 ))
460
436
if kwds :
461
437
raise ValueError (f'Got unexpected field names: { list (kwds )!r} ' )
462
438
return result
@@ -500,6 +476,7 @@ def __getnewargs__(self):
500
476
'__repr__' : __repr__ ,
501
477
'_asdict' : _asdict ,
502
478
'__getnewargs__' : __getnewargs__ ,
479
+ '__match_args__' : field_names ,
503
480
}
504
481
for index , name in enumerate (field_names ):
505
482
doc = _sys .intern (f'Alias for field number { index } ' )
@@ -589,7 +566,7 @@ class Counter(dict):
589
566
# http://code.activestate.com/recipes/259174/
590
567
# Knuth, TAOCP Vol. II section 4.6.3
591
568
592
- def __init__ (* args , ** kwds ):
569
+ def __init__ (self , iterable = None , / , ** kwds ):
593
570
'''Create a new, empty Counter object. And if given, count elements
594
571
from an input iterable. Or, initialize the count from another mapping
595
572
of elements to their counts.
@@ -600,20 +577,18 @@ def __init__(*args, **kwds):
600
577
>>> c = Counter(a=4, b=2) # a new counter from keyword args
601
578
602
579
'''
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 )
611
582
612
583
def __missing__ (self , key ):
613
584
'The count of elements not in the Counter is zero.'
614
585
# Needed so that self[missing_item] does not raise KeyError
615
586
return 0
616
587
588
+ def total (self ):
589
+ 'Sum of the counts'
590
+ return sum (self .values ())
591
+
617
592
def most_common (self , n = None ):
618
593
'''List the n most common elements and their counts from the most
619
594
common to the least. If n is None, then list all element counts.
@@ -625,7 +600,10 @@ def most_common(self, n=None):
625
600
# Emulate Bag.sortedByCount from Smalltalk
626
601
if n is None :
627
602
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 ))
629
607
630
608
def elements (self ):
631
609
'''Iterator over elements repeating each as many times as its count.
@@ -663,7 +641,7 @@ def fromkeys(cls, iterable, v=None):
663
641
raise NotImplementedError (
664
642
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.' )
665
643
666
- def update (* args , ** kwds ):
644
+ def update (self , iterable = None , / , ** kwds ):
667
645
'''Like dict.update() but add counts instead of replacing them.
668
646
669
647
Source can be an iterable, a dictionary, or another Counter instance.
@@ -683,14 +661,6 @@ def update(*args, **kwds):
683
661
# contexts. Instead, we implement straight-addition. Both the inputs
684
662
# and outputs are allowed to contain zero and negative counts.
685
663
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
-
694
664
if iterable is not None :
695
665
if isinstance (iterable , _collections_abc .Mapping ):
696
666
if self :
@@ -699,13 +669,13 @@ def update(*args, **kwds):
699
669
self [elem ] = count + self_get (elem , 0 )
700
670
else :
701
671
# fast path when counter is empty
702
- super (Counter , self ).update (iterable )
672
+ super ().update (iterable )
703
673
else :
704
674
_count_elements (self , iterable )
705
675
if kwds :
706
676
self .update (kwds )
707
677
708
- def subtract (* args , ** kwds ):
678
+ def subtract (self , iterable = None , / , ** kwds ):
709
679
'''Like dict.update() but subtracts counts instead of replacing them.
710
680
Counts can be reduced below zero. Both the inputs and outputs are
711
681
allowed to contain zero and negative counts.
@@ -721,14 +691,6 @@ def subtract(*args, **kwds):
721
691
-1
722
692
723
693
'''
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
-
732
694
if iterable is not None :
733
695
self_get = self .get
734
696
if isinstance (iterable , _collections_abc .Mapping ):
@@ -752,6 +714,42 @@ def __delitem__(self, elem):
752
714
if elem in self :
753
715
super ().__delitem__ (elem )
754
716
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
+
755
753
def __repr__ (self ):
756
754
if not self :
757
755
return f'{ self .__class__ .__name__ } ()'
@@ -772,12 +770,30 @@ def __repr__(self):
772
770
# To strip negative and zero counts, add-in an empty counter:
773
771
# c += Counter()
774
772
#
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)
781
797
782
798
def __add__ (self , other ):
783
799
'''Add counts from two counters.
@@ -1006,12 +1022,15 @@ def copy(self):
1006
1022
1007
1023
__copy__ = copy
1008
1024
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()
1010
1026
'''New ChainMap with a new map followed by all previous maps.
1011
1027
If no map is provided, an empty dict is used.
1028
+ Keyword arguments update the map or new empty dict.
1012
1029
'''
1013
1030
if m is None :
1014
- m = {}
1031
+ m = kwargs
1032
+ elif kwargs :
1033
+ m .update (kwargs )
1015
1034
return self .__class__ (m , * self .maps )
1016
1035
1017
1036
@property
@@ -1073,34 +1092,16 @@ def __ror__(self, other):
1073
1092
class UserDict (_collections_abc .MutableMapping ):
1074
1093
1075
1094
# 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 ):
1092
1096
self .data = {}
1093
1097
if dict is not None :
1094
1098
self .update (dict )
1095
- if len ( kwargs ) :
1099
+ if kwargs :
1096
1100
self .update (kwargs )
1097
1101
1098
1102
def __len__ (self ):
1099
1103
return len (self .data )
1100
1104
1101
- def __bool__ (self ):
1102
- return bool (self .data )
1103
-
1104
1105
def __getitem__ (self , key ):
1105
1106
if key in self .data :
1106
1107
return self .data [key ]
@@ -1153,9 +1154,6 @@ def __copy__(self):
1153
1154
inst .__dict__ ["data" ] = self .__dict__ ["data" ].copy ()
1154
1155
return inst
1155
1156
1156
- def __sizeof__ (self ):
1157
- return _sys .getsizeof (self .data )
1158
-
1159
1157
def copy (self ):
1160
1158
if self .__class__ is UserDict :
1161
1159
return UserDict (self .data .copy ())
@@ -1222,9 +1220,6 @@ def __contains__(self, item):
1222
1220
def __len__ (self ):
1223
1221
return len (self .data )
1224
1222
1225
- def __bool__ (self ):
1226
- return bool (self .data )
1227
-
1228
1223
def __getitem__ (self , i ):
1229
1224
if isinstance (i , slice ):
1230
1225
return self .__class__ (self .data [i ])
@@ -1276,9 +1271,6 @@ def __copy__(self):
1276
1271
inst .__dict__ ["data" ] = self .__dict__ ["data" ][:]
1277
1272
return inst
1278
1273
1279
- def __sizeof__ (self ):
1280
- return _sys .getsizeof (self .data )
1281
-
1282
1274
def append (self , item ):
1283
1275
self .data .append (item )
1284
1276
@@ -1381,9 +1373,6 @@ def __contains__(self, char):
1381
1373
char = char .data
1382
1374
return char in self .data
1383
1375
1384
- def __bool__ (self ):
1385
- return bool (self .data )
1386
-
1387
1376
def __len__ (self ):
1388
1377
return len (self .data )
1389
1378
@@ -1413,9 +1402,6 @@ def __mod__(self, args):
1413
1402
def __rmod__ (self , template ):
1414
1403
return self .__class__ (str (template ) % self )
1415
1404
1416
- def __sizeof__ (self ):
1417
- return _sys .getsizeof (self .data )
1418
-
1419
1405
# the following methods are defined in alphabetical order:
1420
1406
def capitalize (self ):
1421
1407
return self .__class__ (self .data .capitalize ())
@@ -1571,4 +1557,4 @@ def upper(self):
1571
1557
return self .__class__ (self .data .upper ())
1572
1558
1573
1559
def zfill (self , width ):
1574
- return self .__class__ (self .data .zfill (width ))
1560
+ return self .__class__ (self .data .zfill (width ))
0 commit comments