Transcript
Page 1: The (unknown) collections module

{“event”:      “PyCon  ES  2013” “author”:  “Pablo  Enfedaque” “twi2er”:  “pablitoev56”

The  unknown  COLLECTIONS

module

Page 2: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Today  we  are  going  to  talk  about  the  (unknown)  collections  module

And  also  about  built-­‐‑in  containers

Welcome!

Page 3: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

“This  module  implements  specialized  container  datatypes  providing  alternatives  to  Python’s  general  purpose  built-­‐‑in  containers,  

dict,  list,  set,  and  tuple”

The  collections  module

Page 4: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  start  with  Python’s  most  used  container

Page 5: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Yes,  that’s  dict

Page 6: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

dict

>>> d = {'a': 1, 'b': 2, 'c': 3}>>> d['b']2>>> d['d'] = 4>>> d{'d': 4, 'b': 2, 'c': 3, 'a': 1}>>> d['e']Traceback (most recent call last): File "<stdin>", line 1, in <module>KeyError: 'e'>>> print(d.get('e'))None>>> d.get('e', 5)5

Page 7: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

OPERATION AVERAGE AMORTIZED  WORST Get  item    d['b'] O(1) O(n) Set  item      d['d'] = 4 O(1)* O(n) Delete  item    del d['b'] O(1) O(n) Copy    new_d = dict(d) O(n) O(N) Iteration    for k in d: O(n) O(N)

dict  performance

>  Internally  implemented  with  an  optimised  hash  map >  *:  Amortized  cost.  Individual  ops  may  be  really  slow

>  N:  Maximum  size  the  container  ever  achieved

Page 8: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

And  what  about  set?

Page 9: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

set

>>> vowels = {'a', 'e', 'i', 'o', 'u'}>>> letters = set(['a', 'b', 'c', 'd', 'e'])>>> vowels – letters{'i', 'o', 'u’}>>> vowels & letters{'a', 'e’}>>> vowels | letters{'u', 'i', 'o', 'c', 'b', 'a', 'e', 'd’}>>> vowels ^ letters{'u', 'i', 'o', 'c', 'b', 'd'}>>> 'b' in lettersTrue>>> letters.add('a')>>> letters{'c', 'b', 'a', 'e', 'd'}>>> letters.update(['d', 'e', 'f', 'g'])>>> letters{'c', 'b', 'a', 'g', 'f', 'e', 'd'}

Page 10: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

OPERATION AVERAGE AMORTIZED  WORST Check  item        'b' in s1 O(1) O(n) Union                                  s1 | s2 O(len(s1)  +  len(s2)) Intersection              s1 & s2 O(min(len(s1),  len(s2))) O(len(s1)  *  len(s2)) Difference                    s1 – s2 O(len(s1)) Symmetric  diff    s1 ^ s2   O(len(s1)) O(len(s1)  *  len(s2))

set  performance

>  Implementation  very  similar  to  dicts  (hash  map) >  Also  has  in-­‐‑place  modification  methods  (its  average  

cost  depends  on  s2)

Page 11: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

A  bit  boring,  isn’t  it?

Page 12: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let'ʹs  do  something  more  appealing

Page 13: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

During  the  talk  we  will  use  this  str

txt = """El desconocido módulo CollectionsTodo el mundo conoce los tipos básicos de Python y sus contenedores más comunes (list, tuple, dict y set). En cambio, poca gente sabe que para implementar una cola debería utilizar un deque, que con un defaultdict su código quedaría más limpio y sería un poco más eficiente o que podría utilizar namedtuples en lugar de crear nuevas clases. En esta charla repasaremos las estructuras del módulo collections de la librería estándar: namedtuple, deque, Counter, OrderedDict y defaultdict. Veremos su funcionalidad, particularidades y casos prácticos de uso.Pablo Enfedaque VidalTrabajo como R&D SW Engineer en Telefónica PDI en Barcelona, y desde hace más de 5 años casi exclusivamente con Python, un lenguaje que me encanta"""

Page 14: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  classify  words

>>> initials = {}def classify_words(text): for word in text.split(): word = word.lower() if word[0] in initials: initials[word[0]].append(word) else: initials[word[0]] = [word, ] for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 15: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Does  it  look  pythonic?

>>> initials = {}def classify_words(text): for word in text.split(): word = word.lower() if word[0] in initials: initials[word[0]].append(word) else: initials[word[0]] = [word, ] for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 16: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

What  about  now?

>>> initials = {}def classify_words(text): for word in text.split(): word = word.lower() initials.setdefault(word[0], []).append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 17: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.defaultdict

from collections import defaultdict>>> initials = defaultdict(list)def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 18: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.defaultdict

from collections import defaultdict>>> initials = defaultdict(list)def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> initials.default_factory<class 'list'>>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 19: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

>  defaultdict  is  a  subclass  of  the  built-­‐‑in  dict  class

>  The  first  argument  provides  the  initial  value  for  the  

default_factory  a2ribute  (it  defaults  to  None)

>  All  remaining  arguments  are  treated  the  same

>  It  also  overrides  the  __missing__  method  to  call  the  

default_factory  when  an  key  is  not  found

>  default_factory  may  raise  an  exception  (e.g.  KeyError)

>  Since  Python  2.5

collections.defaultdict

Page 20: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  continue  classifying  words

Page 21: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Now  we  have  this  custom  class

class WordsByInitial(): "Holds initial letter and a set and a list of words" def __init__(self, letter): self.letter = letter self.words = [] self.unique_words = set() def append(self, word): self.words.append(word) self.unique_words.add(word) def __str__(self): return "<{}: {} {}>".format(self.letter, self.unique_words, self.words)>>> a_words = WordsByInitial('a')>>> a_words.append('ahora')>>> a_words.append('adios')>>> a_words.append('ahora')>>> print(a_words)<a: {'adios', 'ahora'} ['ahora', 'adios', 'ahora']>

Page 22: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

What  if  we  want  to  use  our  class  with  defaultdict?

Page 23: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

How  do  we  get  the  le2er?

class WordsByInitial(): "Holds initial letter and set and list of words" def __init__(self, letter): self.letter = letter self.words = [] self.unique_words = set() def append(self, word): self.words.append(word) self.unique_words.add(word) def __str__(self): return "<{}: {} {}>".format(self.letter, self.unique_words, self.words)>>> a_words = WordsByInitial('a')>>> a_words.append('ahora')>>> a_words.append('adios')>>> a_words.append('ahora')>>> print(a_words)<a: {'adios', 'ahora'} ['ahora', 'adios', 'ahora']>

Page 24: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

What  if  we  want  the  default_factory  to  receive  the  missing  key?

Page 25: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Time  to  code  our  custom  dict

class WordsDict(dict): def __missing__(self, key): res = self[key] = WordsByInitial(key) return resinitials = WordsDict()def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y <y: {'y'} ['y', 'y', 'y', 'y', 'y', 'y']>s <s: {'sería', 'sus', 'set).', 'sabe', 'sw', 'su'} ['sus’...r <r: {'r&d', 'repasaremos'} ['repasaremos', 'r&d']>q <q: {'quedaría', 'que'} ['que', 'que', 'quedaría', 'que’......

Page 26: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Subclass  overriding  __missing__

class WordsDict(dict): def __missing__(self, key): res = self[key] = WordsByInitial(key) return resinitials = WordsDict()def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y <y: {'y'} ['y', 'y', 'y', 'y', 'y', 'y']>s <s: {'sería', 'sus', 'set).', 'sabe', 'sw', 'su'} ['sus’...r <r: {'r&d', 'repasaremos'} ['repasaremos', 'r&d']>q <q: {'quedaría', 'que'} ['que', 'que', 'quedaría', 'que’......

Page 27: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let'ʹs  move  on  to  something  different

Page 28: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  count  words

from collections import defaultdictdef wordcount(s): wc = defaultdict(int) for word in s.split(): wc[word] += 1 return wc>>> wc = wordcount(txt)>>> for letter, num in wc.items(): print(letter, num)del 1implementar 1exclusivamente 1más 4y 6...>>> sorted(wc.items(), reverse=True, key=lambda x: x[1])[:3][('y', 6), ('de', 5), ('más', 4)]

Page 29: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.Counter

from collections import Counterdef wordcount(s): return Counter(s.split())>>> wc = wordcount(txt)>>> for letter, num in wc.items(): print(letter, num)del 1implementar 1exclusivamente 1más 4y 6...>>> wc.most_common(3)[('y', 6), ('de', 5), ('más', 4)]

Page 30: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.Counter

from collections import Counterdef wordcount(s): return Counter(s.split())>>> wc = wordcount(txt)>>> for letter, num in wc.items(): print(letter, num)del 1implementar 1exclusivamente 1más 4y 6...>>> wc.most_common(3)[('y', 6), ('de', 5), ('más', 4)]

Page 31: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

More  on  collections.Counter

>>> c1 = Counter(a=3, e=2, i=-1, o=5)>>> c2 = Counter(a=1, b=1, c=1, d=1, e=1)>>> c1['u']0>>> c1.most_common(2)[('o', 5), ('a', 3)]>>> list(c1.elements())['o', 'o', 'o', 'o', 'o', 'a', 'a', 'a', 'e', 'e']>>> c1.subtract(c2)>>> c1Counter({'o': 5, 'a': 2, 'e': 1, 'c': -1, 'b': -1, 'd': -1, 'i': -1})>>> c1.update(['b', 'c', 'd'])>>> c1Counter({'o': 5, 'a': 2, 'e': 1, 'c': 0, 'b': 0, 'd': 0, 'i': -1})

Page 32: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

More  on  collections.Counter

>>> c1 = Counter(a=3, e=2, i=-1, o=5)>>> c2 = Counter(a=1, b=1, c=1, d=1, e=1)>>> c1 + c2Counter({'o': 5, 'a': 3, 'e': 2, 'c': 1, 'b': 1, 'd': 1})>>> c1 - c2Counter({'o': 5, 'a': 1})>>> c1 & c2Counter({'a': 1, 'e': 1})>>> c1 | c2Counter({'o': 5, 'a': 2, 'c': 1, 'b': 1, 'e': 1, 'd': 1})>>> +c1Counter({'o': 5, 'a': 2, 'e': 1})>>> -c1Counter({'i': 1})

Page 33: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

>  Counter  is  a  dict  subclass  for  counting  hashable  objects

>  dict  interface  but  they  return  0  instead  of  KeyError

>  Three  additional  methods:  most_common,  elements,  

subtract

>  update  method  has  been  overriden

>  Support  for  mathematical  operators:  +,  -­‐‑,  &,  |

>  Since  Python  2.7

collections.Counter

Page 34: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let'ʹs  go  back  to  words  classification

Page 35: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Classify  words  with  defaultdict

from collections import defaultdict>>> initials = defaultdict(list)def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y ['y', 'y', 'y', 'y', 'y', 'y']s ['sus', 'set).', 'sabe', 'su', 'sería', 'su', 'sw']r ['repasaremos', 'r&d']q ['que', 'que', 'quedaría', 'que', 'que']...

Page 36: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

What  if  we  only  want  to  keep  the

last  three  words  for  each  le2er?

Page 37: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.deque

from collections import defaultdict, deque>>> initials = defaultdict(lambda: deque(maxlen=3))def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y deque(['y', 'y', 'y'], maxlen=3)s deque(['sería', 'su', 'sw'], maxlen=3)r deque(['repasaremos', 'r&d'], maxlen=3)q deque(['quedaría', 'que', 'que'], maxlen=3)...

Page 38: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.deque

from collections import defaultdict, deque>>> initials = defaultdict(lambda: deque(maxlen=3))def classify_words(text): for word in text.split(): word = word.lower() initials[word[0]].append(word) for letter, letter_words in initials.items(): print(letter, letter_words)>>> classify_words(txt)y deque(['y', 'y', 'y'], maxlen=3)s deque(['sería', 'su', 'sw'], maxlen=3)r deque(['repasaremos', 'r&d'], maxlen=3)q deque(['quedaría', 'que', 'que'], maxlen=3)...

Page 39: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

More  on  collections.deque

>>> d = deque(maxlen=5)>>> d.extend(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])>>> ddeque(['d', 'e', 'f', 'g', 'h'], maxlen=5)>>> d.append('i')>>> ddeque(['e', 'f', 'g', 'h', 'i'], maxlen=5)>>> d.appendleft('Z')>>> ddeque(['Z', 'e', 'f', 'g', 'h'], maxlen=5)>>> d.rotate(3)>>> ddeque(['f', 'g', 'h', 'Z', 'e'], maxlen=5)>>> d.popleft()'f’>>> ddeque(['g', 'h', 'Z', 'e'], maxlen=5)

Page 40: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

OPERATION AVERAGE AMORTIZED  WORST append('b’) O(1) O(1) appendleft('b’) O(1) O(1) pop() O(1) O(1) popleft() O(1) O(1) extend(iterable) O(k) O(k) extendleft(iterable) O(k) O(k) rotate() O(k) O(k) remove('b’) O(n) O(n)

deque  performance

>  Represented  internally  as  a  doubly  linked  list >  Ideal  to  implement  queues  (FIFO) >  Since  Python  2.4  

Page 41: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

OPERATION AVERAGE AMORTIZED  WORST append('b’) O(1)* O(1)* insert(index, 'b’) O(n) O(n) Get  item    d[4] O(1) O(1) Set  item      d[4] = 'd' O(1) O(1) Delete  item    del d[4] O(n) O(n) extend(iterable) O(k)* O(k)* Check  item    'b' in list O(n) O(n) Sort O(n  log  n) O(n  log  n)

list  performance

>  Represented  internally  as  an  array >  *:  Amortized  cost.  Individual  ops  may  be  really  slow

>  Ideal  to  implement  stacks  (LIFO)

Page 42: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  move  to  a  different  example

Page 43: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  implement  a  SW  cache

CACHE = {}def set_key(key, value): "Set a key value" CACHE[key] = valuedef get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None)>>> set_key("my_key", "the_value”)>>> print(get_key("my_key"))the_value>>> print(get_key("not_found_key"))None

Page 44: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

What  if  we  want  to  limit  its  size?

Page 45: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.OrderedDict

from collections import OrderedDictCACHE = OrderedDict()MAX_SIZE = 3def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False)def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None)>>> set_key("my_key", "the_value”)>>> print(get_key("my_key"))the_value>>> print(get_key("not_found_key"))None>>> CACHEOrderedDict([('c', 3), ('d', 4), ('e', 5)])

Page 46: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.OrderedDict

from collections import OrderedDictCACHE = OrderedDict()MAX_SIZE = 3def set_key(key, value): "Set a key value, removing oldest key if MAX_SIZE exceeded" CACHE[key] = value if len(CACHE) > MAX_SIZE: CACHE.popitem(last=False)def get_key(key): "Retrieve a key value from the cache, or None if not found" return CACHE.get(key, None)>>> set_key("my_key", "the_value”)>>> print(get_key("my_key"))the_value>>> print(get_key("not_found_key"))None>>> CACHEOrderedDict([('c', 3), ('d', 4), ('e', 5)])

Page 47: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.OrderedDict

>>> d = OrderedDict()>>> d.update([(‘a', 1), (‘e', 2), ('i', 3), ('o', 4), ('u', 5)])>>> dOrderedDict([('a', 1), ('e', 2), ('i', 3), ('o', 4), ('u', 5)])>>> d['i'] = 0>>> list(d.items())[('a', 1), ('e', 2), ('i', 0), ('o', 4), ('u', 5)]>>> d.popitem()('u', 5)>>> d.popitem(last=False)('a', 1)>>> dOrderedDict([('e', 2), ('i', 0), ('o', 4)])>>> d.move_to_end('i')>>> dOrderedDict([('e', 2), ('o', 4), ('i', 0)])>>> d.move_to_end('i', last=False)>>> dOrderedDict([('i', 0), ('e', 2), ('o', 4)])>>> d == OrderedDict([('e', 1), ('i', 2), ('o', 3)])False

Page 48: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

>  OrderedDict  is  a  subclass  of  the  built-­‐‑in  dict  class

>  Remembers  the  order  that  keys  were  first  inserted

>  Updating  a  key  does  not  modify  its  order

>  Two  additional  methods:  popitem,  move_to_end

>  Also  supports  reverse  iteration  using  reversed

>  Since  Python  2.7

collections.OrderedDict

Page 49: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

And  finally,  one  last  example

Page 50: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Let’s  implement  an  image

class Color: def __init__(self, r, g, b): self.r = r self.g = g self.b = bclass Image: def __init__(self, w, h, pixels): self.w = w self.h = h self.pixels = pixels def rotate(self): pass>>> pixels = [Color(127, 127, 127), Color(127, 100, 100), Color(127, 75, 75), ]>>> picture = Image(1280, 720, pixels)

Page 51: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Do  we  really  need  a  class?

class Color: def __init__(self, r, g, b): self.r = r self.g = g self.b = bclass Image: def __init__(self, w, h, pixels): self.w = w self.h = h self.pixels = pixels def rotate(self): pass>>> pixels = [Color(127, 127, 127), Color(127, 100, 100), Color(127, 75, 75), ]>>> picture = Image(1280, 720, pixels)

Page 52: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.namedtuple

>>> from collections import namedtuple>>> Color = namedtuple('Color', ['r', 'g', 'b'])class Image: def __init__(self, w, h, pixels): self.w = w self.h = h self.pixels = pixels def rotate(self): pass>>> pixels = [Color(127, 127, 127), Color(127, 100, 100), Color(127, 75, 75), ]>>> picture = Image(1280, 720, pixels)>>> p = Color(127, 75, 25)>>> p[1]75>>> p.b25

Page 53: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

collections.namedtuple

>>> from collections import namedtuple>>> Color = namedtuple('Color', ['r', 'g', 'b'])class Image: def __init__(self, w, h, pixels): self.w = w self.h = h self.pixels = pixels def rotate(self): pass>>> pixels = [Color(127, 127, 127), Color(127, 100, 100), Color(127, 75, 75), ]>>> picture = Image(1280, 720, pixels)>>> p = Color(127, 75, 25)>>> p[1]75>>> p.b25

Page 54: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

>  Tuple  sublcasses  factory

>  A2ribute  lookup

>  Indexable

>  Iterable

>  Helpful  docstring  and  repr

>  Since  Python  2.6

collections.namedtuple

Page 55: The (unknown) collections module

{  “event”:  “PyCon  ES  2013”,  “author”:  “Pablo  Enfedaque”,  “twi2er”:  “pablitoev56”}

Q&A

Thanks  for  coming!

Slides:


Recommended