WEBVTT 1 00:00:02.461 --> 00:00:04.369 Now as we saw in the previous videos 2 00:00:04.369 --> 00:00:05.491 in this section, 3 00:00:05.491 --> 00:00:08.221 Python classes don't need getters and setters 4 00:00:08.221 --> 00:00:10.120 to allow you to read and change the values 5 00:00:10.120 --> 00:00:11.872 of their data attributes 6 00:00:11.872 --> 00:00:14.522 or instance variables if you're more familiar with that term 7 00:00:14.522 --> 00:00:16.883 from other programming languages. 8 00:00:16.883 --> 00:00:18.333 Python adopts the philosophy 9 00:00:18.333 --> 00:00:20.413 that we're all responsible adults 10 00:00:20.413 --> 00:00:22.261 so it doesn't have the facility 11 00:00:22.261 --> 00:00:24.643 to make class attributes private 12 00:00:24.643 --> 00:00:27.504 like many other object oriented languages do. 13 00:00:27.504 --> 00:00:28.393 Now with that said, 14 00:00:28.393 --> 00:00:30.934 getters and setters are still useful in Python, 15 00:00:30.934 --> 00:00:33.473 even if they're not essential so in this video, 16 00:00:33.473 --> 00:00:35.283 we're gonna take a look at what they are, 17 00:00:35.283 --> 00:00:38.345 how to create them, and why you might want to do so. 18 00:00:38.345 --> 00:00:39.625 Now I'm gonna start off 19 00:00:39.625 --> 00:00:42.273 by doing something quite controversial. 20 00:00:42.273 --> 00:00:46.192 I'm gonna put each of our classes in a separate file. 21 00:00:46.192 --> 00:00:50.094 Now this is the usual way of doing things in C++ or Java, 22 00:00:50.094 --> 00:00:53.412 but there's no need to have one file per class in Python. 23 00:00:53.412 --> 00:00:54.245 And in fact, 24 00:00:54.245 --> 00:00:56.623 if I was creating these classes in a working programme, 25 00:00:56.623 --> 00:00:59.811 I would actually keep them all in the same file. 26 00:00:59.811 --> 00:01:01.402 But the reason I'm gonna do that here 27 00:01:01.402 --> 00:01:03.671 is because we're gonna be flicking back and forth 28 00:01:03.671 --> 00:01:05.442 looking at the various classes 29 00:01:05.442 --> 00:01:07.292 while I describe what's going on 30 00:01:07.292 --> 00:01:09.011 and that's much easier to do 31 00:01:09.011 --> 00:01:11.522 if each class appears in its own tab in the editor 32 00:01:11.522 --> 00:01:14.242 rather than scrolling up and down through a single file. 33 00:01:14.242 --> 00:01:16.863 And it also provides an excuse to show you another way 34 00:01:16.863 --> 00:01:18.492 of importing a class. 35 00:01:18.492 --> 00:01:19.325 So I'm doing it here 36 00:01:19.325 --> 00:01:22.322 but remember that it's not necessary to do this in Python. 37 00:01:22.322 --> 00:01:25.140 You're better off keeping related classes in the same file 38 00:01:25.140 --> 00:01:28.690 so that each file is organised based on functionality. 39 00:01:28.690 --> 00:01:30.442 Okay, so we're gonna use the characters 40 00:01:30.442 --> 00:01:33.050 in a role playing type game for our examples 41 00:01:33.050 --> 00:01:35.128 so let's create a new Python project. 42 00:01:35.128 --> 00:01:37.591 We're gonna call it game. 43 00:01:37.591 --> 00:01:39.674 Python is selected there. 44 00:01:40.562 --> 00:01:41.395 Game. 45 00:01:45.682 --> 00:01:47.290 Now our first class is gonna be used 46 00:01:47.290 --> 00:01:49.660 to represent the people playing the game 47 00:01:49.660 --> 00:01:53.601 so let's create a new Python file called player.py 48 00:01:53.601 --> 00:01:55.709 so I'm just gonna come over here as normal, 49 00:01:55.709 --> 00:01:59.560 right click, new, Python file, file I should say, 50 00:01:59.560 --> 00:02:02.060 player is the name, all right. 51 00:02:04.421 --> 00:02:06.429 So each player is gonna have a name 52 00:02:06.429 --> 00:02:08.970 as well as things like the number of lives they've got left 53 00:02:08.970 --> 00:02:10.240 and their score. 54 00:02:10.240 --> 00:02:13.008 So we're gonna start with this basic player class. 55 00:02:13.008 --> 00:02:17.175 So we're gonna type class Player object colon enter enter 56 00:02:20.480 --> 00:02:24.647 and then we're gonna do def space underscore underscore init 57 00:02:25.680 --> 00:02:28.648 and you saw that I just selected that for ourself, 58 00:02:28.648 --> 00:02:31.488 but then I also need to do a semicolon and a name 59 00:02:31.488 --> 00:02:35.655 for the parameter and we're gonna do self.name equals name 60 00:02:38.076 --> 00:02:41.937 then we're gonna do self.lives is equal to three, 61 00:02:41.937 --> 00:02:46.104 self.level is equal to one and self.score equals zero. 62 00:02:49.619 --> 00:02:51.288 So the convention is that class name 63 00:02:51.288 --> 00:02:53.006 should start with a capital letter, 64 00:02:53.006 --> 00:02:55.187 although some of the built-in classes in Python 65 00:02:55.187 --> 00:02:57.026 don't follow that convention. 66 00:02:57.026 --> 00:03:00.137 Now this is a very simple class with four data attributes 67 00:03:00.137 --> 00:03:02.777 and their given values in the class constructor, 68 00:03:02.777 --> 00:03:04.288 the underscore underscore init, 69 00:03:04.288 --> 00:03:06.139 underscore underscore method. 70 00:03:06.139 --> 00:03:08.276 And again, that's the class constructor. 71 00:03:08.276 --> 00:03:10.617 Now we pass one of these values as a parameter 72 00:03:10.617 --> 00:03:12.347 so when we create each player, 73 00:03:12.347 --> 00:03:14.917 they're given a name when they're created. 74 00:03:14.917 --> 00:03:17.637 Now the other three values start off with default values, 75 00:03:17.637 --> 00:03:21.499 three for lives, one for level and a score of zero. 76 00:03:21.499 --> 00:03:23.087 All right, so we're going to put all the code 77 00:03:23.087 --> 00:03:26.234 that uses the classes in a file called main.py 78 00:03:26.234 --> 00:03:29.483 so let's go ahead and create that. 79 00:03:29.483 --> 00:03:33.650 We're gonna right click on new Python file, call it main, 80 00:03:36.714 --> 00:03:40.464 and the code is gonna be import space Player, 81 00:03:42.455 --> 00:03:46.622 tim equals player in lowercase dot player in uppercase 82 00:03:49.723 --> 00:03:50.806 and then tim, 83 00:03:52.592 --> 00:03:55.509 print tim.name and print tim.lives. 84 00:04:01.064 --> 00:04:03.401 Okay, now I've accidentally put a capital P in there 85 00:04:03.401 --> 00:04:06.384 for the import and it should've been lowercase P 86 00:04:06.384 --> 00:04:08.552 because the filename you can see in the top left hand corner 87 00:04:08.552 --> 00:04:11.293 has a lowercase P for the name 88 00:04:11.293 --> 00:04:13.482 so I'll just do a lowercase P 89 00:04:13.482 --> 00:04:16.103 and we can see it's now finding it 90 00:04:16.103 --> 00:04:18.413 and that error should disappear. 91 00:04:18.413 --> 00:04:22.384 All right, so just to confirm this, if we run this now, 92 00:04:22.384 --> 00:04:24.301 okay, we can see there, 93 00:04:25.232 --> 00:04:26.682 I'm gonna move this down to the bottom, 94 00:04:26.682 --> 00:04:31.304 the player's name is tim and he's got three lives. 95 00:04:31.304 --> 00:04:33.413 All right, now having to type player with lowercase 96 00:04:33.413 --> 00:04:35.314 dot player in uppercase 97 00:04:35.314 --> 00:04:37.213 every time we wanna refer to the player class 98 00:04:37.213 --> 00:04:38.652 is gonna be a bit annoying 99 00:04:38.652 --> 00:04:42.362 so we can change the way that we input the player module 100 00:04:42.362 --> 00:04:43.664 to avoid this. 101 00:04:43.664 --> 00:04:46.162 So up here on line one, let's actually change this 102 00:04:46.162 --> 00:04:47.121 instead of import player to be 103 00:04:47.121 --> 00:04:50.621 from player import Player with a capital P 104 00:04:55.471 --> 00:04:57.281 and then we can just change this definition here 105 00:04:57.281 --> 00:04:59.948 just to be tim equals Player tim 106 00:05:01.001 --> 00:05:04.692 and we can run this and we get the same result. 107 00:05:04.692 --> 00:05:07.823 So basically we can refer to the player class 108 00:05:07.823 --> 00:05:10.401 without having to qualify it with the module name. 109 00:05:10.401 --> 00:05:12.743 Now I did suggest previously 110 00:05:12.743 --> 00:05:14.891 that you don't use this kind of import 111 00:05:14.891 --> 00:05:17.241 and generally I wouldn't recommend it. 112 00:05:17.241 --> 00:05:18.303 But here though, 113 00:05:18.303 --> 00:05:21.292 each module is only gonna contain a single class 114 00:05:21.292 --> 00:05:23.492 so there's really not gonna be any confusion 115 00:05:23.492 --> 00:05:25.591 about where a player is coming from. 116 00:05:25.591 --> 00:05:26.424 Now as I've said, 117 00:05:26.424 --> 00:05:29.161 you probably wouldn't place each class in its own file, 118 00:05:29.161 --> 00:05:31.721 but as we are doing that to this exercise, 119 00:05:31.721 --> 00:05:34.902 we may as well make it a lot easier for ourselves. 120 00:05:34.902 --> 00:05:38.252 All right, so we've got a basic player class 121 00:05:38.252 --> 00:05:40.481 and we could take lives away from the players 122 00:05:40.481 --> 00:05:42.193 as we get into scraps and take damage 123 00:05:42.193 --> 00:05:44.583 from the monsters that they'll be fighting. 124 00:05:44.583 --> 00:05:47.961 So we can do something like here on line seven 125 00:05:47.961 --> 00:05:50.128 tim.lives minus equals one 126 00:05:52.161 --> 00:05:54.943 which is obviously going to deduct the number of lives, 127 00:05:54.943 --> 00:05:56.651 one from the number of lives, 128 00:05:56.651 --> 00:06:01.081 and print out tim.lives and if you run this, 129 00:06:01.081 --> 00:06:03.121 we get this at the bottom of the screen 130 00:06:03.121 --> 00:06:07.151 showing the lives has been decremented and it's now two. 131 00:06:07.151 --> 00:06:08.841 So this is making fine 132 00:06:08.841 --> 00:06:10.823 and the code is accessing the player class 133 00:06:10.823 --> 00:06:13.921 data attributes directly to print them out 134 00:06:13.921 --> 00:06:15.681 or alter their values. 135 00:06:15.681 --> 00:06:18.943 Now the attributes such as lives and names 136 00:06:18.943 --> 00:06:21.543 are encapsulated in the player class, 137 00:06:21.543 --> 00:06:23.022 but they're not hidden 138 00:06:23.022 --> 00:06:27.303 and that's something that I'm sure Java and C++ programmers 139 00:06:27.303 --> 00:06:30.383 will find horrible because in those languages, 140 00:06:30.383 --> 00:06:32.751 providing direct access to the data attributes 141 00:06:32.751 --> 00:06:35.551 is really frowned upon but in Python, 142 00:06:35.551 --> 00:06:36.970 it's considered the opposite, 143 00:06:36.970 --> 00:06:39.511 in other words the way to do things. 144 00:06:39.511 --> 00:06:41.983 So the first thing I'm gonna say about getters and setters 145 00:06:41.983 --> 00:06:44.991 in Python is don't use them. 146 00:06:44.991 --> 00:06:47.063 And I guess that's probably a strange thing to say 147 00:06:47.063 --> 00:06:50.090 in a video about using getters and setters in Python 148 00:06:50.090 --> 00:06:53.044 so I better explain that I don't mean never use them, 149 00:06:53.044 --> 00:06:54.913 I mean don't worry about them 150 00:06:54.913 --> 00:06:57.011 when you're creating your classes 151 00:06:57.011 --> 00:06:59.644 and that's because chances are you won't need them 152 00:06:59.644 --> 00:07:02.342 so don't spend time creating getters and setters 153 00:07:02.342 --> 00:07:04.844 that won't be needed. 154 00:07:04.844 --> 00:07:09.673 Now in Python, you can add a getter or a setter or both 155 00:07:09.673 --> 00:07:13.324 after you created your class and any code using the class 156 00:07:13.324 --> 00:07:15.282 will continue to work fine, 157 00:07:15.282 --> 00:07:18.564 but in Java or C++ that's not possible. 158 00:07:18.564 --> 00:07:22.311 If you allow access to class instance variables later 159 00:07:22.311 --> 00:07:24.052 to start to make them private, 160 00:07:24.052 --> 00:07:26.931 any code that uses the class will have to be changed 161 00:07:26.931 --> 00:07:29.481 to use the getters and setters instead. 162 00:07:29.481 --> 00:07:31.931 As we see in Python though, client code, 163 00:07:31.931 --> 00:07:35.550 that's code that is using the class, isn't affected. 164 00:07:35.550 --> 00:07:38.262 All right, so what are these getters and setters? 165 00:07:38.262 --> 00:07:40.131 Well, a getter is actually a method 166 00:07:40.131 --> 00:07:44.110 that's used to get the value of a data attribute. 167 00:07:44.110 --> 00:07:47.422 So as an example, if we look at the code on line five, 168 00:07:47.422 --> 00:07:48.910 it's actually printing out 169 00:07:48.910 --> 00:07:52.161 the data attribute directly, tim.name, 170 00:07:52.161 --> 00:07:54.007 so instead of that if we wanted to access a name, 171 00:07:54.007 --> 00:07:56.328 we might come down and do something like this, 172 00:07:56.328 --> 00:07:59.495 print tim.get underscore name like so. 173 00:08:04.120 --> 00:08:07.819 So the get underscore name method is called a getter 174 00:08:07.819 --> 00:08:09.589 and normally it just returns the value 175 00:08:09.589 --> 00:08:11.659 of the corresponding variable, 176 00:08:11.659 --> 00:08:13.320 but it can actually do more than that. 177 00:08:13.320 --> 00:08:15.338 For example, the getter for the score 178 00:08:15.338 --> 00:08:18.469 could multiply the score by perhaps the number of lives. 179 00:08:18.469 --> 00:08:20.778 That way, a player's score is much higher 180 00:08:20.778 --> 00:08:24.028 if they've completed the game without losing too many lives. 181 00:08:24.028 --> 00:08:25.691 So getters can be useful 182 00:08:25.691 --> 00:08:27.799 and you'll want to add them sometimes, 183 00:08:27.799 --> 00:08:28.811 but the point I'm making 184 00:08:28.811 --> 00:08:30.358 is that you can add them to the class 185 00:08:30.358 --> 00:08:32.160 if you later decide you need them, 186 00:08:32.160 --> 00:08:33.789 but there's no point in creating them 187 00:08:33.789 --> 00:08:35.170 just for the sake of it 188 00:08:35.170 --> 00:08:38.160 or just because you've come to Python from another language 189 00:08:38.160 --> 00:08:39.708 where you have to use a getter 190 00:08:39.708 --> 00:08:42.239 if you think there might be the faintest possibility 191 00:08:42.239 --> 00:08:44.240 that you'll need one in the future. 192 00:08:44.240 --> 00:08:45.937 All right, so that's the getter, 193 00:08:45.937 --> 00:08:47.656 but a setter is just a method 194 00:08:47.656 --> 00:08:50.498 that's used to set the value of the class data attribute 195 00:08:50.498 --> 00:08:52.400 and it might look something like this, 196 00:08:52.400 --> 00:08:54.817 tim.set underscore lives 300. 197 00:08:58.189 --> 00:09:00.771 A setter may be useful for the lives attribute 198 00:09:00.771 --> 00:09:02.541 of our player class. 199 00:09:02.541 --> 00:09:04.520 It doesn't make sense for the number of lives 200 00:09:04.520 --> 00:09:07.970 to drop below zero so using a setter is a good way 201 00:09:07.970 --> 00:09:11.291 to check the value before updating the attribute. 202 00:09:11.291 --> 00:09:14.640 Now these two examples on line 10 and 11 203 00:09:14.640 --> 00:09:17.720 are how you would use a getter and setter in Java 204 00:09:17.720 --> 00:09:20.509 or C++ for example but in Python, 205 00:09:20.509 --> 00:09:23.221 they actually work a bit differently. 206 00:09:23.221 --> 00:09:25.221 Now the basic principle is the same, 207 00:09:25.221 --> 00:09:29.120 that is to use a method to return the value of an attribute 208 00:09:29.120 --> 00:09:30.838 or assign a new value to it, 209 00:09:30.838 --> 00:09:32.821 but you still use the same syntax 210 00:09:32.821 --> 00:09:36.388 as you would when accessing the attributes directly. 211 00:09:36.388 --> 00:09:39.138 I'm gonna delete these two lines. 212 00:09:42.485 --> 00:09:44.816 Let's go ahead and add a getter and setter 213 00:09:44.816 --> 00:09:47.776 for our lives attribute in the player class. 214 00:09:47.776 --> 00:09:50.496 All right, so going back to the player.py file, 215 00:09:50.496 --> 00:09:54.155 so the first thing we wanna do is hide our lives attribute 216 00:09:54.155 --> 00:09:56.825 by prefixing it with an underscore. 217 00:09:56.825 --> 00:09:59.035 I'm talking about the code here on line five. 218 00:09:59.035 --> 00:10:03.536 So it's gonna be self. and put an underscore there 219 00:10:03.536 --> 00:10:06.106 for underscore lives equals three. 220 00:10:06.106 --> 00:10:07.565 So once we've done that, 221 00:10:07.565 --> 00:10:11.005 we need to create a method to set the value to setter 222 00:10:11.005 --> 00:10:13.834 and of course another method to get the value to getter. 223 00:10:13.834 --> 00:10:16.536 Let's go ahead and do both of those. 224 00:10:16.536 --> 00:10:18.365 So we'll start with the getter 225 00:10:18.365 --> 00:10:22.532 so that's gonna be def space underscore get underscore lives 226 00:10:24.765 --> 00:10:28.515 self colon and return self. underscore lives. 227 00:10:32.403 --> 00:10:37.235 Then we'll do a def underscore set underscore lives 228 00:10:37.235 --> 00:10:38.525 and self in parenthesis 229 00:10:38.525 --> 00:10:40.617 which is added automatically by IntelliJ 230 00:10:40.617 --> 00:10:44.326 and then we're gonna do self. underscore lives 231 00:10:44.326 --> 00:10:45.826 is equal to lives. 232 00:10:47.385 --> 00:10:49.537 And the other thing I'll need to do here is add a parameter 233 00:10:49.537 --> 00:10:50.955 because it's the set method. 234 00:10:50.955 --> 00:10:53.857 We need to pass the number of lives we wanna set it to 235 00:10:53.857 --> 00:10:54.806 and that's it. 236 00:10:54.806 --> 00:10:56.678 Now once again, we're hiding these methods 237 00:10:56.678 --> 00:10:59.427 by starting their names with an underscore. 238 00:10:59.427 --> 00:11:01.776 Of course, they're not really hidden as such, 239 00:11:01.776 --> 00:11:04.329 but there's no need for clients to use them directly 240 00:11:04.329 --> 00:11:06.657 and the underscore at the start of the name 241 00:11:06.657 --> 00:11:09.386 gives users of our class an indication 242 00:11:09.386 --> 00:11:12.809 that they shouldn't really be calling these methods. 243 00:11:12.809 --> 00:11:14.718 Okay, so the last step now 244 00:11:14.718 --> 00:11:17.197 is to define a property called lives 245 00:11:17.197 --> 00:11:18.975 that uses these two methods 246 00:11:18.975 --> 00:11:22.089 when reading and writing our lives attribute. 247 00:11:22.089 --> 00:11:24.129 All right, so let's actually add that now. 248 00:11:24.129 --> 00:11:27.129 So we put lives is equal to property 249 00:11:29.609 --> 00:11:33.238 and it's going to be underscore get underscore lives 250 00:11:33.238 --> 00:11:34.737 without the parenthesis 251 00:11:34.737 --> 00:11:37.426 and underscore set underscore lives 252 00:11:37.426 --> 00:11:39.996 again without any parenthesis. 253 00:11:39.996 --> 00:11:43.289 So our data attribute is now called underscore lives 254 00:11:43.289 --> 00:11:46.438 and we've replaced it with a property called lives 255 00:11:46.438 --> 00:11:50.328 that uses these two methods to access the number of lives 256 00:11:50.328 --> 00:11:52.027 that the player has. 257 00:11:52.027 --> 00:11:55.655 Now back in main.py, if I go back over there, 258 00:11:55.655 --> 00:11:57.158 I can run the programme as is 259 00:11:57.158 --> 00:11:59.705 and everything should still work. 260 00:11:59.705 --> 00:12:02.129 We get the same results as we got previously. 261 00:12:02.129 --> 00:12:04.057 Tim starts off with three lives 262 00:12:04.057 --> 00:12:06.735 which we've printed out on line six. 263 00:12:06.735 --> 00:12:10.277 Then there's two left after we subtract one on line seven 264 00:12:10.277 --> 00:12:12.017 and obviously we're printing out the results of that 265 00:12:12.017 --> 00:12:13.358 on line eight. 266 00:12:13.358 --> 00:12:15.889 So I haven't actually had to make any changes 267 00:12:15.889 --> 00:12:17.455 to our main programme 268 00:12:17.455 --> 00:12:19.969 so it continues to use the player class 269 00:12:19.969 --> 00:12:21.736 in exactly the same way as it did 270 00:12:21.736 --> 00:12:24.267 before we changed the lives attribute 271 00:12:24.267 --> 00:12:26.569 to use the getter and setter methods. 272 00:12:26.569 --> 00:12:27.667 But now that we've done this, 273 00:12:27.667 --> 00:12:30.409 we can add some validation to the setter method 274 00:12:30.409 --> 00:12:33.787 to prevent the number of lives from dropping below zero. 275 00:12:33.787 --> 00:12:37.347 So going back to our player class in the setter method, 276 00:12:37.347 --> 00:12:41.257 we could add some code to do that validation 277 00:12:41.257 --> 00:12:44.297 so we could put if space lives 278 00:12:44.297 --> 00:12:47.627 is greater than or equal to zero colon 279 00:12:47.627 --> 00:12:52.147 then we'll put our self. underscore lives equals lives 280 00:12:52.147 --> 00:12:54.665 then we'll add an else clause else 281 00:12:54.665 --> 00:12:58.665 and we've got our print lives cannot be negative 282 00:13:01.337 --> 00:13:04.947 and self. underscore lives equals zero. 283 00:13:04.947 --> 00:13:06.547 All right, so that's the validation 284 00:13:06.547 --> 00:13:07.846 that only effectively allows us 285 00:13:07.846 --> 00:13:10.457 to set the value of the lives variable, 286 00:13:10.457 --> 00:13:11.965 underscore lives variable, 287 00:13:11.965 --> 00:13:15.406 if the values passed is greater than or equal to zero. 288 00:13:15.406 --> 00:13:16.926 And if that's not the case, 289 00:13:16.926 --> 00:13:19.777 then we print out the message lives cannot be negative 290 00:13:19.777 --> 00:13:22.278 and then we set underscore lives to zero. 291 00:13:22.278 --> 00:13:23.678 So while I'm here, 292 00:13:23.678 --> 00:13:25.065 I'm gonna add a method that we can use 293 00:13:25.065 --> 00:13:27.097 to print out the values of the attributes 294 00:13:27.097 --> 00:13:28.112 so let's go ahead and do that. 295 00:13:28.112 --> 00:13:31.993 We'll put that below the lives property line. 296 00:13:31.993 --> 00:13:36.160 We def space underscore underscore str underscore underscore 297 00:13:39.134 --> 00:13:41.925 and we add the self which added automatically by IntelliJ 298 00:13:41.925 --> 00:13:43.342 then let's return 299 00:13:44.443 --> 00:13:46.943 name and curly brace zero.name 300 00:13:50.306 --> 00:13:51.639 lives zero.lives 301 00:13:56.477 --> 00:13:57.810 level zero.level 302 00:14:02.048 --> 00:14:04.381 and finally score zero.score 303 00:14:06.906 --> 00:14:09.784 and at the end of that line after the double quote, 304 00:14:09.784 --> 00:14:10.867 .format self. 305 00:14:12.475 --> 00:14:13.737 So when you print an object, 306 00:14:13.737 --> 00:14:15.588 Python looks for a special method 307 00:14:15.588 --> 00:14:19.087 called underscore underscore str underscore underscore 308 00:14:19.087 --> 00:14:21.257 which we've just defined on line 21 309 00:14:21.257 --> 00:14:22.365 and I'm gonna call that method 310 00:14:22.365 --> 00:14:25.307 when it needs a string representation of the object 311 00:14:25.307 --> 00:14:27.596 such as when you wanna print it. 312 00:14:27.596 --> 00:14:29.127 Now I've created this method 313 00:14:29.127 --> 00:14:31.975 so that we can easily see the values of the attributes 314 00:14:31.975 --> 00:14:33.647 and I'll come back to that strange use 315 00:14:33.647 --> 00:14:36.148 of the replacement field shortly. 316 00:14:36.148 --> 00:14:38.867 Okay, so we've added some code to the lives setter 317 00:14:38.867 --> 00:14:41.007 to prevent the number of lives going negative 318 00:14:41.007 --> 00:14:42.315 so let's test this. 319 00:14:42.315 --> 00:14:45.127 So we're going back to the main programme 320 00:14:45.127 --> 00:14:49.497 and let's copy lines seven and eight three more times 321 00:14:49.497 --> 00:14:51.695 so I'm gonna copy those 322 00:14:51.695 --> 00:14:55.737 and let's put them outside there, there and three 323 00:14:55.737 --> 00:14:57.047 as you can see. 324 00:14:57.047 --> 00:14:59.437 So we're reducing the value of lives by one each time 325 00:14:59.437 --> 00:15:00.775 and printing out the value 326 00:15:00.775 --> 00:15:02.695 until we get down to the last value 327 00:15:02.695 --> 00:15:04.976 which hopefully is going to be hitting zero, 328 00:15:04.976 --> 00:15:06.099 but the other thing I probably should have done 329 00:15:06.099 --> 00:15:08.019 before I copied it was change this 330 00:15:08.019 --> 00:15:09.950 so instead of just printing out lives, 331 00:15:09.950 --> 00:15:12.398 it prints out just tim. 332 00:15:12.398 --> 00:15:13.279 And now that we've created 333 00:15:13.279 --> 00:15:16.047 that underscore underscore str function, 334 00:15:16.047 --> 00:15:20.327 let's take advantage of that, okay, like so. 335 00:15:20.327 --> 00:15:23.845 So let's run this now and see if it works. 336 00:15:23.845 --> 00:15:24.725 All right, so you can see there 337 00:15:24.725 --> 00:15:28.467 that we've got our lives getting reduced each time we call 338 00:15:28.467 --> 00:15:30.214 and then once it gets to below zero 339 00:15:30.214 --> 00:15:31.707 or would have gone below zero, 340 00:15:31.707 --> 00:15:34.325 we see that we got a message lives cannot be negative 341 00:15:34.325 --> 00:15:37.627 and the number of lives remains at zero. 342 00:15:37.627 --> 00:15:40.426 So although setters aren't needed as such in Python, 343 00:15:40.426 --> 00:15:43.277 they're very useful when you'd want to include validation 344 00:15:43.277 --> 00:15:47.227 on the values that your data attributes can be set to. 345 00:15:47.227 --> 00:15:48.907 All right, so I've skimmed over a couple of things 346 00:15:48.907 --> 00:15:51.546 that we've done in the player class so in the next video, 347 00:15:51.546 --> 00:15:53.947 let's have a look at those things in a bit more detail. 348 00:15:53.947 --> 00:15:56.121 I'll see you in the next video.