1 | n/a | '''This module implements specialized container datatypes providing |
---|
2 | n/a | alternatives to Python's general purpose built-in containers, dict, |
---|
3 | n/a | list, set, and tuple. |
---|
4 | n/a | |
---|
5 | n/a | * namedtuple factory function for creating tuple subclasses with named fields |
---|
6 | n/a | * deque list-like container with fast appends and pops on either end |
---|
7 | n/a | * ChainMap dict-like class for creating a single view of multiple mappings |
---|
8 | n/a | * Counter dict subclass for counting hashable objects |
---|
9 | n/a | * OrderedDict dict subclass that remembers the order entries were added |
---|
10 | n/a | * defaultdict dict subclass that calls a factory function to supply missing values |
---|
11 | n/a | * UserDict wrapper around dictionary objects for easier dict subclassing |
---|
12 | n/a | * UserList wrapper around list objects for easier list subclassing |
---|
13 | n/a | * UserString wrapper around string objects for easier string subclassing |
---|
14 | n/a | |
---|
15 | n/a | ''' |
---|
16 | n/a | |
---|
17 | n/a | __all__ = ['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList', |
---|
18 | n/a | 'UserString', 'Counter', 'OrderedDict', 'ChainMap'] |
---|
19 | n/a | |
---|
20 | n/a | # For backwards compatibility, continue to make the collections ABCs |
---|
21 | n/a | # available through the collections module. |
---|
22 | n/a | from _collections_abc import * |
---|
23 | n/a | import _collections_abc |
---|
24 | n/a | __all__ += _collections_abc.__all__ |
---|
25 | n/a | |
---|
26 | n/a | from operator import itemgetter as _itemgetter, eq as _eq |
---|
27 | n/a | from keyword import iskeyword as _iskeyword |
---|
28 | n/a | import sys as _sys |
---|
29 | n/a | import heapq as _heapq |
---|
30 | n/a | from _weakref import proxy as _proxy |
---|
31 | n/a | from itertools import repeat as _repeat, chain as _chain, starmap as _starmap |
---|
32 | n/a | from reprlib import recursive_repr as _recursive_repr |
---|
33 | n/a | |
---|
34 | n/a | try: |
---|
35 | n/a | from _collections import deque |
---|
36 | n/a | except ImportError: |
---|
37 | n/a | pass |
---|
38 | n/a | else: |
---|
39 | n/a | MutableSequence.register(deque) |
---|
40 | n/a | |
---|
41 | n/a | try: |
---|
42 | n/a | from _collections import defaultdict |
---|
43 | n/a | except ImportError: |
---|
44 | n/a | pass |
---|
45 | n/a | |
---|
46 | n/a | |
---|
47 | n/a | ################################################################################ |
---|
48 | n/a | ### OrderedDict |
---|
49 | n/a | ################################################################################ |
---|
50 | n/a | |
---|
51 | n/a | class _OrderedDictKeysView(KeysView): |
---|
52 | n/a | |
---|
53 | n/a | def __reversed__(self): |
---|
54 | n/a | yield from reversed(self._mapping) |
---|
55 | n/a | |
---|
56 | n/a | class _OrderedDictItemsView(ItemsView): |
---|
57 | n/a | |
---|
58 | n/a | def __reversed__(self): |
---|
59 | n/a | for key in reversed(self._mapping): |
---|
60 | n/a | yield (key, self._mapping[key]) |
---|
61 | n/a | |
---|
62 | n/a | class _OrderedDictValuesView(ValuesView): |
---|
63 | n/a | |
---|
64 | n/a | def __reversed__(self): |
---|
65 | n/a | for key in reversed(self._mapping): |
---|
66 | n/a | yield self._mapping[key] |
---|
67 | n/a | |
---|
68 | n/a | class _Link(object): |
---|
69 | n/a | __slots__ = 'prev', 'next', 'key', '__weakref__' |
---|
70 | n/a | |
---|
71 | n/a | class OrderedDict(dict): |
---|
72 | n/a | 'Dictionary that remembers insertion order' |
---|
73 | n/a | # An inherited dict maps keys to values. |
---|
74 | n/a | # The inherited dict provides __getitem__, __len__, __contains__, and get. |
---|
75 | n/a | # The remaining methods are order-aware. |
---|
76 | n/a | # Big-O running times for all methods are the same as regular dictionaries. |
---|
77 | n/a | |
---|
78 | n/a | # The internal self.__map dict maps keys to links in a doubly linked list. |
---|
79 | n/a | # The circular doubly linked list starts and ends with a sentinel element. |
---|
80 | n/a | # The sentinel element never gets deleted (this simplifies the algorithm). |
---|
81 | n/a | # The sentinel is in self.__hardroot with a weakref proxy in self.__root. |
---|
82 | n/a | # The prev links are weakref proxies (to prevent circular references). |
---|
83 | n/a | # Individual links are kept alive by the hard reference in self.__map. |
---|
84 | n/a | # Those hard references disappear when a key is deleted from an OrderedDict. |
---|
85 | n/a | |
---|
86 | n/a | def __init__(*args, **kwds): |
---|
87 | n/a | '''Initialize an ordered dictionary. The signature is the same as |
---|
88 | n/a | regular dictionaries, but keyword arguments are not recommended because |
---|
89 | n/a | their insertion order is arbitrary. |
---|
90 | n/a | |
---|
91 | n/a | ''' |
---|
92 | n/a | if not args: |
---|
93 | n/a | raise TypeError("descriptor '__init__' of 'OrderedDict' object " |
---|
94 | n/a | "needs an argument") |
---|
95 | n/a | self, *args = args |
---|
96 | n/a | if len(args) > 1: |
---|
97 | n/a | raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
---|
98 | n/a | try: |
---|
99 | n/a | self.__root |
---|
100 | n/a | except AttributeError: |
---|
101 | n/a | self.__hardroot = _Link() |
---|
102 | n/a | self.__root = root = _proxy(self.__hardroot) |
---|
103 | n/a | root.prev = root.next = root |
---|
104 | n/a | self.__map = {} |
---|
105 | n/a | self.__update(*args, **kwds) |
---|
106 | n/a | |
---|
107 | n/a | def __setitem__(self, key, value, |
---|
108 | n/a | dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): |
---|
109 | n/a | 'od.__setitem__(i, y) <==> od[i]=y' |
---|
110 | n/a | # Setting a new item creates a new link at the end of the linked list, |
---|
111 | n/a | # and the inherited dictionary is updated with the new key/value pair. |
---|
112 | n/a | if key not in self: |
---|
113 | n/a | self.__map[key] = link = Link() |
---|
114 | n/a | root = self.__root |
---|
115 | n/a | last = root.prev |
---|
116 | n/a | link.prev, link.next, link.key = last, root, key |
---|
117 | n/a | last.next = link |
---|
118 | n/a | root.prev = proxy(link) |
---|
119 | n/a | dict_setitem(self, key, value) |
---|
120 | n/a | |
---|
121 | n/a | def __delitem__(self, key, dict_delitem=dict.__delitem__): |
---|
122 | n/a | 'od.__delitem__(y) <==> del od[y]' |
---|
123 | n/a | # Deleting an existing item uses self.__map to find the link which gets |
---|
124 | n/a | # removed by updating the links in the predecessor and successor nodes. |
---|
125 | n/a | dict_delitem(self, key) |
---|
126 | n/a | link = self.__map.pop(key) |
---|
127 | n/a | link_prev = link.prev |
---|
128 | n/a | link_next = link.next |
---|
129 | n/a | link_prev.next = link_next |
---|
130 | n/a | link_next.prev = link_prev |
---|
131 | n/a | link.prev = None |
---|
132 | n/a | link.next = None |
---|
133 | n/a | |
---|
134 | n/a | def __iter__(self): |
---|
135 | n/a | 'od.__iter__() <==> iter(od)' |
---|
136 | n/a | # Traverse the linked list in order. |
---|
137 | n/a | root = self.__root |
---|
138 | n/a | curr = root.next |
---|
139 | n/a | while curr is not root: |
---|
140 | n/a | yield curr.key |
---|
141 | n/a | curr = curr.next |
---|
142 | n/a | |
---|
143 | n/a | def __reversed__(self): |
---|
144 | n/a | 'od.__reversed__() <==> reversed(od)' |
---|
145 | n/a | # Traverse the linked list in reverse order. |
---|
146 | n/a | root = self.__root |
---|
147 | n/a | curr = root.prev |
---|
148 | n/a | while curr is not root: |
---|
149 | n/a | yield curr.key |
---|
150 | n/a | curr = curr.prev |
---|
151 | n/a | |
---|
152 | n/a | def clear(self): |
---|
153 | n/a | 'od.clear() -> None. Remove all items from od.' |
---|
154 | n/a | root = self.__root |
---|
155 | n/a | root.prev = root.next = root |
---|
156 | n/a | self.__map.clear() |
---|
157 | n/a | dict.clear(self) |
---|
158 | n/a | |
---|
159 | n/a | def popitem(self, last=True): |
---|
160 | n/a | '''Remove and return a (key, value) pair from the dictionary. |
---|
161 | n/a | |
---|
162 | n/a | Pairs are returned in LIFO order if last is true or FIFO order if false. |
---|
163 | n/a | ''' |
---|
164 | n/a | if not self: |
---|
165 | n/a | raise KeyError('dictionary is empty') |
---|
166 | n/a | root = self.__root |
---|
167 | n/a | if last: |
---|
168 | n/a | link = root.prev |
---|
169 | n/a | link_prev = link.prev |
---|
170 | n/a | link_prev.next = root |
---|
171 | n/a | root.prev = link_prev |
---|
172 | n/a | else: |
---|
173 | n/a | link = root.next |
---|
174 | n/a | link_next = link.next |
---|
175 | n/a | root.next = link_next |
---|
176 | n/a | link_next.prev = root |
---|
177 | n/a | key = link.key |
---|
178 | n/a | del self.__map[key] |
---|
179 | n/a | value = dict.pop(self, key) |
---|
180 | n/a | return key, value |
---|
181 | n/a | |
---|
182 | n/a | def move_to_end(self, key, last=True): |
---|
183 | n/a | '''Move an existing element to the end (or beginning if last is false). |
---|
184 | n/a | |
---|
185 | n/a | Raise KeyError if the element does not exist. |
---|
186 | n/a | ''' |
---|
187 | n/a | link = self.__map[key] |
---|
188 | n/a | link_prev = link.prev |
---|
189 | n/a | link_next = link.next |
---|
190 | n/a | soft_link = link_next.prev |
---|
191 | n/a | link_prev.next = link_next |
---|
192 | n/a | link_next.prev = link_prev |
---|
193 | n/a | root = self.__root |
---|
194 | n/a | if last: |
---|
195 | n/a | last = root.prev |
---|
196 | n/a | link.prev = last |
---|
197 | n/a | link.next = root |
---|
198 | n/a | root.prev = soft_link |
---|
199 | n/a | last.next = link |
---|
200 | n/a | else: |
---|
201 | n/a | first = root.next |
---|
202 | n/a | link.prev = root |
---|
203 | n/a | link.next = first |
---|
204 | n/a | first.prev = soft_link |
---|
205 | n/a | root.next = link |
---|
206 | n/a | |
---|
207 | n/a | def __sizeof__(self): |
---|
208 | n/a | sizeof = _sys.getsizeof |
---|
209 | n/a | n = len(self) + 1 # number of links including root |
---|
210 | n/a | size = sizeof(self.__dict__) # instance dictionary |
---|
211 | n/a | size += sizeof(self.__map) * 2 # internal dict and inherited dict |
---|
212 | n/a | size += sizeof(self.__hardroot) * n # link objects |
---|
213 | n/a | size += sizeof(self.__root) * n # proxy objects |
---|
214 | n/a | return size |
---|
215 | n/a | |
---|
216 | n/a | update = __update = MutableMapping.update |
---|
217 | n/a | |
---|
218 | n/a | def keys(self): |
---|
219 | n/a | "D.keys() -> a set-like object providing a view on D's keys" |
---|
220 | n/a | return _OrderedDictKeysView(self) |
---|
221 | n/a | |
---|
222 | n/a | def items(self): |
---|
223 | n/a | "D.items() -> a set-like object providing a view on D's items" |
---|
224 | n/a | return _OrderedDictItemsView(self) |
---|
225 | n/a | |
---|
226 | n/a | def values(self): |
---|
227 | n/a | "D.values() -> an object providing a view on D's values" |
---|
228 | n/a | return _OrderedDictValuesView(self) |
---|
229 | n/a | |
---|
230 | n/a | __ne__ = MutableMapping.__ne__ |
---|
231 | n/a | |
---|
232 | n/a | __marker = object() |
---|
233 | n/a | |
---|
234 | n/a | def pop(self, key, default=__marker): |
---|
235 | n/a | '''od.pop(k[,d]) -> v, remove specified key and return the corresponding |
---|
236 | n/a | value. If key is not found, d is returned if given, otherwise KeyError |
---|
237 | n/a | is raised. |
---|
238 | n/a | |
---|
239 | n/a | ''' |
---|
240 | n/a | if key in self: |
---|
241 | n/a | result = self[key] |
---|
242 | n/a | del self[key] |
---|
243 | n/a | return result |
---|
244 | n/a | if default is self.__marker: |
---|
245 | n/a | raise KeyError(key) |
---|
246 | n/a | return default |
---|
247 | n/a | |
---|
248 | n/a | def setdefault(self, key, default=None): |
---|
249 | n/a | '''Insert key with a value of default if key is not in the dictionary. |
---|
250 | n/a | |
---|
251 | n/a | Return the value for key if key is in the dictionary, else default. |
---|
252 | n/a | ''' |
---|
253 | n/a | if key in self: |
---|
254 | n/a | return self[key] |
---|
255 | n/a | self[key] = default |
---|
256 | n/a | return default |
---|
257 | n/a | |
---|
258 | n/a | @_recursive_repr() |
---|
259 | n/a | def __repr__(self): |
---|
260 | n/a | 'od.__repr__() <==> repr(od)' |
---|
261 | n/a | if not self: |
---|
262 | n/a | return '%s()' % (self.__class__.__name__,) |
---|
263 | n/a | return '%s(%r)' % (self.__class__.__name__, list(self.items())) |
---|
264 | n/a | |
---|
265 | n/a | def __reduce__(self): |
---|
266 | n/a | 'Return state information for pickling' |
---|
267 | n/a | inst_dict = vars(self).copy() |
---|
268 | n/a | for k in vars(OrderedDict()): |
---|
269 | n/a | inst_dict.pop(k, None) |
---|
270 | n/a | return self.__class__, (), inst_dict or None, None, iter(self.items()) |
---|
271 | n/a | |
---|
272 | n/a | def copy(self): |
---|
273 | n/a | 'od.copy() -> a shallow copy of od' |
---|
274 | n/a | return self.__class__(self) |
---|
275 | n/a | |
---|
276 | n/a | @classmethod |
---|
277 | n/a | def fromkeys(cls, iterable, value=None): |
---|
278 | n/a | '''Create a new ordered dictionary with keys from iterable and values set to value. |
---|
279 | n/a | ''' |
---|
280 | n/a | self = cls() |
---|
281 | n/a | for key in iterable: |
---|
282 | n/a | self[key] = value |
---|
283 | n/a | return self |
---|
284 | n/a | |
---|
285 | n/a | def __eq__(self, other): |
---|
286 | n/a | '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive |
---|
287 | n/a | while comparison to a regular mapping is order-insensitive. |
---|
288 | n/a | |
---|
289 | n/a | ''' |
---|
290 | n/a | if isinstance(other, OrderedDict): |
---|
291 | n/a | return dict.__eq__(self, other) and all(map(_eq, self, other)) |
---|
292 | n/a | return dict.__eq__(self, other) |
---|
293 | n/a | |
---|
294 | n/a | |
---|
295 | n/a | try: |
---|
296 | n/a | from _collections import OrderedDict |
---|
297 | n/a | except ImportError: |
---|
298 | n/a | # Leave the pure Python version in place. |
---|
299 | n/a | pass |
---|
300 | n/a | |
---|
301 | n/a | |
---|
302 | n/a | ################################################################################ |
---|
303 | n/a | ### namedtuple |
---|
304 | n/a | ################################################################################ |
---|
305 | n/a | |
---|
306 | n/a | _class_template = """\ |
---|
307 | n/a | from builtins import property as _property, tuple as _tuple |
---|
308 | n/a | from operator import itemgetter as _itemgetter |
---|
309 | n/a | from collections import OrderedDict |
---|
310 | n/a | |
---|
311 | n/a | class {typename}(tuple): |
---|
312 | n/a | '{typename}({arg_list})' |
---|
313 | n/a | |
---|
314 | n/a | __slots__ = () |
---|
315 | n/a | |
---|
316 | n/a | _fields = {field_names!r} |
---|
317 | n/a | |
---|
318 | n/a | def __new__(_cls, {arg_list}): |
---|
319 | n/a | 'Create new instance of {typename}({arg_list})' |
---|
320 | n/a | return _tuple.__new__(_cls, ({arg_list})) |
---|
321 | n/a | |
---|
322 | n/a | @classmethod |
---|
323 | n/a | def _make(cls, iterable, new=tuple.__new__, len=len): |
---|
324 | n/a | 'Make a new {typename} object from a sequence or iterable' |
---|
325 | n/a | result = new(cls, iterable) |
---|
326 | n/a | if len(result) != {num_fields:d}: |
---|
327 | n/a | raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result)) |
---|
328 | n/a | return result |
---|
329 | n/a | |
---|
330 | n/a | def _replace(_self, **kwds): |
---|
331 | n/a | 'Return a new {typename} object replacing specified fields with new values' |
---|
332 | n/a | result = _self._make(map(kwds.pop, {field_names!r}, _self)) |
---|
333 | n/a | if kwds: |
---|
334 | n/a | raise ValueError('Got unexpected field names: %r' % list(kwds)) |
---|
335 | n/a | return result |
---|
336 | n/a | |
---|
337 | n/a | def __repr__(self): |
---|
338 | n/a | 'Return a nicely formatted representation string' |
---|
339 | n/a | return self.__class__.__name__ + '({repr_fmt})' % self |
---|
340 | n/a | |
---|
341 | n/a | def _asdict(self): |
---|
342 | n/a | 'Return a new OrderedDict which maps field names to their values.' |
---|
343 | n/a | return OrderedDict(zip(self._fields, self)) |
---|
344 | n/a | |
---|
345 | n/a | def __getnewargs__(self): |
---|
346 | n/a | 'Return self as a plain tuple. Used by copy and pickle.' |
---|
347 | n/a | return tuple(self) |
---|
348 | n/a | |
---|
349 | n/a | {field_defs} |
---|
350 | n/a | """ |
---|
351 | n/a | |
---|
352 | n/a | _repr_template = '{name}=%r' |
---|
353 | n/a | |
---|
354 | n/a | _field_template = '''\ |
---|
355 | n/a | {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}') |
---|
356 | n/a | ''' |
---|
357 | n/a | |
---|
358 | n/a | def namedtuple(typename, field_names, *, verbose=False, rename=False, module=None): |
---|
359 | n/a | """Returns a new subclass of tuple with named fields. |
---|
360 | n/a | |
---|
361 | n/a | >>> Point = namedtuple('Point', ['x', 'y']) |
---|
362 | n/a | >>> Point.__doc__ # docstring for the new class |
---|
363 | n/a | 'Point(x, y)' |
---|
364 | n/a | >>> p = Point(11, y=22) # instantiate with positional args or keywords |
---|
365 | n/a | >>> p[0] + p[1] # indexable like a plain tuple |
---|
366 | n/a | 33 |
---|
367 | n/a | >>> x, y = p # unpack like a regular tuple |
---|
368 | n/a | >>> x, y |
---|
369 | n/a | (11, 22) |
---|
370 | n/a | >>> p.x + p.y # fields also accessible by name |
---|
371 | n/a | 33 |
---|
372 | n/a | >>> d = p._asdict() # convert to a dictionary |
---|
373 | n/a | >>> d['x'] |
---|
374 | n/a | 11 |
---|
375 | n/a | >>> Point(**d) # convert from a dictionary |
---|
376 | n/a | Point(x=11, y=22) |
---|
377 | n/a | >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields |
---|
378 | n/a | Point(x=100, y=22) |
---|
379 | n/a | |
---|
380 | n/a | """ |
---|
381 | n/a | |
---|
382 | n/a | # Validate the field names. At the user's option, either generate an error |
---|
383 | n/a | # message or automatically replace the field name with a valid name. |
---|
384 | n/a | if isinstance(field_names, str): |
---|
385 | n/a | field_names = field_names.replace(',', ' ').split() |
---|
386 | n/a | field_names = list(map(str, field_names)) |
---|
387 | n/a | typename = str(typename) |
---|
388 | n/a | if rename: |
---|
389 | n/a | seen = set() |
---|
390 | n/a | for index, name in enumerate(field_names): |
---|
391 | n/a | if (not name.isidentifier() |
---|
392 | n/a | or _iskeyword(name) |
---|
393 | n/a | or name.startswith('_') |
---|
394 | n/a | or name in seen): |
---|
395 | n/a | field_names[index] = '_%d' % index |
---|
396 | n/a | seen.add(name) |
---|
397 | n/a | for name in [typename] + field_names: |
---|
398 | n/a | if type(name) is not str: |
---|
399 | n/a | raise TypeError('Type names and field names must be strings') |
---|
400 | n/a | if not name.isidentifier(): |
---|
401 | n/a | raise ValueError('Type names and field names must be valid ' |
---|
402 | n/a | 'identifiers: %r' % name) |
---|
403 | n/a | if _iskeyword(name): |
---|
404 | n/a | raise ValueError('Type names and field names cannot be a ' |
---|
405 | n/a | 'keyword: %r' % name) |
---|
406 | n/a | seen = set() |
---|
407 | n/a | for name in field_names: |
---|
408 | n/a | if name.startswith('_') and not rename: |
---|
409 | n/a | raise ValueError('Field names cannot start with an underscore: ' |
---|
410 | n/a | '%r' % name) |
---|
411 | n/a | if name in seen: |
---|
412 | n/a | raise ValueError('Encountered duplicate field name: %r' % name) |
---|
413 | n/a | seen.add(name) |
---|
414 | n/a | |
---|
415 | n/a | # Fill-in the class template |
---|
416 | n/a | class_definition = _class_template.format( |
---|
417 | n/a | typename = typename, |
---|
418 | n/a | field_names = tuple(field_names), |
---|
419 | n/a | num_fields = len(field_names), |
---|
420 | n/a | arg_list = repr(tuple(field_names)).replace("'", "")[1:-1], |
---|
421 | n/a | repr_fmt = ', '.join(_repr_template.format(name=name) |
---|
422 | n/a | for name in field_names), |
---|
423 | n/a | field_defs = '\n'.join(_field_template.format(index=index, name=name) |
---|
424 | n/a | for index, name in enumerate(field_names)) |
---|
425 | n/a | ) |
---|
426 | n/a | |
---|
427 | n/a | # Execute the template string in a temporary namespace and support |
---|
428 | n/a | # tracing utilities by setting a value for frame.f_globals['__name__'] |
---|
429 | n/a | namespace = dict(__name__='namedtuple_%s' % typename) |
---|
430 | n/a | exec(class_definition, namespace) |
---|
431 | n/a | result = namespace[typename] |
---|
432 | n/a | result._source = class_definition |
---|
433 | n/a | if verbose: |
---|
434 | n/a | print(result._source) |
---|
435 | n/a | |
---|
436 | n/a | # For pickling to work, the __module__ variable needs to be set to the frame |
---|
437 | n/a | # where the named tuple is created. Bypass this step in environments where |
---|
438 | n/a | # sys._getframe is not defined (Jython for example) or sys._getframe is not |
---|
439 | n/a | # defined for arguments greater than 0 (IronPython), or where the user has |
---|
440 | n/a | # specified a particular module. |
---|
441 | n/a | if module is None: |
---|
442 | n/a | try: |
---|
443 | n/a | module = _sys._getframe(1).f_globals.get('__name__', '__main__') |
---|
444 | n/a | except (AttributeError, ValueError): |
---|
445 | n/a | pass |
---|
446 | n/a | if module is not None: |
---|
447 | n/a | result.__module__ = module |
---|
448 | n/a | |
---|
449 | n/a | return result |
---|
450 | n/a | |
---|
451 | n/a | |
---|
452 | n/a | ######################################################################## |
---|
453 | n/a | ### Counter |
---|
454 | n/a | ######################################################################## |
---|
455 | n/a | |
---|
456 | n/a | def _count_elements(mapping, iterable): |
---|
457 | n/a | 'Tally elements from the iterable.' |
---|
458 | n/a | mapping_get = mapping.get |
---|
459 | n/a | for elem in iterable: |
---|
460 | n/a | mapping[elem] = mapping_get(elem, 0) + 1 |
---|
461 | n/a | |
---|
462 | n/a | try: # Load C helper function if available |
---|
463 | n/a | from _collections import _count_elements |
---|
464 | n/a | except ImportError: |
---|
465 | n/a | pass |
---|
466 | n/a | |
---|
467 | n/a | class Counter(dict): |
---|
468 | n/a | '''Dict subclass for counting hashable items. Sometimes called a bag |
---|
469 | n/a | or multiset. Elements are stored as dictionary keys and their counts |
---|
470 | n/a | are stored as dictionary values. |
---|
471 | n/a | |
---|
472 | n/a | >>> c = Counter('abcdeabcdabcaba') # count elements from a string |
---|
473 | n/a | |
---|
474 | n/a | >>> c.most_common(3) # three most common elements |
---|
475 | n/a | [('a', 5), ('b', 4), ('c', 3)] |
---|
476 | n/a | >>> sorted(c) # list all unique elements |
---|
477 | n/a | ['a', 'b', 'c', 'd', 'e'] |
---|
478 | n/a | >>> ''.join(sorted(c.elements())) # list elements with repetitions |
---|
479 | n/a | 'aaaaabbbbcccdde' |
---|
480 | n/a | >>> sum(c.values()) # total of all counts |
---|
481 | n/a | 15 |
---|
482 | n/a | |
---|
483 | n/a | >>> c['a'] # count of letter 'a' |
---|
484 | n/a | 5 |
---|
485 | n/a | >>> for elem in 'shazam': # update counts from an iterable |
---|
486 | n/a | ... c[elem] += 1 # by adding 1 to each element's count |
---|
487 | n/a | >>> c['a'] # now there are seven 'a' |
---|
488 | n/a | 7 |
---|
489 | n/a | >>> del c['b'] # remove all 'b' |
---|
490 | n/a | >>> c['b'] # now there are zero 'b' |
---|
491 | n/a | 0 |
---|
492 | n/a | |
---|
493 | n/a | >>> d = Counter('simsalabim') # make another counter |
---|
494 | n/a | >>> c.update(d) # add in the second counter |
---|
495 | n/a | >>> c['a'] # now there are nine 'a' |
---|
496 | n/a | 9 |
---|
497 | n/a | |
---|
498 | n/a | >>> c.clear() # empty the counter |
---|
499 | n/a | >>> c |
---|
500 | n/a | Counter() |
---|
501 | n/a | |
---|
502 | n/a | Note: If a count is set to zero or reduced to zero, it will remain |
---|
503 | n/a | in the counter until the entry is deleted or the counter is cleared: |
---|
504 | n/a | |
---|
505 | n/a | >>> c = Counter('aaabbc') |
---|
506 | n/a | >>> c['b'] -= 2 # reduce the count of 'b' by two |
---|
507 | n/a | >>> c.most_common() # 'b' is still in, but its count is zero |
---|
508 | n/a | [('a', 3), ('c', 1), ('b', 0)] |
---|
509 | n/a | |
---|
510 | n/a | ''' |
---|
511 | n/a | # References: |
---|
512 | n/a | # http://en.wikipedia.org/wiki/Multiset |
---|
513 | n/a | # http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html |
---|
514 | n/a | # http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm |
---|
515 | n/a | # http://code.activestate.com/recipes/259174/ |
---|
516 | n/a | # Knuth, TAOCP Vol. II section 4.6.3 |
---|
517 | n/a | |
---|
518 | n/a | def __init__(*args, **kwds): |
---|
519 | n/a | '''Create a new, empty Counter object. And if given, count elements |
---|
520 | n/a | from an input iterable. Or, initialize the count from another mapping |
---|
521 | n/a | of elements to their counts. |
---|
522 | n/a | |
---|
523 | n/a | >>> c = Counter() # a new, empty counter |
---|
524 | n/a | >>> c = Counter('gallahad') # a new counter from an iterable |
---|
525 | n/a | >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping |
---|
526 | n/a | >>> c = Counter(a=4, b=2) # a new counter from keyword args |
---|
527 | n/a | |
---|
528 | n/a | ''' |
---|
529 | n/a | if not args: |
---|
530 | n/a | raise TypeError("descriptor '__init__' of 'Counter' object " |
---|
531 | n/a | "needs an argument") |
---|
532 | n/a | self, *args = args |
---|
533 | n/a | if len(args) > 1: |
---|
534 | n/a | raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
---|
535 | n/a | super(Counter, self).__init__() |
---|
536 | n/a | self.update(*args, **kwds) |
---|
537 | n/a | |
---|
538 | n/a | def __missing__(self, key): |
---|
539 | n/a | 'The count of elements not in the Counter is zero.' |
---|
540 | n/a | # Needed so that self[missing_item] does not raise KeyError |
---|
541 | n/a | return 0 |
---|
542 | n/a | |
---|
543 | n/a | def most_common(self, n=None): |
---|
544 | n/a | '''List the n most common elements and their counts from the most |
---|
545 | n/a | common to the least. If n is None, then list all element counts. |
---|
546 | n/a | |
---|
547 | n/a | >>> Counter('abcdeabcdabcaba').most_common(3) |
---|
548 | n/a | [('a', 5), ('b', 4), ('c', 3)] |
---|
549 | n/a | |
---|
550 | n/a | ''' |
---|
551 | n/a | # Emulate Bag.sortedByCount from Smalltalk |
---|
552 | n/a | if n is None: |
---|
553 | n/a | return sorted(self.items(), key=_itemgetter(1), reverse=True) |
---|
554 | n/a | return _heapq.nlargest(n, self.items(), key=_itemgetter(1)) |
---|
555 | n/a | |
---|
556 | n/a | def elements(self): |
---|
557 | n/a | '''Iterator over elements repeating each as many times as its count. |
---|
558 | n/a | |
---|
559 | n/a | >>> c = Counter('ABCABC') |
---|
560 | n/a | >>> sorted(c.elements()) |
---|
561 | n/a | ['A', 'A', 'B', 'B', 'C', 'C'] |
---|
562 | n/a | |
---|
563 | n/a | # Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1 |
---|
564 | n/a | >>> prime_factors = Counter({2: 2, 3: 3, 17: 1}) |
---|
565 | n/a | >>> product = 1 |
---|
566 | n/a | >>> for factor in prime_factors.elements(): # loop over factors |
---|
567 | n/a | ... product *= factor # and multiply them |
---|
568 | n/a | >>> product |
---|
569 | n/a | 1836 |
---|
570 | n/a | |
---|
571 | n/a | Note, if an element's count has been set to zero or is a negative |
---|
572 | n/a | number, elements() will ignore it. |
---|
573 | n/a | |
---|
574 | n/a | ''' |
---|
575 | n/a | # Emulate Bag.do from Smalltalk and Multiset.begin from C++. |
---|
576 | n/a | return _chain.from_iterable(_starmap(_repeat, self.items())) |
---|
577 | n/a | |
---|
578 | n/a | # Override dict methods where necessary |
---|
579 | n/a | |
---|
580 | n/a | @classmethod |
---|
581 | n/a | def fromkeys(cls, iterable, v=None): |
---|
582 | n/a | # There is no equivalent method for counters because setting v=1 |
---|
583 | n/a | # means that no element can have a count greater than one. |
---|
584 | n/a | raise NotImplementedError( |
---|
585 | n/a | 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') |
---|
586 | n/a | |
---|
587 | n/a | def update(*args, **kwds): |
---|
588 | n/a | '''Like dict.update() but add counts instead of replacing them. |
---|
589 | n/a | |
---|
590 | n/a | Source can be an iterable, a dictionary, or another Counter instance. |
---|
591 | n/a | |
---|
592 | n/a | >>> c = Counter('which') |
---|
593 | n/a | >>> c.update('witch') # add elements from another iterable |
---|
594 | n/a | >>> d = Counter('watch') |
---|
595 | n/a | >>> c.update(d) # add elements from another counter |
---|
596 | n/a | >>> c['h'] # four 'h' in which, witch, and watch |
---|
597 | n/a | 4 |
---|
598 | n/a | |
---|
599 | n/a | ''' |
---|
600 | n/a | # The regular dict.update() operation makes no sense here because the |
---|
601 | n/a | # replace behavior results in the some of original untouched counts |
---|
602 | n/a | # being mixed-in with all of the other counts for a mismash that |
---|
603 | n/a | # doesn't have a straight-forward interpretation in most counting |
---|
604 | n/a | # contexts. Instead, we implement straight-addition. Both the inputs |
---|
605 | n/a | # and outputs are allowed to contain zero and negative counts. |
---|
606 | n/a | |
---|
607 | n/a | if not args: |
---|
608 | n/a | raise TypeError("descriptor 'update' of 'Counter' object " |
---|
609 | n/a | "needs an argument") |
---|
610 | n/a | self, *args = args |
---|
611 | n/a | if len(args) > 1: |
---|
612 | n/a | raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
---|
613 | n/a | iterable = args[0] if args else None |
---|
614 | n/a | if iterable is not None: |
---|
615 | n/a | if isinstance(iterable, Mapping): |
---|
616 | n/a | if self: |
---|
617 | n/a | self_get = self.get |
---|
618 | n/a | for elem, count in iterable.items(): |
---|
619 | n/a | self[elem] = count + self_get(elem, 0) |
---|
620 | n/a | else: |
---|
621 | n/a | super(Counter, self).update(iterable) # fast path when counter is empty |
---|
622 | n/a | else: |
---|
623 | n/a | _count_elements(self, iterable) |
---|
624 | n/a | if kwds: |
---|
625 | n/a | self.update(kwds) |
---|
626 | n/a | |
---|
627 | n/a | def subtract(*args, **kwds): |
---|
628 | n/a | '''Like dict.update() but subtracts counts instead of replacing them. |
---|
629 | n/a | Counts can be reduced below zero. Both the inputs and outputs are |
---|
630 | n/a | allowed to contain zero and negative counts. |
---|
631 | n/a | |
---|
632 | n/a | Source can be an iterable, a dictionary, or another Counter instance. |
---|
633 | n/a | |
---|
634 | n/a | >>> c = Counter('which') |
---|
635 | n/a | >>> c.subtract('witch') # subtract elements from another iterable |
---|
636 | n/a | >>> c.subtract(Counter('watch')) # subtract elements from another counter |
---|
637 | n/a | >>> c['h'] # 2 in which, minus 1 in witch, minus 1 in watch |
---|
638 | n/a | 0 |
---|
639 | n/a | >>> c['w'] # 1 in which, minus 1 in witch, minus 1 in watch |
---|
640 | n/a | -1 |
---|
641 | n/a | |
---|
642 | n/a | ''' |
---|
643 | n/a | if not args: |
---|
644 | n/a | raise TypeError("descriptor 'subtract' of 'Counter' object " |
---|
645 | n/a | "needs an argument") |
---|
646 | n/a | self, *args = args |
---|
647 | n/a | if len(args) > 1: |
---|
648 | n/a | raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
---|
649 | n/a | iterable = args[0] if args else None |
---|
650 | n/a | if iterable is not None: |
---|
651 | n/a | self_get = self.get |
---|
652 | n/a | if isinstance(iterable, Mapping): |
---|
653 | n/a | for elem, count in iterable.items(): |
---|
654 | n/a | self[elem] = self_get(elem, 0) - count |
---|
655 | n/a | else: |
---|
656 | n/a | for elem in iterable: |
---|
657 | n/a | self[elem] = self_get(elem, 0) - 1 |
---|
658 | n/a | if kwds: |
---|
659 | n/a | self.subtract(kwds) |
---|
660 | n/a | |
---|
661 | n/a | def copy(self): |
---|
662 | n/a | 'Return a shallow copy.' |
---|
663 | n/a | return self.__class__(self) |
---|
664 | n/a | |
---|
665 | n/a | def __reduce__(self): |
---|
666 | n/a | return self.__class__, (dict(self),) |
---|
667 | n/a | |
---|
668 | n/a | def __delitem__(self, elem): |
---|
669 | n/a | 'Like dict.__delitem__() but does not raise KeyError for missing values.' |
---|
670 | n/a | if elem in self: |
---|
671 | n/a | super().__delitem__(elem) |
---|
672 | n/a | |
---|
673 | n/a | def __repr__(self): |
---|
674 | n/a | if not self: |
---|
675 | n/a | return '%s()' % self.__class__.__name__ |
---|
676 | n/a | try: |
---|
677 | n/a | items = ', '.join(map('%r: %r'.__mod__, self.most_common())) |
---|
678 | n/a | return '%s({%s})' % (self.__class__.__name__, items) |
---|
679 | n/a | except TypeError: |
---|
680 | n/a | # handle case where values are not orderable |
---|
681 | n/a | return '{0}({1!r})'.format(self.__class__.__name__, dict(self)) |
---|
682 | n/a | |
---|
683 | n/a | # Multiset-style mathematical operations discussed in: |
---|
684 | n/a | # Knuth TAOCP Volume II section 4.6.3 exercise 19 |
---|
685 | n/a | # and at http://en.wikipedia.org/wiki/Multiset |
---|
686 | n/a | # |
---|
687 | n/a | # Outputs guaranteed to only include positive counts. |
---|
688 | n/a | # |
---|
689 | n/a | # To strip negative and zero counts, add-in an empty counter: |
---|
690 | n/a | # c += Counter() |
---|
691 | n/a | |
---|
692 | n/a | def __add__(self, other): |
---|
693 | n/a | '''Add counts from two counters. |
---|
694 | n/a | |
---|
695 | n/a | >>> Counter('abbb') + Counter('bcc') |
---|
696 | n/a | Counter({'b': 4, 'c': 2, 'a': 1}) |
---|
697 | n/a | |
---|
698 | n/a | ''' |
---|
699 | n/a | if not isinstance(other, Counter): |
---|
700 | n/a | return NotImplemented |
---|
701 | n/a | result = Counter() |
---|
702 | n/a | for elem, count in self.items(): |
---|
703 | n/a | newcount = count + other[elem] |
---|
704 | n/a | if newcount > 0: |
---|
705 | n/a | result[elem] = newcount |
---|
706 | n/a | for elem, count in other.items(): |
---|
707 | n/a | if elem not in self and count > 0: |
---|
708 | n/a | result[elem] = count |
---|
709 | n/a | return result |
---|
710 | n/a | |
---|
711 | n/a | def __sub__(self, other): |
---|
712 | n/a | ''' Subtract count, but keep only results with positive counts. |
---|
713 | n/a | |
---|
714 | n/a | >>> Counter('abbbc') - Counter('bccd') |
---|
715 | n/a | Counter({'b': 2, 'a': 1}) |
---|
716 | n/a | |
---|
717 | n/a | ''' |
---|
718 | n/a | if not isinstance(other, Counter): |
---|
719 | n/a | return NotImplemented |
---|
720 | n/a | result = Counter() |
---|
721 | n/a | for elem, count in self.items(): |
---|
722 | n/a | newcount = count - other[elem] |
---|
723 | n/a | if newcount > 0: |
---|
724 | n/a | result[elem] = newcount |
---|
725 | n/a | for elem, count in other.items(): |
---|
726 | n/a | if elem not in self and count < 0: |
---|
727 | n/a | result[elem] = 0 - count |
---|
728 | n/a | return result |
---|
729 | n/a | |
---|
730 | n/a | def __or__(self, other): |
---|
731 | n/a | '''Union is the maximum of value in either of the input counters. |
---|
732 | n/a | |
---|
733 | n/a | >>> Counter('abbb') | Counter('bcc') |
---|
734 | n/a | Counter({'b': 3, 'c': 2, 'a': 1}) |
---|
735 | n/a | |
---|
736 | n/a | ''' |
---|
737 | n/a | if not isinstance(other, Counter): |
---|
738 | n/a | return NotImplemented |
---|
739 | n/a | result = Counter() |
---|
740 | n/a | for elem, count in self.items(): |
---|
741 | n/a | other_count = other[elem] |
---|
742 | n/a | newcount = other_count if count < other_count else count |
---|
743 | n/a | if newcount > 0: |
---|
744 | n/a | result[elem] = newcount |
---|
745 | n/a | for elem, count in other.items(): |
---|
746 | n/a | if elem not in self and count > 0: |
---|
747 | n/a | result[elem] = count |
---|
748 | n/a | return result |
---|
749 | n/a | |
---|
750 | n/a | def __and__(self, other): |
---|
751 | n/a | ''' Intersection is the minimum of corresponding counts. |
---|
752 | n/a | |
---|
753 | n/a | >>> Counter('abbb') & Counter('bcc') |
---|
754 | n/a | Counter({'b': 1}) |
---|
755 | n/a | |
---|
756 | n/a | ''' |
---|
757 | n/a | if not isinstance(other, Counter): |
---|
758 | n/a | return NotImplemented |
---|
759 | n/a | result = Counter() |
---|
760 | n/a | for elem, count in self.items(): |
---|
761 | n/a | other_count = other[elem] |
---|
762 | n/a | newcount = count if count < other_count else other_count |
---|
763 | n/a | if newcount > 0: |
---|
764 | n/a | result[elem] = newcount |
---|
765 | n/a | return result |
---|
766 | n/a | |
---|
767 | n/a | def __pos__(self): |
---|
768 | n/a | 'Adds an empty counter, effectively stripping negative and zero counts' |
---|
769 | n/a | result = Counter() |
---|
770 | n/a | for elem, count in self.items(): |
---|
771 | n/a | if count > 0: |
---|
772 | n/a | result[elem] = count |
---|
773 | n/a | return result |
---|
774 | n/a | |
---|
775 | n/a | def __neg__(self): |
---|
776 | n/a | '''Subtracts from an empty counter. Strips positive and zero counts, |
---|
777 | n/a | and flips the sign on negative counts. |
---|
778 | n/a | |
---|
779 | n/a | ''' |
---|
780 | n/a | result = Counter() |
---|
781 | n/a | for elem, count in self.items(): |
---|
782 | n/a | if count < 0: |
---|
783 | n/a | result[elem] = 0 - count |
---|
784 | n/a | return result |
---|
785 | n/a | |
---|
786 | n/a | def _keep_positive(self): |
---|
787 | n/a | '''Internal method to strip elements with a negative or zero count''' |
---|
788 | n/a | nonpositive = [elem for elem, count in self.items() if not count > 0] |
---|
789 | n/a | for elem in nonpositive: |
---|
790 | n/a | del self[elem] |
---|
791 | n/a | return self |
---|
792 | n/a | |
---|
793 | n/a | def __iadd__(self, other): |
---|
794 | n/a | '''Inplace add from another counter, keeping only positive counts. |
---|
795 | n/a | |
---|
796 | n/a | >>> c = Counter('abbb') |
---|
797 | n/a | >>> c += Counter('bcc') |
---|
798 | n/a | >>> c |
---|
799 | n/a | Counter({'b': 4, 'c': 2, 'a': 1}) |
---|
800 | n/a | |
---|
801 | n/a | ''' |
---|
802 | n/a | for elem, count in other.items(): |
---|
803 | n/a | self[elem] += count |
---|
804 | n/a | return self._keep_positive() |
---|
805 | n/a | |
---|
806 | n/a | def __isub__(self, other): |
---|
807 | n/a | '''Inplace subtract counter, but keep only results with positive counts. |
---|
808 | n/a | |
---|
809 | n/a | >>> c = Counter('abbbc') |
---|
810 | n/a | >>> c -= Counter('bccd') |
---|
811 | n/a | >>> c |
---|
812 | n/a | Counter({'b': 2, 'a': 1}) |
---|
813 | n/a | |
---|
814 | n/a | ''' |
---|
815 | n/a | for elem, count in other.items(): |
---|
816 | n/a | self[elem] -= count |
---|
817 | n/a | return self._keep_positive() |
---|
818 | n/a | |
---|
819 | n/a | def __ior__(self, other): |
---|
820 | n/a | '''Inplace union is the maximum of value from either counter. |
---|
821 | n/a | |
---|
822 | n/a | >>> c = Counter('abbb') |
---|
823 | n/a | >>> c |= Counter('bcc') |
---|
824 | n/a | >>> c |
---|
825 | n/a | Counter({'b': 3, 'c': 2, 'a': 1}) |
---|
826 | n/a | |
---|
827 | n/a | ''' |
---|
828 | n/a | for elem, other_count in other.items(): |
---|
829 | n/a | count = self[elem] |
---|
830 | n/a | if other_count > count: |
---|
831 | n/a | self[elem] = other_count |
---|
832 | n/a | return self._keep_positive() |
---|
833 | n/a | |
---|
834 | n/a | def __iand__(self, other): |
---|
835 | n/a | '''Inplace intersection is the minimum of corresponding counts. |
---|
836 | n/a | |
---|
837 | n/a | >>> c = Counter('abbb') |
---|
838 | n/a | >>> c &= Counter('bcc') |
---|
839 | n/a | >>> c |
---|
840 | n/a | Counter({'b': 1}) |
---|
841 | n/a | |
---|
842 | n/a | ''' |
---|
843 | n/a | for elem, count in self.items(): |
---|
844 | n/a | other_count = other[elem] |
---|
845 | n/a | if other_count < count: |
---|
846 | n/a | self[elem] = other_count |
---|
847 | n/a | return self._keep_positive() |
---|
848 | n/a | |
---|
849 | n/a | |
---|
850 | n/a | ######################################################################## |
---|
851 | n/a | ### ChainMap |
---|
852 | n/a | ######################################################################## |
---|
853 | n/a | |
---|
854 | n/a | class ChainMap(MutableMapping): |
---|
855 | n/a | ''' A ChainMap groups multiple dicts (or other mappings) together |
---|
856 | n/a | to create a single, updateable view. |
---|
857 | n/a | |
---|
858 | n/a | The underlying mappings are stored in a list. That list is public and can |
---|
859 | n/a | be accessed or updated using the *maps* attribute. There is no other |
---|
860 | n/a | state. |
---|
861 | n/a | |
---|
862 | n/a | Lookups search the underlying mappings successively until a key is found. |
---|
863 | n/a | In contrast, writes, updates, and deletions only operate on the first |
---|
864 | n/a | mapping. |
---|
865 | n/a | |
---|
866 | n/a | ''' |
---|
867 | n/a | |
---|
868 | n/a | def __init__(self, *maps): |
---|
869 | n/a | '''Initialize a ChainMap by setting *maps* to the given mappings. |
---|
870 | n/a | If no mappings are provided, a single empty dictionary is used. |
---|
871 | n/a | |
---|
872 | n/a | ''' |
---|
873 | n/a | self.maps = list(maps) or [{}] # always at least one map |
---|
874 | n/a | |
---|
875 | n/a | def __missing__(self, key): |
---|
876 | n/a | raise KeyError(key) |
---|
877 | n/a | |
---|
878 | n/a | def __getitem__(self, key): |
---|
879 | n/a | for mapping in self.maps: |
---|
880 | n/a | try: |
---|
881 | n/a | return mapping[key] # can't use 'key in mapping' with defaultdict |
---|
882 | n/a | except KeyError: |
---|
883 | n/a | pass |
---|
884 | n/a | return self.__missing__(key) # support subclasses that define __missing__ |
---|
885 | n/a | |
---|
886 | n/a | def get(self, key, default=None): |
---|
887 | n/a | return self[key] if key in self else default |
---|
888 | n/a | |
---|
889 | n/a | def __len__(self): |
---|
890 | n/a | return len(set().union(*self.maps)) # reuses stored hash values if possible |
---|
891 | n/a | |
---|
892 | n/a | def __iter__(self): |
---|
893 | n/a | return iter(set().union(*self.maps)) |
---|
894 | n/a | |
---|
895 | n/a | def __contains__(self, key): |
---|
896 | n/a | return any(key in m for m in self.maps) |
---|
897 | n/a | |
---|
898 | n/a | def __bool__(self): |
---|
899 | n/a | return any(self.maps) |
---|
900 | n/a | |
---|
901 | n/a | @_recursive_repr() |
---|
902 | n/a | def __repr__(self): |
---|
903 | n/a | return '{0.__class__.__name__}({1})'.format( |
---|
904 | n/a | self, ', '.join(map(repr, self.maps))) |
---|
905 | n/a | |
---|
906 | n/a | @classmethod |
---|
907 | n/a | def fromkeys(cls, iterable, *args): |
---|
908 | n/a | 'Create a ChainMap with a single dict created from the iterable.' |
---|
909 | n/a | return cls(dict.fromkeys(iterable, *args)) |
---|
910 | n/a | |
---|
911 | n/a | def copy(self): |
---|
912 | n/a | 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' |
---|
913 | n/a | return self.__class__(self.maps[0].copy(), *self.maps[1:]) |
---|
914 | n/a | |
---|
915 | n/a | __copy__ = copy |
---|
916 | n/a | |
---|
917 | n/a | def new_child(self, m=None): # like Django's Context.push() |
---|
918 | n/a | '''New ChainMap with a new map followed by all previous maps. |
---|
919 | n/a | If no map is provided, an empty dict is used. |
---|
920 | n/a | ''' |
---|
921 | n/a | if m is None: |
---|
922 | n/a | m = {} |
---|
923 | n/a | return self.__class__(m, *self.maps) |
---|
924 | n/a | |
---|
925 | n/a | @property |
---|
926 | n/a | def parents(self): # like Django's Context.pop() |
---|
927 | n/a | 'New ChainMap from maps[1:].' |
---|
928 | n/a | return self.__class__(*self.maps[1:]) |
---|
929 | n/a | |
---|
930 | n/a | def __setitem__(self, key, value): |
---|
931 | n/a | self.maps[0][key] = value |
---|
932 | n/a | |
---|
933 | n/a | def __delitem__(self, key): |
---|
934 | n/a | try: |
---|
935 | n/a | del self.maps[0][key] |
---|
936 | n/a | except KeyError: |
---|
937 | n/a | raise KeyError('Key not found in the first mapping: {!r}'.format(key)) |
---|
938 | n/a | |
---|
939 | n/a | def popitem(self): |
---|
940 | n/a | 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' |
---|
941 | n/a | try: |
---|
942 | n/a | return self.maps[0].popitem() |
---|
943 | n/a | except KeyError: |
---|
944 | n/a | raise KeyError('No keys found in the first mapping.') |
---|
945 | n/a | |
---|
946 | n/a | def pop(self, key, *args): |
---|
947 | n/a | 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' |
---|
948 | n/a | try: |
---|
949 | n/a | return self.maps[0].pop(key, *args) |
---|
950 | n/a | except KeyError: |
---|
951 | n/a | raise KeyError('Key not found in the first mapping: {!r}'.format(key)) |
---|
952 | n/a | |
---|
953 | n/a | def clear(self): |
---|
954 | n/a | 'Clear maps[0], leaving maps[1:] intact.' |
---|
955 | n/a | self.maps[0].clear() |
---|
956 | n/a | |
---|
957 | n/a | |
---|
958 | n/a | ################################################################################ |
---|
959 | n/a | ### UserDict |
---|
960 | n/a | ################################################################################ |
---|
961 | n/a | |
---|
962 | n/a | class UserDict(MutableMapping): |
---|
963 | n/a | |
---|
964 | n/a | # Start by filling-out the abstract methods |
---|
965 | n/a | def __init__(*args, **kwargs): |
---|
966 | n/a | if not args: |
---|
967 | n/a | raise TypeError("descriptor '__init__' of 'UserDict' object " |
---|
968 | n/a | "needs an argument") |
---|
969 | n/a | self, *args = args |
---|
970 | n/a | if len(args) > 1: |
---|
971 | n/a | raise TypeError('expected at most 1 arguments, got %d' % len(args)) |
---|
972 | n/a | if args: |
---|
973 | n/a | dict = args[0] |
---|
974 | n/a | elif 'dict' in kwargs: |
---|
975 | n/a | dict = kwargs.pop('dict') |
---|
976 | n/a | import warnings |
---|
977 | n/a | warnings.warn("Passing 'dict' as keyword argument is deprecated", |
---|
978 | n/a | DeprecationWarning, stacklevel=2) |
---|
979 | n/a | else: |
---|
980 | n/a | dict = None |
---|
981 | n/a | self.data = {} |
---|
982 | n/a | if dict is not None: |
---|
983 | n/a | self.update(dict) |
---|
984 | n/a | if len(kwargs): |
---|
985 | n/a | self.update(kwargs) |
---|
986 | n/a | def __len__(self): return len(self.data) |
---|
987 | n/a | def __getitem__(self, key): |
---|
988 | n/a | if key in self.data: |
---|
989 | n/a | return self.data[key] |
---|
990 | n/a | if hasattr(self.__class__, "__missing__"): |
---|
991 | n/a | return self.__class__.__missing__(self, key) |
---|
992 | n/a | raise KeyError(key) |
---|
993 | n/a | def __setitem__(self, key, item): self.data[key] = item |
---|
994 | n/a | def __delitem__(self, key): del self.data[key] |
---|
995 | n/a | def __iter__(self): |
---|
996 | n/a | return iter(self.data) |
---|
997 | n/a | |
---|
998 | n/a | # Modify __contains__ to work correctly when __missing__ is present |
---|
999 | n/a | def __contains__(self, key): |
---|
1000 | n/a | return key in self.data |
---|
1001 | n/a | |
---|
1002 | n/a | # Now, add the methods in dicts but not in MutableMapping |
---|
1003 | n/a | def __repr__(self): return repr(self.data) |
---|
1004 | n/a | def copy(self): |
---|
1005 | n/a | if self.__class__ is UserDict: |
---|
1006 | n/a | return UserDict(self.data.copy()) |
---|
1007 | n/a | import copy |
---|
1008 | n/a | data = self.data |
---|
1009 | n/a | try: |
---|
1010 | n/a | self.data = {} |
---|
1011 | n/a | c = copy.copy(self) |
---|
1012 | n/a | finally: |
---|
1013 | n/a | self.data = data |
---|
1014 | n/a | c.update(self) |
---|
1015 | n/a | return c |
---|
1016 | n/a | @classmethod |
---|
1017 | n/a | def fromkeys(cls, iterable, value=None): |
---|
1018 | n/a | d = cls() |
---|
1019 | n/a | for key in iterable: |
---|
1020 | n/a | d[key] = value |
---|
1021 | n/a | return d |
---|
1022 | n/a | |
---|
1023 | n/a | |
---|
1024 | n/a | |
---|
1025 | n/a | ################################################################################ |
---|
1026 | n/a | ### UserList |
---|
1027 | n/a | ################################################################################ |
---|
1028 | n/a | |
---|
1029 | n/a | class UserList(MutableSequence): |
---|
1030 | n/a | """A more or less complete user-defined wrapper around list objects.""" |
---|
1031 | n/a | def __init__(self, initlist=None): |
---|
1032 | n/a | self.data = [] |
---|
1033 | n/a | if initlist is not None: |
---|
1034 | n/a | # XXX should this accept an arbitrary sequence? |
---|
1035 | n/a | if type(initlist) == type(self.data): |
---|
1036 | n/a | self.data[:] = initlist |
---|
1037 | n/a | elif isinstance(initlist, UserList): |
---|
1038 | n/a | self.data[:] = initlist.data[:] |
---|
1039 | n/a | else: |
---|
1040 | n/a | self.data = list(initlist) |
---|
1041 | n/a | def __repr__(self): return repr(self.data) |
---|
1042 | n/a | def __lt__(self, other): return self.data < self.__cast(other) |
---|
1043 | n/a | def __le__(self, other): return self.data <= self.__cast(other) |
---|
1044 | n/a | def __eq__(self, other): return self.data == self.__cast(other) |
---|
1045 | n/a | def __gt__(self, other): return self.data > self.__cast(other) |
---|
1046 | n/a | def __ge__(self, other): return self.data >= self.__cast(other) |
---|
1047 | n/a | def __cast(self, other): |
---|
1048 | n/a | return other.data if isinstance(other, UserList) else other |
---|
1049 | n/a | def __contains__(self, item): return item in self.data |
---|
1050 | n/a | def __len__(self): return len(self.data) |
---|
1051 | n/a | def __getitem__(self, i): return self.data[i] |
---|
1052 | n/a | def __setitem__(self, i, item): self.data[i] = item |
---|
1053 | n/a | def __delitem__(self, i): del self.data[i] |
---|
1054 | n/a | def __add__(self, other): |
---|
1055 | n/a | if isinstance(other, UserList): |
---|
1056 | n/a | return self.__class__(self.data + other.data) |
---|
1057 | n/a | elif isinstance(other, type(self.data)): |
---|
1058 | n/a | return self.__class__(self.data + other) |
---|
1059 | n/a | return self.__class__(self.data + list(other)) |
---|
1060 | n/a | def __radd__(self, other): |
---|
1061 | n/a | if isinstance(other, UserList): |
---|
1062 | n/a | return self.__class__(other.data + self.data) |
---|
1063 | n/a | elif isinstance(other, type(self.data)): |
---|
1064 | n/a | return self.__class__(other + self.data) |
---|
1065 | n/a | return self.__class__(list(other) + self.data) |
---|
1066 | n/a | def __iadd__(self, other): |
---|
1067 | n/a | if isinstance(other, UserList): |
---|
1068 | n/a | self.data += other.data |
---|
1069 | n/a | elif isinstance(other, type(self.data)): |
---|
1070 | n/a | self.data += other |
---|
1071 | n/a | else: |
---|
1072 | n/a | self.data += list(other) |
---|
1073 | n/a | return self |
---|
1074 | n/a | def __mul__(self, n): |
---|
1075 | n/a | return self.__class__(self.data*n) |
---|
1076 | n/a | __rmul__ = __mul__ |
---|
1077 | n/a | def __imul__(self, n): |
---|
1078 | n/a | self.data *= n |
---|
1079 | n/a | return self |
---|
1080 | n/a | def append(self, item): self.data.append(item) |
---|
1081 | n/a | def insert(self, i, item): self.data.insert(i, item) |
---|
1082 | n/a | def pop(self, i=-1): return self.data.pop(i) |
---|
1083 | n/a | def remove(self, item): self.data.remove(item) |
---|
1084 | n/a | def clear(self): self.data.clear() |
---|
1085 | n/a | def copy(self): return self.__class__(self) |
---|
1086 | n/a | def count(self, item): return self.data.count(item) |
---|
1087 | n/a | def index(self, item, *args): return self.data.index(item, *args) |
---|
1088 | n/a | def reverse(self): self.data.reverse() |
---|
1089 | n/a | def sort(self, *args, **kwds): self.data.sort(*args, **kwds) |
---|
1090 | n/a | def extend(self, other): |
---|
1091 | n/a | if isinstance(other, UserList): |
---|
1092 | n/a | self.data.extend(other.data) |
---|
1093 | n/a | else: |
---|
1094 | n/a | self.data.extend(other) |
---|
1095 | n/a | |
---|
1096 | n/a | |
---|
1097 | n/a | |
---|
1098 | n/a | ################################################################################ |
---|
1099 | n/a | ### UserString |
---|
1100 | n/a | ################################################################################ |
---|
1101 | n/a | |
---|
1102 | n/a | class UserString(Sequence): |
---|
1103 | n/a | def __init__(self, seq): |
---|
1104 | n/a | if isinstance(seq, str): |
---|
1105 | n/a | self.data = seq |
---|
1106 | n/a | elif isinstance(seq, UserString): |
---|
1107 | n/a | self.data = seq.data[:] |
---|
1108 | n/a | else: |
---|
1109 | n/a | self.data = str(seq) |
---|
1110 | n/a | def __str__(self): return str(self.data) |
---|
1111 | n/a | def __repr__(self): return repr(self.data) |
---|
1112 | n/a | def __int__(self): return int(self.data) |
---|
1113 | n/a | def __float__(self): return float(self.data) |
---|
1114 | n/a | def __complex__(self): return complex(self.data) |
---|
1115 | n/a | def __hash__(self): return hash(self.data) |
---|
1116 | n/a | def __getnewargs__(self): |
---|
1117 | n/a | return (self.data[:],) |
---|
1118 | n/a | |
---|
1119 | n/a | def __eq__(self, string): |
---|
1120 | n/a | if isinstance(string, UserString): |
---|
1121 | n/a | return self.data == string.data |
---|
1122 | n/a | return self.data == string |
---|
1123 | n/a | def __lt__(self, string): |
---|
1124 | n/a | if isinstance(string, UserString): |
---|
1125 | n/a | return self.data < string.data |
---|
1126 | n/a | return self.data < string |
---|
1127 | n/a | def __le__(self, string): |
---|
1128 | n/a | if isinstance(string, UserString): |
---|
1129 | n/a | return self.data <= string.data |
---|
1130 | n/a | return self.data <= string |
---|
1131 | n/a | def __gt__(self, string): |
---|
1132 | n/a | if isinstance(string, UserString): |
---|
1133 | n/a | return self.data > string.data |
---|
1134 | n/a | return self.data > string |
---|
1135 | n/a | def __ge__(self, string): |
---|
1136 | n/a | if isinstance(string, UserString): |
---|
1137 | n/a | return self.data >= string.data |
---|
1138 | n/a | return self.data >= string |
---|
1139 | n/a | |
---|
1140 | n/a | def __contains__(self, char): |
---|
1141 | n/a | if isinstance(char, UserString): |
---|
1142 | n/a | char = char.data |
---|
1143 | n/a | return char in self.data |
---|
1144 | n/a | |
---|
1145 | n/a | def __len__(self): return len(self.data) |
---|
1146 | n/a | def __getitem__(self, index): return self.__class__(self.data[index]) |
---|
1147 | n/a | def __add__(self, other): |
---|
1148 | n/a | if isinstance(other, UserString): |
---|
1149 | n/a | return self.__class__(self.data + other.data) |
---|
1150 | n/a | elif isinstance(other, str): |
---|
1151 | n/a | return self.__class__(self.data + other) |
---|
1152 | n/a | return self.__class__(self.data + str(other)) |
---|
1153 | n/a | def __radd__(self, other): |
---|
1154 | n/a | if isinstance(other, str): |
---|
1155 | n/a | return self.__class__(other + self.data) |
---|
1156 | n/a | return self.__class__(str(other) + self.data) |
---|
1157 | n/a | def __mul__(self, n): |
---|
1158 | n/a | return self.__class__(self.data*n) |
---|
1159 | n/a | __rmul__ = __mul__ |
---|
1160 | n/a | def __mod__(self, args): |
---|
1161 | n/a | return self.__class__(self.data % args) |
---|
1162 | n/a | def __rmod__(self, format): |
---|
1163 | n/a | return self.__class__(format % args) |
---|
1164 | n/a | |
---|
1165 | n/a | # the following methods are defined in alphabetical order: |
---|
1166 | n/a | def capitalize(self): return self.__class__(self.data.capitalize()) |
---|
1167 | n/a | def casefold(self): |
---|
1168 | n/a | return self.__class__(self.data.casefold()) |
---|
1169 | n/a | def center(self, width, *args): |
---|
1170 | n/a | return self.__class__(self.data.center(width, *args)) |
---|
1171 | n/a | def count(self, sub, start=0, end=_sys.maxsize): |
---|
1172 | n/a | if isinstance(sub, UserString): |
---|
1173 | n/a | sub = sub.data |
---|
1174 | n/a | return self.data.count(sub, start, end) |
---|
1175 | n/a | def encode(self, encoding=None, errors=None): # XXX improve this? |
---|
1176 | n/a | if encoding: |
---|
1177 | n/a | if errors: |
---|
1178 | n/a | return self.__class__(self.data.encode(encoding, errors)) |
---|
1179 | n/a | return self.__class__(self.data.encode(encoding)) |
---|
1180 | n/a | return self.__class__(self.data.encode()) |
---|
1181 | n/a | def endswith(self, suffix, start=0, end=_sys.maxsize): |
---|
1182 | n/a | return self.data.endswith(suffix, start, end) |
---|
1183 | n/a | def expandtabs(self, tabsize=8): |
---|
1184 | n/a | return self.__class__(self.data.expandtabs(tabsize)) |
---|
1185 | n/a | def find(self, sub, start=0, end=_sys.maxsize): |
---|
1186 | n/a | if isinstance(sub, UserString): |
---|
1187 | n/a | sub = sub.data |
---|
1188 | n/a | return self.data.find(sub, start, end) |
---|
1189 | n/a | def format(self, *args, **kwds): |
---|
1190 | n/a | return self.data.format(*args, **kwds) |
---|
1191 | n/a | def format_map(self, mapping): |
---|
1192 | n/a | return self.data.format_map(mapping) |
---|
1193 | n/a | def index(self, sub, start=0, end=_sys.maxsize): |
---|
1194 | n/a | return self.data.index(sub, start, end) |
---|
1195 | n/a | def isalpha(self): return self.data.isalpha() |
---|
1196 | n/a | def isalnum(self): return self.data.isalnum() |
---|
1197 | n/a | def isdecimal(self): return self.data.isdecimal() |
---|
1198 | n/a | def isdigit(self): return self.data.isdigit() |
---|
1199 | n/a | def isidentifier(self): return self.data.isidentifier() |
---|
1200 | n/a | def islower(self): return self.data.islower() |
---|
1201 | n/a | def isnumeric(self): return self.data.isnumeric() |
---|
1202 | n/a | def isprintable(self): return self.data.isprintable() |
---|
1203 | n/a | def isspace(self): return self.data.isspace() |
---|
1204 | n/a | def istitle(self): return self.data.istitle() |
---|
1205 | n/a | def isupper(self): return self.data.isupper() |
---|
1206 | n/a | def join(self, seq): return self.data.join(seq) |
---|
1207 | n/a | def ljust(self, width, *args): |
---|
1208 | n/a | return self.__class__(self.data.ljust(width, *args)) |
---|
1209 | n/a | def lower(self): return self.__class__(self.data.lower()) |
---|
1210 | n/a | def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars)) |
---|
1211 | n/a | maketrans = str.maketrans |
---|
1212 | n/a | def partition(self, sep): |
---|
1213 | n/a | return self.data.partition(sep) |
---|
1214 | n/a | def replace(self, old, new, maxsplit=-1): |
---|
1215 | n/a | if isinstance(old, UserString): |
---|
1216 | n/a | old = old.data |
---|
1217 | n/a | if isinstance(new, UserString): |
---|
1218 | n/a | new = new.data |
---|
1219 | n/a | return self.__class__(self.data.replace(old, new, maxsplit)) |
---|
1220 | n/a | def rfind(self, sub, start=0, end=_sys.maxsize): |
---|
1221 | n/a | if isinstance(sub, UserString): |
---|
1222 | n/a | sub = sub.data |
---|
1223 | n/a | return self.data.rfind(sub, start, end) |
---|
1224 | n/a | def rindex(self, sub, start=0, end=_sys.maxsize): |
---|
1225 | n/a | return self.data.rindex(sub, start, end) |
---|
1226 | n/a | def rjust(self, width, *args): |
---|
1227 | n/a | return self.__class__(self.data.rjust(width, *args)) |
---|
1228 | n/a | def rpartition(self, sep): |
---|
1229 | n/a | return self.data.rpartition(sep) |
---|
1230 | n/a | def rstrip(self, chars=None): |
---|
1231 | n/a | return self.__class__(self.data.rstrip(chars)) |
---|
1232 | n/a | def split(self, sep=None, maxsplit=-1): |
---|
1233 | n/a | return self.data.split(sep, maxsplit) |
---|
1234 | n/a | def rsplit(self, sep=None, maxsplit=-1): |
---|
1235 | n/a | return self.data.rsplit(sep, maxsplit) |
---|
1236 | n/a | def splitlines(self, keepends=False): return self.data.splitlines(keepends) |
---|
1237 | n/a | def startswith(self, prefix, start=0, end=_sys.maxsize): |
---|
1238 | n/a | return self.data.startswith(prefix, start, end) |
---|
1239 | n/a | def strip(self, chars=None): return self.__class__(self.data.strip(chars)) |
---|
1240 | n/a | def swapcase(self): return self.__class__(self.data.swapcase()) |
---|
1241 | n/a | def title(self): return self.__class__(self.data.title()) |
---|
1242 | n/a | def translate(self, *args): |
---|
1243 | n/a | return self.__class__(self.data.translate(*args)) |
---|
1244 | n/a | def upper(self): return self.__class__(self.data.upper()) |
---|
1245 | n/a | def zfill(self, width): return self.__class__(self.data.zfill(width)) |
---|