|
| 1 | +# Handy classes in the standard library |
| 2 | + |
| 3 | +So far we have learned to use lists, tuples and dictionaries. They are |
| 4 | +commonly used data types in Python. The standard library contains more |
| 5 | +handy types that behave a lot like the datatypes that we know already. |
| 6 | +You can always use the built-in types instead of the collections module, |
| 7 | +but sometimes the collections module makes everything a lot easier. |
| 8 | + |
| 9 | +## Sets |
| 10 | + |
| 11 | +Let's say we have two lists of strings |
| 12 | + |
| 13 | +```python |
| 14 | + |
| 15 | +``` |
| 16 | + |
| 17 | +## Named tuples |
| 18 | + |
| 19 | +It can be tempting to make a class that just contains a bunch of data |
| 20 | +and that's it. |
| 21 | + |
| 22 | +```python |
| 23 | +class Website: |
| 24 | + |
| 25 | + def __init__(self, url, founding_year, free_to_use): |
| 26 | + self.url = url |
| 27 | + self.founding_year = founding_year |
| 28 | + self.free_to_use = free_to_use |
| 29 | + |
| 30 | + |
| 31 | +github = Website('https://github.com/', 2008, True) |
| 32 | +``` |
| 33 | + |
| 34 | +You should avoid making classes like this. This class has only one |
| 35 | +method, so it doesn't really need to be a class. We could just use a |
| 36 | +tuple instead: |
| 37 | + |
| 38 | +```python |
| 39 | +github = ('https://github.com/', 2008, True) |
| 40 | +``` |
| 41 | + |
| 42 | +The problem with this is that if someone reading our code sees something |
| 43 | +like `website[1] > 2010` it's not going to make much sense, like |
| 44 | +`website.founding_year > 2010` would. |
| 45 | + |
| 46 | +In cases like this, `collections.namedtuple` is handy: |
| 47 | + |
| 48 | +```python |
| 49 | +>>> Website = collections.namedtuple('Website', 'url founding_year free_to_use') |
| 50 | +>>> github = Website('https://github.com/', 2008, True) |
| 51 | +>>> github[1] |
| 52 | +2008 |
| 53 | +>>> for thing in github: |
| 54 | +... print(thing) |
| 55 | +... |
| 56 | +https://github.com/ |
| 57 | +2008 |
| 58 | +True |
| 59 | +>>> github.founding_year |
| 60 | +2008 |
| 61 | +>>> github |
| 62 | +Website(url='https://github.com/', founding_year=2008, free_to_use=True) |
| 63 | +>>> print(github) |
| 64 | +Website(url='https://github.com/', founding_year=2008, free_to_use=True) |
| 65 | +>>> |
| 66 | +``` |
| 67 | + |
| 68 | +As you can see, our `github` behaves like a tuple, but |
| 69 | +`github.founding_year` also works and `github` looks nice when we have a |
| 70 | +look at it on the `>>>` prompt or we print it. |
| 71 | + |
| 72 | +## Deques |
| 73 | + |
| 74 | +To understand deques, we need to first learn about a list method I |
| 75 | +haven't talked about earlier. It's called `pop` and it works like this: |
| 76 | + |
| 77 | +```python |
| 78 | +>>> names = ['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish'] |
| 79 | +>>> names.pop() |
| 80 | +'go|dfish' |
| 81 | +>>> names |
| 82 | +['wub_wub', 'theelous3', 'Nitori', 'RubyPinch'] |
| 83 | +>>> names.pop() |
| 84 | +'RubyPinch' |
| 85 | +>>> names |
| 86 | +['wub_wub', 'theelous3', 'Nitori'] |
| 87 | +>>> names.pop() |
| 88 | +'Nitori' |
| 89 | +>>> names |
| 90 | +['wub_wub', 'theelous3'] |
| 91 | +``` |
| 92 | + |
| 93 | +As you can see, the list shortens by one from the end when we pop from |
| 94 | +it, and we also get the removed value back. So now we know that we can |
| 95 | +add an item to the end of a list using `append`, and we can remove an |
| 96 | +item from the end using `pop`. |
| 97 | + |
| 98 | +It's also possible to do this in the beginning of a list, but lists were |
| 99 | +not designed to be used that way and it would be slow if our list would |
| 100 | +be big. |
| 101 | + |
| 102 | +The `collections.deque` class makes appending and popping from both ends |
| 103 | +easy and fast. It works just like lists, but it also has `appendleft` |
| 104 | +and `popleft` methods. |
| 105 | + |
| 106 | +```python |
| 107 | +>>> names = collections.deque(['theelous3', 'Nitori', 'RubyPinch']) |
| 108 | +>>> names |
| 109 | +deque(['theelous3', 'Nitori', 'RubyPinch']) |
| 110 | +>>> names.appendleft('wub_wub') |
| 111 | +>>> names.append('go|dfish') |
| 112 | +>>> names |
| 113 | +deque(['wub_wub', 'theelous3', 'Nitori', 'RubyPinch', 'go|dfish']) |
| 114 | +>>> names.popleft() |
| 115 | +'wub_wub' |
| 116 | +>>> names.pop() |
| 117 | +'go|dfish' |
| 118 | +>>> names |
| 119 | +deque(['theelous3', 'Nitori', 'RubyPinch']) |
| 120 | +>>> |
| 121 | +``` |
| 122 | + |
| 123 | +Deques are often used as queues. It means that items are always added to |
| 124 | +one end and popped from the other end. |
| 125 | + |
| 126 | + |
| 127 | +**TODO:** add some of ChainMap, Counter, OrderedDict, defaultdict, deque, sets |
0 commit comments