stl michael poeltl © 2011,2013

collections

ChainMap

Mit python3.3 wurde die Klasse ChainMap() *released*. Zuvor, unter python3.2 fand man sie schon als _ChainMap().
Darüber muss man sich klar sein, wenn man ChainMap() einstzen möche, aber python-Interprtoren von prior 3.2 hat.
Ein erstes kleines Beispiel zeigt bereits, was ChainMap() macht.

>>> from collections import ChainMap
>>> erstes = { 'x':7, 'y':8, 'z':-2}
>>> zweites = { 'x':-1.1, 'y':2, 'z':-2.2}
>>> together = ChainMap(erstes,zweites)
>>> print( together['x'])
7
>>> print( together )
ChainMap({'z': -2, 'x': 7, 'y': 8}, {'z': -2.2, 'x': -1.1, 'y': 2})
>>> together
ChainMap({'z': -2, 'x': 7, 'y': 8}, {'z': -2.2, 'x': -1.1, 'y': 2})
>>> together_2 = ChainMap(zweites, erstes)
>>> print( together_2['x'])
-1.1
>>>

Counter

>>> from collections import Counter
>>> print (Counter(open('/etc/resolv.conf').read()).most_common(3))
[('a', 8), ('.', 7), (' ', 5)]
>>>

deque

Der Aufruf von deque(maxsize=3) baut eine Queue mit fixer Größe.
Ist die queue voll (maxsize reached), dann wird das älteste Objekt aus der queue entfernt.

>>> from collections import deque
>>> d = deque(maxlen=4)
>>> d.append('erstes')
>>> d.append(2)
>>> d.append('drei')
>>> d.append(4)
>>> d.append('fuenf')
>>> print( d )
deque([2, 'drei', 4, 'fuenf'], maxlen=4)
>>>

deques scheinen für einfache queue-structures wie geschaffen zu sein.
Ein deque kann man von beiden Seiten *befüllen*, auf beiden Seiten rauspoppen, laenge abfragen, maxsize, die Anordnung umdrehen, das deque leeren...

>>> d.maxlen
4
>>> d.count(2)
1
>>> d.clear() #deque-object leeren!
>>>  print( d )
deque([], maxlen=4)
>>> d.appendleft(178)
>>> d.appendleft(22)
>>> d.append('michael')
>>> print( d )
deque([22, 178, 'michael'], maxlen=4)
>>> d.extend([2,'2'])
>>> print( d )
deque([178, 'michael', 2, '2'], maxlen=4)
>>> d.extendleft([8,'8'])
>>> d.reverse()
>>> d.popleft()
'michael'
>>>

named tuples

retourniert anstatt eines herkömmlichen Objekts ein neues Klassenobjekt.
Das erste Argument ist der name der (tuple)Klasse, und der zweite Parameter ist ein string, der eine Argumentliste enthält, wobei die Argumente entweder mit spaces oder mit Beistrich voneinander getrennt sind.
Syntax ist gewöhnungsbedürftig, aber dann, wenn man es einmal behirnt hat, dann ist man froh, dass es das gibt.

>>> from collections import namedtuple
>>> punkt = namedtuple('punkt', 'x y')
>>> p1 = punkt(0,4)
>>> p2 = punkt(3,-1)
>>> p3 = p1 + p2
>>> type(p3)
<class 'tuple'>
>>> p3
(0, 4, 3, -1)
>>> p1
punkt(x=0, y=4)
>>> p2
punkt(x=3, y=-1)
>>> punkt1 = namedtuple('punkt1', 'x y z')
>>> p01 = punkt1(1,2,3)
>>> p01.z
3
>>> [ i*j for i in p01 for j in p02 ]
[3, -1, 5, 6, -2, 10, 9, -3, 15]
>>> list(map((lambda x,y: x*y), p01,p02))
[3, -2, 15]
>>>

OrderedDict()

dict-Objekte sind, wie Du ja weißt, unordered objects. Das ermöglicht mehr Möglichkeiten bzw. höhere Flexibilität, aber manchmal ist es so, dass man sich geordnete dicts wünscht.

OrderedDict() (großes o, großes d) zeigt auf ein Klassenobjekt. Sehen wir uns ein paar Beispiele an, und dann ist es eh klar, in welche richtung das geht. Diesmal relativ easy.

>>> from collections import OrderedDict
>>> o_d = OrderedDict()
>>> o_d['m'] = 1
>>> o_d['i'] = 2
>>> o_d['c'] = 3
>>> o_d['h'] = 4
>>> print (o_d)
OrderedDict([('m', 1), ('i', 2), ('c', 3), ('h', 4)])
>>> print (o_d[2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 2
>>> print (o_d['i'])
2
>>> o_d.keys()
KeysView(OrderedDict([('m', 1), ('i', 2), ('c', 3), ('h', 4)]))
>>> print (list(o_d.keys()))
['m', 'i', 'c', 'h']
>>> print (list(o_d.values()))
[1, 2, 3, 4]
>>> print (list(o_d.items()))
[('m', 1), ('i', 2), ('c', 3), ('h', 4)]
>>> o_d[30] = 'irgendwas'
>>> o_d.update({7:'a'})
>>> print (o_d)
OrderedDict([('m', 1), ('i', 2), ('c', 3), ('h', 4), (30, 'irgendwas'), (7, 'a')])
>>>

Wir sehen schon, dass diese Klasse offensichtlich von der dict-Klasse geerbt haben muss, denn da gibt es schon viele Methoden, die es dort und da ibt. Also - willst Du geordnete Verhältnisse, dann ist OrderedDict() das, was Du brauchst.

Man könnte übrigens auch eine generator expression einsetzen, um so ein dict oder OrderedDict() zu füllen.

>>> geordnet = OrderedDict( (v, chr(v)) for v in range (96,103))
>>> print (geordnet)
OrderedDict([(96, '`'), (97, 'a'), (98, 'b'), (99, 'c'), (100, 'd'), (101, 'e'), (102, 'f')])
>>>

defaultdict

Das Setzen von default-Werten beim Abruf eines values an einem bestimmten key in einem dict-object haben wir schon gesehen.

>>> from collections import defaultdict
>>> was = defaultdict(bool)
>>> was['eins'] = 1
>>> print (was['gibtsnet'])
False
>>>

Mit defaultdict baut man sich ein dict, und gibt an, von welchem Typ der default-Wert sein soll, und da ein False-Wert; also
str --> '', int --> 0, bool --> False, list --> [], dict --> {}
man wählt das aus, was am ehesten passt.

>>> wer = defaultdict(str)
>>> print (wer['michael'])

>>> wieviel = defaultdict(int)
>>> print (wieviel['baelle'])
0
>>>

Wenn es nur um die default-Werte geht, und das scheint hier der Fall zu sein, dann erspart man sich eine Code-Zeile (get()-methode). Und daher neige ich schon dazu, beim herkömmlichen dict-Objekt zu bleiben.


Hier geht es zum Seitenanfang und da geht es zur python Startseite