|
| 1 | +# Lists and tuples |
| 2 | + |
| 3 | +## Why should we use lists? |
| 4 | + |
| 5 | +Sometimes we may end up doing something like this. |
| 6 | + |
| 7 | +```py |
| 8 | +name1 = 'wub_wub' |
| 9 | +name2 = 'theelous3' |
| 10 | +name3 = 'RubyPinch' |
| 11 | +name4 = 'go|dfish' |
| 12 | +name5 = 'Nitori' |
| 13 | + |
| 14 | +name = input("Enter your name: ") |
| 15 | +if name == name1 or name == name2 or name == name3 or name == name4 or name == name5: |
| 16 | + print("I know you!") |
| 17 | +else: |
| 18 | + print("Sorry, I don't know who you are :(") |
| 19 | +``` |
| 20 | + |
| 21 | +This code works just fine, but there's a problem. The name check |
| 22 | +is repetitive, and adding a new name requires adding even more |
| 23 | +repetitive, boring checks. |
| 24 | + |
| 25 | +## Our first list |
| 26 | + |
| 27 | +Instead of adding a new variable for each name it might be |
| 28 | +better to store all names in one variable. This means that our |
| 29 | +one variable needs to point to multiple values. An easy way to |
| 30 | +do this is using a list: |
| 31 | + |
| 32 | +```py |
| 33 | +names = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] |
| 34 | +``` |
| 35 | + |
| 36 | +Here the `names` variable points to a list, which then points to |
| 37 | +strings, like this: |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | +## What can we do with lists? |
| 42 | + |
| 43 | +Let's open the `>>>` prompt and create a name list. |
| 44 | + |
| 45 | +```py |
| 46 | +>>> names = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] |
| 47 | +>>> names |
| 48 | +['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] |
| 49 | +>>> |
| 50 | +``` |
| 51 | + |
| 52 | +There's many things [we can do with strings](handy-stuff-strings.md), |
| 53 | +and some of these things also work with lists. |
| 54 | + |
| 55 | +```py |
| 56 | +>>> len(names) # we have 5 names |
| 57 | +5 |
| 58 | +>>> names + ['Akuli'] # create a new list with me in it |
| 59 | +['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori', 'Akuli'] |
| 60 | +>>> ['theelous3', 'RubyPinch'] * 2 # repeating |
| 61 | +['theelous3', 'RubyPinch', 'theelous3', 'RubyPinch'] |
| 62 | +>>> |
| 63 | +``` |
| 64 | + |
| 65 | +With strings indexing and slicing both returned a string, but |
| 66 | +with lists we get a new list when we're slicing and an element |
| 67 | +from the list if we're indexing. |
| 68 | + |
| 69 | +```py |
| 70 | +>>> names[:2] # first two names |
| 71 | +['wub_wub', 'theelous3'] |
| 72 | +>>> names[0] # the first name |
| 73 | +'wub_wub' |
| 74 | +>>> |
| 75 | +``` |
| 76 | + |
| 77 | +If we want to check if the program knows a name all we need to |
| 78 | +do is to use the `in` keyword. |
| 79 | + |
| 80 | +```py |
| 81 | +>>> 'lol' in names |
| 82 | +False |
| 83 | +>>> 'RubyPinch' in names |
| 84 | +True |
| 85 | +>>> |
| 86 | +``` |
| 87 | + |
| 88 | +We can't use this for checking if a list of names is a part of |
| 89 | +our name list. |
| 90 | + |
| 91 | +```py |
| 92 | +>>> ['RubyPinch', 'go|dfish'] in names |
| 93 | +False |
| 94 | +>>> ['RubyPinch'] in names |
| 95 | +False |
| 96 | +>>> |
| 97 | +``` |
| 98 | + |
| 99 | +Lists have a few [useful |
| 100 | +methods](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists). |
| 101 | +Some of the most commonly used ones are append, extend and |
| 102 | +remove. append adds an item to the end of a list, extend adds |
| 103 | +multiple items from another list and remove removes an item. |
| 104 | + |
| 105 | +```py |
| 106 | +>>> names |
| 107 | +['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] |
| 108 | +>>> names.remove('theelous3') # sorry theelous3 |
| 109 | +>>> names.remove('go|dfish') # and sorry go|dfish |
| 110 | +>>> names |
| 111 | +['wub_wub', 'RubyPinch', 'Nitori'] |
| 112 | +>>> names.append('Akuli') # let's add me here |
| 113 | +>>> names |
| 114 | +['wub_wub', 'RubyPinch', 'Nitori', 'Akuli'] |
| 115 | +>>> names.extend(['go|dfish', 'theelous3']) # wb guys |
| 116 | +>>> names |
| 117 | +['wub_wub', 'RubyPinch', 'Nitori', 'Akuli', 'go|dfish', 'theelous3'] |
| 118 | +>>> |
| 119 | +``` |
| 120 | + |
| 121 | +As you can see, **list can be changed in-place**. In other |
| 122 | +words, they are **mutable**. Integers, floats, strings and many |
| 123 | +other built-in types can't, so they are **immutable**. |
| 124 | + |
| 125 | +With [strings](handy-stuff-strings.md) we did something to them |
| 126 | +and then set the result back to the same variable, like |
| 127 | +`message = message.strip()`. This just doesn't work right with |
| 128 | +most mutable things because they're designed to be changed in-place. |
| 129 | + |
| 130 | +```py |
| 131 | +>>> names = names.remove('Akuli') |
| 132 | +>>> print(names) # now it's None! |
| 133 | +None |
| 134 | +>>> |
| 135 | +``` |
| 136 | + |
| 137 | +This is the same thing that happened way back when [we assigned |
| 138 | +print's return value to a variable](using-functions.md). |
| 139 | + |
| 140 | +## What is what? |
| 141 | + |
| 142 | +After working with lists a while you'll find out that they |
| 143 | +behave like this: |
| 144 | + |
| 145 | +```py |
| 146 | +>>> a = [1, 2, 3] |
| 147 | +>>> b = a |
| 148 | +>>> b.append(4) |
| 149 | +>>> a # this changed also! |
| 150 | +[1, 2, 3, 4] |
| 151 | +>>> |
| 152 | +``` |
| 153 | + |
| 154 | +This can be confusing at first, but it's actually easy to |
| 155 | +explain. The problem with this code example is the `b = a` |
| 156 | +line. If we draw a diagram of this example it looks like this: |
| 157 | + |
| 158 | + |
| 159 | + |
| 160 | +This is when the `is` keyword comes in. It can be used to |
| 161 | +check if two variables point to the **same** thing. |
| 162 | + |
| 163 | +```py |
| 164 | +>>> a is b |
| 165 | +True |
| 166 | +>>> |
| 167 | +``` |
| 168 | + |
| 169 | +Typing `[]` creates a **new** list every time. |
| 170 | + |
| 171 | +```py |
| 172 | +>>> [] is [] |
| 173 | +False |
| 174 | +>>> |
| 175 | +``` |
| 176 | + |
| 177 | +If we need a new list with the same content we can use the |
| 178 | +`copy` method: |
| 179 | + |
| 180 | +```py |
| 181 | +>>> a = [1, 2, 3] |
| 182 | +>>> b = a.copy() |
| 183 | +>>> b is a |
| 184 | +False |
| 185 | +>>> b.append(4) |
| 186 | +>>> a |
| 187 | +[1, 2, 3] |
| 188 | +>>> |
| 189 | +``` |
| 190 | + |
| 191 | +If you're using Python 3.2 or older you can do `a[:]` instead |
| 192 | +of `a.copy()`. `a[:]` is a slice of the whole list, just like |
| 193 | +`a[0:]`. |
| 194 | + |
| 195 | +## Tuples |
| 196 | + |
| 197 | +Tuples are a lot like lists, but they're immutable so they |
| 198 | +can't be changed in-place. We create them like lists, but |
| 199 | +with `()` instead of `[]`. |
| 200 | + |
| 201 | +```py |
| 202 | +>>> thing = (1, 2, 3) |
| 203 | +>>> thing |
| 204 | +(1, 2, 3) |
| 205 | +>>> thing = () |
| 206 | +>>> thing |
| 207 | +() |
| 208 | +>>> |
| 209 | +``` |
| 210 | + |
| 211 | +If we need to create a tuple that contains only one item we |
| 212 | +need to use `(item,)` instead of `(item)` because `(item)` is |
| 213 | +used in places like `(1 + 2) * 3`. |
| 214 | + |
| 215 | +```py |
| 216 | +>>> (3) |
| 217 | +3 |
| 218 | +>>> (3,) |
| 219 | +(3,) |
| 220 | +>>> (1 + 2) * 3 |
| 221 | +9 |
| 222 | +>>> (1 + 2,) * 3 |
| 223 | +(3, 3, 3) |
| 224 | +>>> |
| 225 | +``` |
| 226 | + |
| 227 | +Tuples don't have methods like append, extend and remove |
| 228 | +because they can't change theirselves in-place. |
| 229 | + |
| 230 | +```py |
| 231 | +>>> stuff = (1, 2, 3) |
| 232 | +>>> stuff.append(4) |
| 233 | +Traceback (most recent call last): |
| 234 | + File "<stdin>", line 1, in <module> |
| 235 | +AttributeError: 'tuple' object has no attribute 'append' |
| 236 | +>>> |
| 237 | +``` |
| 238 | + |
| 239 | +So, why the heck would we use tuples instead of lists? There's |
| 240 | +a few cases when we don't want mutability, but there's also |
| 241 | +cases when Python programmers just like to use tuples. If you |
| 242 | +want to know more about this you can read [Ned Batchelder's blog |
| 243 | +post about this](http://nedbatchelder.com/blog/201608/lists_vs_tuples.html). |
| 244 | + |
| 245 | +## Summary |
| 246 | + |
| 247 | +- Lists are a way to point to multiple values with just one variable. |
| 248 | +- Lists can be changed in-place and they have methods that change them |
| 249 | + in-place, like append, extend and remove. |
| 250 | +- Slicing lists returns a **new** list, and indexing them returns an |
| 251 | + item from them. |
| 252 | +- `thing = another_thing` does not create a copy of `another_thing`. |
| 253 | +- Tuples are like lists, but they can't be changed in-place. They're |
| 254 | + also used in different places. |
| 255 | + |
| 256 | +## Examples |
| 257 | + |
| 258 | +Here's the same program we had in the beginning of this tutorial, but |
| 259 | +using a list: |
| 260 | + |
| 261 | +```py |
| 262 | +namelist = ['wub_wub', 'theelous3', 'RubyPinch', 'go|dfish', 'Nitori'] |
| 263 | + |
| 264 | +name = input("Enter your name: ") |
| 265 | +if name in namelist: |
| 266 | + print("I know you!") |
| 267 | +else: |
| 268 | + print("Sorry, I don't know who you are :(") |
| 269 | +``` |
0 commit comments