WEBVTT 1 00:00:01.950 --> 00:00:06.350 so just when you thought we were able to actually move on from 2 00:00:06.350 --> 00:00:10.570 blackjack but actually we got a little bit more to talk about and we are gonna use 3 00:00:10.570 --> 00:00:15.480 blackjack as this example now this is specifically talking about underscores 4 00:00:15.480 --> 00:00:19.690 in variable names now we've had a look at a few of the modules in the Python Standard 5 00:00:19.690 --> 00:00:23.500 library in previous lectures and we jumped into the source to check 6 00:00:23.500 --> 00:00:27.730 out how to use a few things and when we did that you may have noticed that many 7 00:00:27.730 --> 00:00:33.000 object names start or end with underscores or even start and end 8 00:00:33.000 --> 00:00:37.030 underscores and you might be wondering what that's all about and obviously you can 9 00:00:37.030 --> 00:00:40.370 see on line 3 we are using underscore underscore name underscore underscore now 10 00:00:40.370 --> 00:00:43.390 we've discussed ending a name with a single underscore when we looked at the 11 00:00:43.390 --> 00:00:48.170 spin box widget in the Tkinter video and you can set the range of values 12 00:00:48.170 --> 00:00:53.360 that appears in the spin box using the to and from underscore arguments but because from 13 00:00:53.360 --> 00:00:59.600 is a Python keyword we used from underscore rather than from now a convention 14 00:00:59.600 --> 00:01:04.239 is to use a single underscore after a name if it would otherwise conflict with the 15 00:01:04.239 --> 00:01:08.319 name that's built into Python so reserved a keyword in other words it's 16 00:01:08.319 --> 00:01:11.719 probably better to use a different name of course but if the name that Python 17 00:01:11.719 --> 00:01:17.020 already uses makes sense for your particular use then probably adding 18 00:01:17.020 --> 00:01:19.170 an underscore to the end of the name is the way to go 19 00:01:19.170 --> 00:01:24.030 you can do that quite easily so in the case of specifying a range of values 20 00:01:24.030 --> 00:01:27.639 from a spin box widget to and from a probably the best names to use so the 21 00:01:27.639 --> 00:01:31.679 creators of the Tkinter module uses convention adding an underscore in this 22 00:01:31.679 --> 00:01:37.109 case to the from keyword so that's the easy one out of the way now for other uses of 23 00:01:37.109 --> 00:01:38.689 underscores around 24 00:01:38.689 --> 00:01:44.299 names now unlike many other languages Python has actually got no concept of 25 00:01:44.299 --> 00:01:48.709 private or protected variables that means that it's possible to do things 26 00:01:48.709 --> 00:01:52.209 with a module that you probably shouldn't do so let's have a look at a few 27 00:01:52.209 --> 00:01:57.159 ways we can miss with our blackjack module so we've got the project open from 28 00:01:57.159 --> 00:02:01.840 the previous video we made the changes in the previous video to it so we are able to 29 00:02:01.840 --> 00:02:06.499 import it as a module and the project should now have 2 Python files as 30 00:02:06.499 --> 00:02:11.129 you can see on the screen now blackjack.py and import_test.py so 31 00:02:11.129 --> 00:02:14.510 it's useful to be able to call the play function as you can see me doing on line 32 00:02:14.510 --> 00:02:19.349 4 and also using the cards list to create decks for other games is also 33 00:02:19.349 --> 00:02:23.200 extremely useful but beyond that though their is not much else in the 34 00:02:23.200 --> 00:02:27.349 Blackjack module that really makes any sense to use once it's actually been 35 00:02:27.349 --> 00:02:32.180 imported now there is a score_hand function but that's really very specific 36 00:02:32.180 --> 00:02:36.140 to blackjack and couldn't be used to decide which of 2 poker hands are better for 37 00:02:36.140 --> 00:02:39.140 argument sake because it's a completely different algorithm 38 00:02:39.849 --> 00:02:44.220 now in Java for example only the play function and cards list would be made available to 39 00:02:44.220 --> 00:02:48.000 other programs everything else would have been marked private so that it was 40 00:02:48.000 --> 00:02:51.950 hidden and then it wouldn't actually show but as I said Python doesn't 41 00:02:51.950 --> 00:02:56.590 have any or doesn't have private objects and that means that we can do silly 42 00:02:56.590 --> 00:03:00.700 things after importing the blackjack module so we are going to start by calling the deal_cards 43 00:03:00.700 --> 00:03:04.549 function just to show you that it can be done and not suggesting it's actually 44 00:03:04.549 --> 00:03:11.920 a wise thing to do so come down here if we wanted to we could do something like.... 45 00:03:11.920 --> 00:03:21.579 ....and so let's run that just to 46 00:03:21.579 --> 00:03:26.389 confirm that it does actually work so right click this and click run to make sure 47 00:03:26.389 --> 00:03:30.720 we're running import_test and not blackjack so do that we run it and tab over and 48 00:03:30.720 --> 00:03:34.470 have a look and obviously we've got two cards now the dealer has actually got 2 49 00:03:34.470 --> 00:03:38.750 cards although at this stage due to the way we designed it only the second one 50 00:03:38.750 --> 00:03:42.900 is actually included in the dealer score and as a result that does look really 51 00:03:42.900 --> 00:03:46.370 strange and that is because we've got a total score of 13 for the dealer 52 00:03:46.370 --> 00:03:50.099 but only the second one is calculated again this is an ideal basically 53 00:03:50.099 --> 00:03:56.019 giving access to areas of the game that we wouldn't ordinarily want someone 54 00:03:56.019 --> 00:04:00.069 who's imported this blackjack module to be able to access our code that way because it's 55 00:04:00.069 --> 00:04:03.590 sort of breaking the game as such this is compounded by the fact there's really 56 00:04:03.590 --> 00:04:07.109 nothing to indicate that we shouldn't be calling this function so from that 57 00:04:07.109 --> 00:04:11.889 perspective of someone who's imported the blackjack module and is wanting to use 58 00:04:11.889 --> 00:04:15.250 it their's no clear indication that you know maybe I shouldn't be actually calling 59 00:04:15.250 --> 00:04:19.780 this method here and obviously by calling and then by trial and error 60 00:04:19.780 --> 00:04:23.020 and running through and testing it and seeing that it doesn't work they will eventually figure 61 00:04:23.020 --> 00:04:25.970 it out but there's no easy way to know ahead of time if 62 00:04:25.970 --> 00:04:33.290 that's the case by convention starting a name with an underscore indicates 63 00:04:33.290 --> 00:04:37.050 that it should be treated as protected which means it's not intended to be 64 00:04:37.050 --> 00:04:41.870 used outside the modules existence so it's really a standard in Python now theirs a 65 00:04:41.870 --> 00:04:45.580 little bit more to that when using classes and we'll talk about that in the 66 00:04:45.580 --> 00:04:49.770 next section when we start object oriented programming but if we go back into the 67 00:04:49.770 --> 00:04:50.830 blackjack module 68 00:04:50.830 --> 00:04:55.540 we can actually refactor the deal_card function so that it's called _deal_ 69 00:04:55.540 --> 00:05:05.090 card so we go back their go to our deal card and if I refactor that right 70 00:05:05.090 --> 00:05:18.320 click it refactor rename and put an underscore in front of it and refactor it...that should 71 00:05:18.320 --> 00:05:21.690 have changed everywhere even here 72 00:05:21.690 --> 00:05:26.480 back in the import_test.py but notice what happened now IntelliJ has actually come 73 00:05:26.480 --> 00:05:30.970 up and help us now its access to a protected member_deal_ 74 00:05:30.970 --> 00:05:36.050 card of a module so we are now correctly getting a warning that this is 75 00:05:36.050 --> 00:05:41.860 a protected member in so much as far as Python is actually concerned so their is still 76 00:05:41.860 --> 00:05:45.020 nothing preventing the access just wanna make that clear we can still run it and 77 00:05:45.020 --> 00:05:51.950 if we do run it the game still actually work so unlike Java or another programming language 78 00:05:51.950 --> 00:05:55.410 where once we set it to like private or protected we can actually restrict the 79 00:05:55.410 --> 00:06:00.320 uses here we can't do that so it's still gonna work but you do get a warning 80 00:06:00.320 --> 00:06:04.380 that it's quite prominent its not just a little warning on the right hand side its actually 81 00:06:04.380 --> 00:06:05.990 underscoring 82 00:06:05.990 --> 00:06:09.260 you know the little underscore on the actual method name we are trying to access which will hopefully 83 00:06:09.260 --> 00:06:14.810 get you to look at and think what have I done wrong here so if you find yourself using an object 84 00:06:14.810 --> 00:06:18.760 whos name starts with an underscore now bear in mind that you probably shouldn't 85 00:06:18.760 --> 00:06:25.740 be doing that the developer of the module has defined it that way for you probably not 86 00:06:25.740 --> 00:06:29.290 to access it that way of course if the object is in your own code then you 87 00:06:29.290 --> 00:06:33.470 probably know what you doing then its ok but just be very careful if it existed 88 00:06:33.470 --> 00:06:35.090 in a module that you didn't actually write 89 00:06:35.090 --> 00:06:39.240 yourself and as you can see IntelliJ is aware of this convention and provides us 90 00:06:39.240 --> 00:06:42.780 with this very useful warning so that at least we are aware of what 91 00:06:42.780 --> 00:06:46.620 we're actually doing so just close it down because there is actually another 92 00:06:46.620 --> 00:06:52.740 implication of using underscored at the start of a name so if your using 93 00:06:52.740 --> 00:06:56.340 alternate way of importing blackjack anything whose name starts with an 94 00:06:56.340 --> 00:07:00.160 underscore is not actually imported now we've recommended before that you 95 00:07:00.160 --> 00:07:03.729 don't do an import* from a module because all of the names from the 96 00:07:03.729 --> 00:07:07.500 imported modules then have become part of your modules namespace and it's then very 97 00:07:07.500 --> 00:07:12.260 easy to lose track of what names belong to what because the way we imported blackjack 98 00:07:12.260 --> 00:07:16.700 we need to use blackjack. to access any of the Blackjack objects which makes it 99 00:07:16.700 --> 00:07:21.220 very obvious that we're actually dealing with code that's part of blackjack 100 00:07:21.220 --> 00:07:24.460 and you can see on lines 5 and 6 we are actually inputting the . their to 101 00:07:24.460 --> 00:07:27.780 access that blackjack specific functionality so we can now 102 00:07:27.780 --> 00:07:32.389 look at the difference in more detail so what we are gonna do is comment out all this 103 00:07:32.389 --> 00:07:39.150 code for now just leave the import in we are gonna have a look at what's in global so I want 104 00:07:39.150 --> 00:07:42.610 to list all the names separately rather than in one long line that we get if 105 00:07:42.610 --> 00:07:47.539 we just used print globals which have used previously so gonna create a 106 00:07:47.539 --> 00:07:57.250 loop here so... 107 00:07:57.250 --> 00:08:04.470 ...so if we run this but we get an error straightaway so x is meant to 108 00:08:04.470 --> 00:08:08.240 iterate through all the keys in the dictionary but as soon as we've used X the 109 00:08:08.240 --> 00:08:11.510 dictionary changes and Python gives us an error so this code does not actually work 110 00:08:11.510 --> 00:08:15.650 because obviously we knew very well that we defined that has actually altered the 111 00:08:15.650 --> 00:08:20.849 dictionary itself so we can't actually access the the globals that why so one quick way 112 00:08:20.849 --> 00:08:24.820 around this is to take a copy of the globals dictionary then iterate through that 113 00:08:24.820 --> 00:08:30.150 so that means we won't see our variable X in that list but as a quick way to make a 114 00:08:30.150 --> 00:08:33.630 copy is to use the sorted function then the actual code has the added advantage 115 00:08:33.630 --> 00:08:38.810 of producing a sorted list so let's go ahead and do that so..... 116 00:08:38.810 --> 00:08:40.130 .... 117 00:08:40.130 --> 00:08:51.430 .....so that way 118 00:08:51.430 --> 00:08:55.320 there's nothing being added to the dictionary when we go to iterate 119 00:08:55.320 --> 00:08:59.690 through G and we should find that it actually works without an error so 120 00:08:59.690 --> 00:09:06.130 if we run this this time it actually has worked so the list itself is pretty 121 00:09:06.130 --> 00:09:09.770 small and a part from a few things underscore before and after their names 122 00:09:09.770 --> 00:09:13.740 the only object that's present in here is blackjack which of course we 123 00:09:13.740 --> 00:09:17.900 imported on line 1 but let's just change the import and see what happens if we 124 00:09:17.900 --> 00:09:19.410 added a start so... 125 00:09:19.410 --> 00:09:22.410 ..... 126 00:09:23.120 --> 00:09:35.000 ...we do it that way and we run it....you can see we got a completely 127 00:09:35.000 --> 00:09:39.700 different result but all our functions as you can see and the variables are 128 00:09:39.700 --> 00:09:44.120 showing up basically everything from the blackjacks module namespace now appears 129 00:09:44.120 --> 00:09:48.690 in our modules namespace so if we created an object called cards for 130 00:09:48.690 --> 00:09:53.090 example then the blackjack modules card would no longer be available so I said 131 00:09:53.090 --> 00:09:57.100 that everything from the blackjacks module namespace is imported but to be 132 00:09:57.100 --> 00:10:00.560 precise that's not strictly true for example there's no assign there if you have a 133 00:10:00.560 --> 00:10:05.000 look at the screen of our _deal_card function and if we 134 00:10:05.000 --> 00:10:19.760 try and use it now we actually get an error so if we try and do that....and we got an error their unresolved 135 00:10:19.760 --> 00:10:24.670 reference so the Python import mechanism does actually take note of 136 00:10:24.670 --> 00:10:27.880 this convention and it won't import any objects that start with an underscore 137 00:10:27.880 --> 00:10:33.440 when you import star now when we import blackjack the objects from the 138 00:10:33.440 --> 00:10:37.870 blackjack module aren't imported separately so everything even names beginning with 139 00:10:37.870 --> 00:10:41.950 underscores are available by the prefixing them with blackjack. so we 140 00:10:41.950 --> 00:10:44.720 put the import back as to what it was like before 141 00:10:44.720 --> 00:10:50.700 ....that's not gonna work because it's an unresolved reference but we 142 00:10:50.700 --> 00:10:53.030 go back and put blackjack in front of it 143 00:10:53.030 --> 00:10:57.970 to tell Python that it's the Blackjack module we are dealing with it and 144 00:10:57.970 --> 00:11:06.460 for the frame....the error goes away and we are good to go we still get a warning here 145 00:11:06.460 --> 00:11:12.950 from IntelliJ telling us that its accessing a protected member but it does work again now lets get rid 146 00:11:12.950 --> 00:11:28.140 of this code......our app is running again all being with two cards again with 147 00:11:28.140 --> 00:11:33.470 only one being scored so using a double underscores at the start of a name invokes 148 00:11:33.470 --> 00:11:38.450 Python's name mangling rules so this convention really exists to prevent name 149 00:11:38.450 --> 00:11:42.780 clashes when subclassing objects and again we'll look at this in more detail 150 00:11:42.780 --> 00:11:47.420 in the next section when we start dealing with object oriented programming but in a 151 00:11:47.420 --> 00:11:51.740 blackjack module two underscore would really serve no useful purpose but of 152 00:11:51.740 --> 00:11:56.450 course anything that starts with two underscores automatically also starts with one so 153 00:11:56.450 --> 00:12:00.730 import* wouldn't actually import them now the final underscore naming 154 00:12:00.730 --> 00:12:05.450 convention to discuss here is names that start and end with two underscores now 155 00:12:05.450 --> 00:12:09.450 basically things that you shouldn't be changing now we've seen just 156 00:12:09.450 --> 00:12:14.230 deleted it __name__ and use it to restrict the code 157 00:12:14.230 --> 00:12:17.820 that was executed when our module was imported so it should be obvious from 158 00:12:17.820 --> 00:12:22.920 the example that changing the value of the __name__ isn't a 159 00:12:22.920 --> 00:12:28.280 good idea so of course I will just go ahed and do just that now to show you what happens the 160 00:12:28.280 --> 00:12:32.090 same is generally true of anything that's name with double underscores that 161 00:12:32.090 --> 00:12:37.330 at the start and end they can be useful to use but they should never be change so we are gonna go ahead 162 00:12:37.330 --> 00:12:47.910 now to our code and make sure that it's set correctly and I'll actually get rid of this code their....so now we've got our import we got our blackjack deal_card and blackjack.py 163 00:12:47.910 --> 00:12:52.330 so we are ready to go with that so we tested that will just test one more time to make 164 00:12:52.330 --> 00:13:00.400 sure that it does work obviously our app is working nicely so that is good and of course we're 165 00:13:00.400 --> 00:13:03.860 getting two cards because we're using line 3 calling that method when we 166 00:13:03.860 --> 00:13:07.480 shouldn't be doing that so next what we gonna do is we are going to break things by 167 00:13:07.480 --> 00:13:14.960 changing the value of name the __name__ in blackjack.py so we are going to their and close this run window down 168 00:13:15.790 --> 00:13:25.240 just below the play method what I'm going to do is change this variables so... 169 00:13:25.240 --> 00:13:37.300 .... 170 00:13:37.300 --> 00:13:39.570 so obviously this is something you shouldn't be doing good just making the 171 00:13:39.570 --> 00:13:43.760 point that these two underscores at the start and end of the variable names is something 172 00:13:43.760 --> 00:13:47.580 is Python way of saying you should never change this but we are just doing this to see what 173 00:13:47.580 --> 00:13:48.570 happens 174 00:13:48.570 --> 00:13:56.090 if we run our import_test and have a look so you can see that the 175 00:13:56.090 --> 00:14:02.780 game starts up fine but notice that the dealers has got only one card so the code 176 00:14:02.780 --> 00:14:06.620 the import_test hasn't yet executed and that this is the original 177 00:14:06.620 --> 00:14:10.900 effect that we saw when we first imported blackjack because __name__ 178 00:14:10.900 --> 00:14:15.390 has been set to main or the __name__ 179 00:14:15.390 --> 00:14:18.390 I'm talking about this code 180 00:14:19.340 --> 00:14:24.460 code we added to line 125 because we change that the test that restricts code execution 181 00:14:24.460 --> 00:14:28.130 on import is no longer valid and the code runs when we import the module 182 00:14:28.130 --> 00:14:36.920 so then if we actually get back to our code and close this we then get an error because 183 00:14:36.920 --> 00:14:40.600 by closing the window we've destroyed all the TKinter objects so that nothing 184 00:14:40.600 --> 00:14:47.020 works and the game cannot be played by calling the play function so Python doesn't prevent you 185 00:14:47.020 --> 00:14:50.330 as such from modify these variables but if you do so then the results are 186 00:14:50.330 --> 00:14:54.160 undefined and you can run into all sorts of problems like I just introduced 187 00:14:54.160 --> 00:14:59.890 to you the only thing you can be reasonably sure of is that their is something that is going to break so before 188 00:14:59.890 --> 00:15:03.230 moving on i'm just gonna remove this offending line again because that shouldn't be 189 00:15:03.230 --> 00:15:10.770 in their deleted that like so close this run window so we just about done here and what I'm going to 190 00:15:10.770 --> 00:15:15.160 leave you with now is one more use of the underscore that will quickly go 191 00:15:15.160 --> 00:15:20.060 through so a variable that's just name_ with nothing else indicates 192 00:15:20.060 --> 00:15:25.820 a throwaway value so underscore by itself is a valid variable name and 193 00:15:25.820 --> 00:15:26.380 rather than 194 00:15:26.380 --> 00:15:29.410 thinking of a name for something that's not gonna be used the convention is to 195 00:15:29.410 --> 00:15:32.410 call it either that underscore or underscore underscore 196 00:15:32.960 --> 00:15:37.650 so examples of things that you might have to access but are not going to use include 197 00:15:37.650 --> 00:15:40.770 tuples we want to use some of the values of a tuple but not all of them 198 00:15:40.770 --> 00:15:46.100 let's just write a simple code I'm just going to comment out blackjack for now and put it below that 199 00:15:46.100 --> 00:15:51.000 and will put..... 200 00:15:51.000 --> 00:16:09.970 .... 201 00:16:09.970 --> 00:16:11.180 ... 202 00:16:11.180 --> 00:16:18.310 .....so as we saw in the tuples video at the start of this course you can 203 00:16:18.310 --> 00:16:22.400 assign all the values of a tuple to a variables using a single assignment that 204 00:16:22.400 --> 00:16:27.320 I have actually done here on line 8 but this code isn't really 205 00:16:27.320 --> 00:16:32.030 interested in my age just my name and country and so I've put an underscore 206 00:16:32.030 --> 00:16:38.020 where the age would actually be now we could actually add another line to print the age if we wanted to 207 00:16:38.020 --> 00:16:44.430 so....and that would still quite happily work run it to make sure it 208 00:16:44.430 --> 00:16:45.130 does work 209 00:16:45.130 --> 00:16:51.190 Tim Australia and 24 so it is working but the point here is that it's just a 210 00:16:51.190 --> 00:16:56.390 way for you to name something as a throwaway value that you know that you 211 00:16:56.390 --> 00:17:00.410 are not gonna be using for the rest of your programs obviously in the case of the age which 212 00:17:00.410 --> 00:17:05.709 was just a second part their that is set to 24 currently if we actually gonna use the value then 213 00:17:05.709 --> 00:17:09.829 you probably give it a better name than the underscore so the single underscore 214 00:17:09.829 --> 00:17:13.540 or 2 underscores as variable names are used when you would not be doing 215 00:17:13.540 --> 00:17:17.569 anything else with the value but you have to specify the variable ok so 216 00:17:17.569 --> 00:17:20.360 that's it I'm gonna finish here now and I'll see you in the next video