1
1
import pprint
2
- from itertools import chain
2
+ from itertools import chain , filterfalse
3
3
from collections import abc
4
4
5
5
_marker = object ()
6
6
7
7
8
+ def _unique_everseen (iterable ):
9
+ """List unique elements, preserving order.
10
+ Remember all elements ever seen.
11
+ Recipe from
12
+ https://docs.python.org/3/library/itertools.html#itertools-recipes"""
13
+ # unique_everseen('AAAABBBCCDAABBB') --> A B C D
14
+ # unique_everseen('ABBCcAD', str.lower) --> A B C D
15
+ seen = set ()
16
+ seen_add = seen .add
17
+ for element in filterfalse (seen .__contains__ , iterable ):
18
+ seen_add (element )
19
+ yield element
20
+
21
+
8
22
class MultiDict (abc .Mapping ):
9
23
"""Read-only ordered dictionary that can have multiple values for each key.
10
24
@@ -25,10 +39,8 @@ def __init__(self, *args, **kwargs):
25
39
args = list (args [0 ])
26
40
for arg in args :
27
41
if not len (arg ) == 2 :
28
- raise TypeError (
29
- "MultiDict takes either dict or list of \
30
- (key, value) tuples"
31
- )
42
+ raise TypeError ("MultiDict takes either dict "
43
+ "or list of (key, value) tuples" )
32
44
33
45
self ._fill (chain (args , kwargs .items ()))
34
46
@@ -217,13 +229,13 @@ def __delitem__(self, key):
217
229
super ().__delitem__ (key .upper ())
218
230
219
231
220
- class _ItemsView ( abc . ItemsView ) :
232
+ class _ViewBase :
221
233
222
234
def __init__ (self , items , * , getall = False ):
223
235
self ._getall = getall
224
236
self ._keys = [item [0 ] for item in items ]
225
237
if not getall :
226
- self ._keys = set ( self ._keys )
238
+ self ._keys = list ( _unique_everseen ( self ._keys ) )
227
239
228
240
items_to_use = []
229
241
if getall :
@@ -238,6 +250,9 @@ def __init__(self, items, *, getall=False):
238
250
239
251
super ().__init__ (items_to_use )
240
252
253
+
254
+ class _ItemsView (_ViewBase , abc .ItemsView ):
255
+
241
256
def __contains__ (self , item ):
242
257
assert isinstance (item , tuple ) or isinstance (item , list )
243
258
assert len (item ) == 2
@@ -247,27 +262,7 @@ def __iter__(self):
247
262
yield from self ._mapping
248
263
249
264
250
- class _ValuesView (abc .ValuesView ):
251
-
252
- def __init__ (self , items , * , getall = False ):
253
- self ._getall = getall
254
- self ._keys = [item [0 ] for item in items ]
255
- if not getall :
256
- self ._keys = set (self ._keys )
257
-
258
- items_to_use = []
259
- if getall :
260
- items_to_use = items
261
- else :
262
- for key in self ._keys :
263
- for k , v in items :
264
- if k == key :
265
- items_to_use .append ((k , v ))
266
- break
267
-
268
- assert len (items_to_use ) == len (self ._keys )
269
-
270
- super ().__init__ (items_to_use )
265
+ class _ValuesView (_ViewBase , abc .ValuesView ):
271
266
272
267
def __contains__ (self , value ):
273
268
for item in self ._mapping :
@@ -280,26 +275,7 @@ def __iter__(self):
280
275
yield item [1 ]
281
276
282
277
283
- class _KeysView (abc .KeysView ):
284
-
285
- def __init__ (self , items , * , getall = False ):
286
- self ._getall = getall
287
- self ._keys = [item [0 ] for item in items ]
288
- if not getall :
289
- self ._keys = set (self ._keys )
290
-
291
- items_to_use = []
292
- if getall :
293
- items_to_use = items
294
- else :
295
- for key in self ._keys :
296
- for k , v in items :
297
- if k == key :
298
- items_to_use .append ((k , v ))
299
- break
300
- assert len (items_to_use ) == len (self ._keys )
301
-
302
- super ().__init__ (items_to_use )
278
+ class _KeysView (_ViewBase , abc .KeysView ):
303
279
304
280
def __contains__ (self , key ):
305
281
return key in self ._keys
0 commit comments