1 00:00:00,000 --> 00:00:03,472 [MUSIC PLAYING] 2 00:00:03,472 --> 00:00:23,808 3 00:00:23,808 --> 00:00:27,290 DAVID MALAN: All right, this is CS50, Introduction 4 00:00:27,290 --> 00:00:28,610 to Programming with Python. 5 00:00:28,610 --> 00:00:31,640 My name is David Malan, and this is our week on library. 6 00:00:31,640 --> 00:00:35,540 So libraries are generally files of code that other people 7 00:00:35,540 --> 00:00:39,315 have written that you can use in your own programs or a library's code 8 00:00:39,315 --> 00:00:41,690 that you've written that you can use in your own program, 9 00:00:41,690 --> 00:00:45,120 but maybe not just this program, but another and another as well. 10 00:00:45,120 --> 00:00:47,630 So Python supports exactly this idea. 11 00:00:47,630 --> 00:00:51,860 This ability to share code with others, share code across your own projects. 12 00:00:51,860 --> 00:00:54,320 And it does so by way of what it calls module. 13 00:00:54,320 --> 00:00:57,080 A module in Python is just a library that 14 00:00:57,080 --> 00:01:01,400 typically has one or more functions or other features built into it. 15 00:01:01,400 --> 00:01:03,860 Generally, the purpose of a library or a module 16 00:01:03,860 --> 00:01:06,860 specifically is to encourage reusability of code 17 00:01:06,860 --> 00:01:10,730 if you find yourself using the same types of functions again and again, 18 00:01:10,730 --> 00:01:11,900 the same functionality. 19 00:01:11,900 --> 00:01:15,800 If you find yourself copying and pasting from an old project 20 00:01:15,800 --> 00:01:20,090 into your new project, odds are there's an opportunity there to factor out 21 00:01:20,090 --> 00:01:24,080 that code that you keep copying and pasting that you keep reusing and put 22 00:01:24,080 --> 00:01:28,530 it into a library that you can then load into your programs moving forward 23 00:01:28,530 --> 00:01:30,440 so as to not just copy and paste it and have 24 00:01:30,440 --> 00:01:32,430 all these different copies all over. 25 00:01:32,430 --> 00:01:36,140 So what are some of the modules or libraries that Python comes with? 26 00:01:36,140 --> 00:01:39,200 Well, Python comes with a random library literally, 27 00:01:39,200 --> 00:01:41,600 which is to say that when you install the Python 28 00:01:41,600 --> 00:01:44,030 interpreter on your Mac or PC or somewhere 29 00:01:44,030 --> 00:01:46,070 in the cloud, not only do you get Python, 30 00:01:46,070 --> 00:01:48,390 you get a whole bunch of modules as well. 31 00:01:48,390 --> 00:01:50,570 Now, these modules provide you with functions 32 00:01:50,570 --> 00:01:54,770 that you don't have access to just by default like you do print and input. 33 00:01:54,770 --> 00:01:58,370 Print and input and other such functions just work in Python. 34 00:01:58,370 --> 00:02:02,250 But sometimes functions are tucked away in these modules, 35 00:02:02,250 --> 00:02:04,490 so you have to be more deliberate about loading them 36 00:02:04,490 --> 00:02:06,000 into the computer's memory. 37 00:02:06,000 --> 00:02:09,289 So somewhere on the computer's hard drive, once you've installed Python, 38 00:02:09,289 --> 00:02:13,820 there is also, it turns out a file, probably called random.py 39 00:02:13,820 --> 00:02:17,700 that someone else wrote probably long ago but that you have access to. 40 00:02:17,700 --> 00:02:20,930 And in that random.py file, there's probably one or more functions 41 00:02:20,930 --> 00:02:25,190 that you yourself can use in order to do things randomly. 42 00:02:25,190 --> 00:02:29,120 That is to say how could you flip a coin in a program in Python? 43 00:02:29,120 --> 00:02:33,062 How could you pick a random number between 1 and 10 in Python? 44 00:02:33,062 --> 00:02:34,520 Well, you need a bit of randomness. 45 00:02:34,520 --> 00:02:37,130 And while you could figure out mathematically 46 00:02:37,130 --> 00:02:39,440 how to write functions like that yourself, 47 00:02:39,440 --> 00:02:42,590 it's a lot easier to stand on the shoulders of others who've already 48 00:02:42,590 --> 00:02:45,620 solved that problem for you so you can focus on the problem 49 00:02:45,620 --> 00:02:48,030 that you yourself want to solve. 50 00:02:48,030 --> 00:02:51,260 So for documentation on most any Python module, 51 00:02:51,260 --> 00:02:52,970 you go to the official Python docs. 52 00:02:52,970 --> 00:02:57,080 And you go to a URL like this where the documentation for that specific module 53 00:02:57,080 --> 00:02:57,650 lives. 54 00:02:57,650 --> 00:02:59,810 And within the documentation, you'll see a list 55 00:02:59,810 --> 00:03:03,260 of the functions or other functionality that some module provide. 56 00:03:03,260 --> 00:03:08,060 But how do you go about loading a module into your own program 57 00:03:08,060 --> 00:03:10,580 so that you can use the functions in that module? 58 00:03:10,580 --> 00:03:14,450 Well, we need a new keyword in Python and namely it's import. 59 00:03:14,450 --> 00:03:20,690 The import keyword in Python allows you to import the contents of the functions 60 00:03:20,690 --> 00:03:23,660 from some module in Python. 61 00:03:23,660 --> 00:03:26,190 Well, how might I go about using this in practice? 62 00:03:26,190 --> 00:03:29,750 Well, let me propose that there exists in that random module 63 00:03:29,750 --> 00:03:31,440 this function among others. 64 00:03:31,440 --> 00:03:34,430 So I have copied and pasted from the documentation 65 00:03:34,430 --> 00:03:38,120 this summary of a function called Choice. 66 00:03:38,120 --> 00:03:42,620 Now, the function exists in the random module, so to speak, 67 00:03:42,620 --> 00:03:45,780 not a random module, the random module. 68 00:03:45,780 --> 00:03:48,800 And so generally the documentation describes it fully like this. 69 00:03:48,800 --> 00:03:52,485 random.choice is how you would technically call this function, 70 00:03:52,485 --> 00:03:54,110 though, we'll see alternatives to that. 71 00:03:54,110 --> 00:03:58,310 In parentheses, there is a parameter called S-E-Q for sequence. 72 00:03:58,310 --> 00:04:01,250 And sequence generally means a list or something 73 00:04:01,250 --> 00:04:05,370 that is list-like if you have a list of numbers or strings or anything else. 74 00:04:05,370 --> 00:04:06,920 And the documentation elaborate. 75 00:04:06,920 --> 00:04:09,980 Well, how can I go about using this function to solve, perhaps, 76 00:04:09,980 --> 00:04:11,150 a familiar problem? 77 00:04:11,150 --> 00:04:13,340 Well, let me go ahead and open up VS Code here. 78 00:04:13,340 --> 00:04:17,779 And let me propose that we implement a program that simulates flipping a coin. 79 00:04:17,779 --> 00:04:21,890 A coin that in the US has heads or tails, the idea of which 80 00:04:21,890 --> 00:04:25,520 is to pick a decision with 50/50 probability. 81 00:04:25,520 --> 00:04:29,420 50% probability of heads, 50% probability of tails. 82 00:04:29,420 --> 00:04:31,460 Or you can use some other mechanism like that. 83 00:04:31,460 --> 00:04:35,930 Well, let me go ahead and open a program with code called generate.py 84 00:04:35,930 --> 00:04:39,115 because I want to start generating a whole bunch of random information. 85 00:04:39,115 --> 00:04:41,240 The first of which is just going to be a coin toss. 86 00:04:41,240 --> 00:04:43,700 Now, how do I go about using that function? 87 00:04:43,700 --> 00:04:46,880 Well, I first have to import the random library. 88 00:04:46,880 --> 00:04:49,520 So literally the first or among the first lines of my file 89 00:04:49,520 --> 00:04:51,500 should be import random. 90 00:04:51,500 --> 00:04:56,160 And that just gives me access to all of the functions in that specific module. 91 00:04:56,160 --> 00:04:58,950 Now, suppose I want to flip a coin. 92 00:04:58,950 --> 00:05:03,380 Well, I can do random.choice per the documentation a moment ago. 93 00:05:03,380 --> 00:05:05,090 And that again takes a sequence. 94 00:05:05,090 --> 00:05:05,840 What's a sequence? 95 00:05:05,840 --> 00:05:07,700 It's a list or something that's list-like. 96 00:05:07,700 --> 00:05:08,930 And we know about lists. 97 00:05:08,930 --> 00:05:11,090 We've used lists to iterate over numbers. 98 00:05:11,090 --> 00:05:13,460 We've used lists to iterate over students at Hogwarts. 99 00:05:13,460 --> 00:05:18,200 Let's go ahead now and iterate over just a list of two sides of a coin, 100 00:05:18,200 --> 00:05:20,690 "heads," quote, unquote, or tails. 101 00:05:20,690 --> 00:05:22,400 Now, I could call these anything I want. 102 00:05:22,400 --> 00:05:23,690 These are my string. 103 00:05:23,690 --> 00:05:25,860 I just want to simulate a tossing a coin. 104 00:05:25,860 --> 00:05:28,670 So I'm just going to say in all lowercase, heads and tail. 105 00:05:28,670 --> 00:05:30,080 But notice the syntax. 106 00:05:30,080 --> 00:05:32,058 I have "heads" and "tails" in double quotes. 107 00:05:32,058 --> 00:05:33,350 That's because they're strings. 108 00:05:33,350 --> 00:05:36,000 I could also use single quotes so long as I'm consistent. 109 00:05:36,000 --> 00:05:38,900 There's a comma between them, which means the list has two elements. 110 00:05:38,900 --> 00:05:42,410 They're square brackets to the right and the left, which 111 00:05:42,410 --> 00:05:44,450 indicates that this is indeed a list. 112 00:05:44,450 --> 00:05:47,508 That's the syntax recall for defining a list in Python. 113 00:05:47,508 --> 00:05:49,550 And then lastly, there's something more familiar. 114 00:05:49,550 --> 00:05:52,280 There's the parentheses outside of those square brackets. 115 00:05:52,280 --> 00:05:55,550 But those are just the parentheses that belong to the Choice function 116 00:05:55,550 --> 00:05:58,980 and specify where its parameter gets passed in. 117 00:05:58,980 --> 00:06:03,740 But again, unlike past function, I have to specify what module 118 00:06:03,740 --> 00:06:05,610 this function is in at least for now. 119 00:06:05,610 --> 00:06:09,440 And so I do random.choice to call the specific function. 120 00:06:09,440 --> 00:06:12,620 All right, well, it's one thing to flip a coin picking between those 121 00:06:12,620 --> 00:06:14,310 with 50% probability. 122 00:06:14,310 --> 00:06:15,980 And that's what random.choice does. 123 00:06:15,980 --> 00:06:19,910 It takes in a list, and it returns to one of those values randomly 124 00:06:19,910 --> 00:06:21,290 with equal probability. 125 00:06:21,290 --> 00:06:24,080 Because I've passed in two items, I've got a 50/50 chance. 126 00:06:24,080 --> 00:06:28,500 If I passed in three items, it'd be a 33% chance for each of those items 127 00:06:28,500 --> 00:06:29,090 and so forth. 128 00:06:29,090 --> 00:06:30,740 Python does the math for you. 129 00:06:30,740 --> 00:06:33,270 But I want to store the value of this in a variable. 130 00:06:33,270 --> 00:06:37,310 So let's define a variable called coin equals whatever the return value is. 131 00:06:37,310 --> 00:06:39,380 So this is indeed like flipping a coin. 132 00:06:39,380 --> 00:06:42,320 I'm going to store in a variable called coin, whatever 133 00:06:42,320 --> 00:06:43,700 that value is, heads or tails. 134 00:06:43,700 --> 00:06:46,280 And now, just so I can see what's going on, let's go ahead 135 00:06:46,280 --> 00:06:49,430 and print out the value of that string coin 136 00:06:49,430 --> 00:06:52,520 All right, let me go ahead now and run this program in my terminal window. 137 00:06:52,520 --> 00:06:55,700 Python of generate.py, Enter. 138 00:06:55,700 --> 00:06:58,340 And it looks like the first coin toss was the heads. 139 00:06:58,340 --> 00:07:00,500 Let's go ahead and run it again. 140 00:07:00,500 --> 00:07:02,128 And it looks like it was heads again. 141 00:07:02,128 --> 00:07:03,920 Maybe you want to chime into the chat here. 142 00:07:03,920 --> 00:07:06,560 If I run it a third time, what's it going to be this time? 143 00:07:06,560 --> 00:07:10,020 If you want to type your thoughts in the chat, 144 00:07:10,020 --> 00:07:11,670 you might think there's a bug here. 145 00:07:11,670 --> 00:07:14,220 But this is probability in action. 146 00:07:14,220 --> 00:07:16,830 If I go ahead and hit Enter a third time there, 147 00:07:16,830 --> 00:07:21,120 it's actually now tails And again, tails and again tails and again tails 148 00:07:21,120 --> 00:07:23,460 and again tails and again heads. 149 00:07:23,460 --> 00:07:25,740 Now, if we did this an infinite number of times, 150 00:07:25,740 --> 00:07:27,750 it would indeed work out to be 50/50. 151 00:07:27,750 --> 00:07:31,110 If we only do it a few times, it might not work out as cleanly. 152 00:07:31,110 --> 00:07:33,360 But that's how probabilities indeed work. 153 00:07:33,360 --> 00:07:35,760 All right, so I've got that now working. 154 00:07:35,760 --> 00:07:37,810 Could I have implemented this in a different way? 155 00:07:37,810 --> 00:07:42,600 Well, let me show you an alternative to actually using the import keyword alone 156 00:07:42,600 --> 00:07:45,480 and let me introduce the keyword from in Python. 157 00:07:45,480 --> 00:07:50,490 So from is a keyword in Python that you can use when importing functions 158 00:07:50,490 --> 00:07:55,180 from a module, but it allows you to be a little more specific than import alone. 159 00:07:55,180 --> 00:07:57,240 So if I go back to my code here, it's worth 160 00:07:57,240 --> 00:08:01,260 noting that what technically I'm doing here by importing random 161 00:08:01,260 --> 00:08:04,920 is I'm technically importing everything that's in that module. 162 00:08:04,920 --> 00:08:09,570 So not just the function called random.choice but a few other functions 163 00:08:09,570 --> 00:08:10,240 as well. 164 00:08:10,240 --> 00:08:12,870 So instead of using this line of code at the top of my file, 165 00:08:12,870 --> 00:08:15,240 import random, which will technically give me access 166 00:08:15,240 --> 00:08:18,510 to all of the contents they're in, a downside of that 167 00:08:18,510 --> 00:08:22,050 is that I have to type in random.choice, random.this, 168 00:08:22,050 --> 00:08:24,960 random.that because all of the functions I'm calling 169 00:08:24,960 --> 00:08:28,030 have to be associated with the scope of that module. 170 00:08:28,030 --> 00:08:31,530 Well, suppose that I just want to call the function as its name, choice. 171 00:08:31,530 --> 00:08:32,730 I can do that as well. 172 00:08:32,730 --> 00:08:37,799 Let me replace this first line here with from random import choice. 173 00:08:37,799 --> 00:08:42,179 And what this does effectively is it loads the function's name choice 174 00:08:42,179 --> 00:08:47,050 into my current namespace into the scope of the file I'm working in. 175 00:08:47,050 --> 00:08:50,670 What that means is that I now no longer have to specify 176 00:08:50,670 --> 00:08:52,420 which choice function I mean. 177 00:08:52,420 --> 00:08:53,770 I can just say choice. 178 00:08:53,770 --> 00:08:56,220 And so it loads it into the local namespace 179 00:08:56,220 --> 00:09:00,510 that is into my local vocabulary, if you will, so I can just now say choice. 180 00:09:00,510 --> 00:09:05,070 This might be advantageous in what cases, do you think? 181 00:09:05,070 --> 00:09:10,170 When might you want to import the name of the function explicitly like this 182 00:09:10,170 --> 00:09:12,660 as opposed to just saying random.choice-- 183 00:09:12,660 --> 00:09:16,470 random.choice throughout your code when calling a function? 184 00:09:16,470 --> 00:09:21,675 Any instincts here for this alternative import using from? 185 00:09:21,675 --> 00:09:23,940 AUDIENCE: Hello, I'm Mohammed Omar from Egypt. 186 00:09:23,940 --> 00:09:29,340 And maybe if we have a variable that its name is basically like choice 187 00:09:29,340 --> 00:09:30,990 if I have a variable called the choice. 188 00:09:30,990 --> 00:09:33,760 So I need to differentiate which trays I choose. 189 00:09:33,760 --> 00:09:36,302 So I'm going to choose random data choice. 190 00:09:36,302 --> 00:09:38,010 DAVID MALAN: Yeah, really good instincts. 191 00:09:38,010 --> 00:09:40,710 By using the first approach by just importing random, 192 00:09:40,710 --> 00:09:42,900 you're making sure that all of its contents 193 00:09:42,900 --> 00:09:46,680 are associated with or scoped to the random module 194 00:09:46,680 --> 00:09:49,320 so that you can have your own choice function. 195 00:09:49,320 --> 00:09:51,150 You can have your own choice variable. 196 00:09:51,150 --> 00:09:54,870 You can use the same names as all of the functions or variables that 197 00:09:54,870 --> 00:09:58,328 are stored inside of that file without them colliding, so to speak. 198 00:09:58,328 --> 00:09:59,370 And this is a good thing. 199 00:09:59,370 --> 00:10:03,150 In older languages, it was the case that if you imported someone's library, 200 00:10:03,150 --> 00:10:05,790 you better hope that you're not using the same functions 201 00:10:05,790 --> 00:10:08,070 or variables as they are because you might 202 00:10:08,070 --> 00:10:09,750 in fact have some kind of conflict. 203 00:10:09,750 --> 00:10:11,940 Python and certain other languages allow you 204 00:10:11,940 --> 00:10:16,007 to scope the names of those functions and variables to the file or the module 205 00:10:16,007 --> 00:10:16,840 that they come from. 206 00:10:16,840 --> 00:10:17,850 So that's a good thing. 207 00:10:17,850 --> 00:10:20,640 But honestly, this is such a short program. 208 00:10:20,640 --> 00:10:23,850 Or equivalently, maybe I'm using the choice function 209 00:10:23,850 --> 00:10:28,530 in so many places calling random.choice, random.choice, random.choice. 210 00:10:28,530 --> 00:10:31,230 It's just making my code longer and longer and longer. 211 00:10:31,230 --> 00:10:34,260 Marginally so, but hey, just getting ugly and annoying, 212 00:10:34,260 --> 00:10:38,380 I can simply import choice and now tighten up my code a little bit. 213 00:10:38,380 --> 00:10:40,440 So as with so many decisions in the past, 214 00:10:40,440 --> 00:10:43,260 there's not necessarily one right approach or another. 215 00:10:43,260 --> 00:10:43,860 It depends. 216 00:10:43,860 --> 00:10:45,780 But I think for those very reasons, sometimes 217 00:10:45,780 --> 00:10:48,090 it's better to do what we did the first time, which 218 00:10:48,090 --> 00:10:52,980 is only import the module so as to retain the scope therein. 219 00:10:52,980 --> 00:10:55,740 Well, let me propose that we transition to another function that 220 00:10:55,740 --> 00:10:57,910 comes with Python's random module. 221 00:10:57,910 --> 00:11:01,200 And that's this here from the documentation randint. 222 00:11:01,200 --> 00:11:04,410 It's a bit hard to say, but it implies get back a random int. 223 00:11:04,410 --> 00:11:08,640 And if you read the documentation, it's a random int that's between A and B 224 00:11:08,640 --> 00:11:09,760 inclusive. 225 00:11:09,760 --> 00:11:12,990 So if you were to pass in 1 for A and 10 for B, 226 00:11:12,990 --> 00:11:17,160 you would get back a number between 1 and 10 inclusive, including the 1 227 00:11:17,160 --> 00:11:18,780 and including the 10 potentially. 228 00:11:18,780 --> 00:11:21,040 Each with a 10% probability. 229 00:11:21,040 --> 00:11:23,520 So how might I go about using a program like this? 230 00:11:23,520 --> 00:11:26,160 Well, let me come back to my generate the py file. 231 00:11:26,160 --> 00:11:28,200 And why don't we go ahead and try generating 232 00:11:28,200 --> 00:11:29,760 a random number between 1 and 10? 233 00:11:29,760 --> 00:11:31,350 You might do this frequently in the real world. 234 00:11:31,350 --> 00:11:32,910 When you just want someone to pick a random number, 235 00:11:32,910 --> 00:11:34,770 you tell them as much in the human response. 236 00:11:34,770 --> 00:11:37,020 Let's get the computer to do the same here. 237 00:11:37,020 --> 00:11:39,900 Let me go ahead and delete my two lines of code at the bottom 238 00:11:39,900 --> 00:11:41,430 but keep my import random. 239 00:11:41,430 --> 00:11:44,250 And let's go ahead and define a variable this time called number, 240 00:11:44,250 --> 00:11:47,910 set it equal to the return value of random.randint 241 00:11:47,910 --> 00:11:52,990 and now passing A, a value of 1 and B, a value of 10. 242 00:11:52,990 --> 00:11:55,598 And now, let's go ahead and print the number. 243 00:11:55,598 --> 00:11:57,390 I'm going to go ahead in my terminal window 244 00:11:57,390 --> 00:12:00,360 and run Python of generate.py and hit Enter. 245 00:12:00,360 --> 00:12:01,920 4. 246 00:12:01,920 --> 00:12:04,650 A Python of generate.py and hit Enter. 247 00:12:04,650 --> 00:12:11,700 8, again, 9, again, 7, again, 10, again, 2, again. 248 00:12:11,700 --> 00:12:13,078 And we can do this all day long. 249 00:12:13,078 --> 00:12:15,120 And if we add all of those up, they should end up 250 00:12:15,120 --> 00:12:17,640 being with 10% probability each. 251 00:12:17,640 --> 00:12:19,610 Now, how might you use this information? 252 00:12:19,610 --> 00:12:21,360 Well, maybe we're playing a guessing game. 253 00:12:21,360 --> 00:12:25,710 Or maybe we're trying to randomize the behavior of some character in the game. 254 00:12:25,710 --> 00:12:29,640 You can imagine using very simple building blocks like this just 255 00:12:29,640 --> 00:12:32,070 spicing up your program by getting it to do things 256 00:12:32,070 --> 00:12:36,270 a little less predictably because you're choosing these values seemingly 257 00:12:36,270 --> 00:12:36,780 randomly. 258 00:12:36,780 --> 00:12:38,730 And you're deferring to Python to actually do 259 00:12:38,730 --> 00:12:43,380 the generation of these numbers using its own algorithms and its own math. 260 00:12:43,380 --> 00:12:44,820 Well, what more could we do here? 261 00:12:44,820 --> 00:12:46,860 Let me propose that we introduce another function that 262 00:12:46,860 --> 00:12:48,270 comes from this random library. 263 00:12:48,270 --> 00:12:52,110 Yet, another that you yourself don't have to implement, shuffle. 264 00:12:52,110 --> 00:12:55,690 If you read the documentation for shuffle in the same random module, 265 00:12:55,690 --> 00:12:58,590 you'll see that it takes in a list, for instance, of values 266 00:12:58,590 --> 00:13:00,030 and just shuffles them up. 267 00:13:00,030 --> 00:13:02,730 It randomize them like a deck of cards. 268 00:13:02,730 --> 00:13:06,120 Here, you might shuffle them so as to put them into seemingly random order. 269 00:13:06,120 --> 00:13:09,240 Well, how do I use this based on this function's name? 270 00:13:09,240 --> 00:13:11,850 Well, let me propose that we go back to VS Code here. 271 00:13:11,850 --> 00:13:14,700 And let me go ahead and this time do the following. 272 00:13:14,700 --> 00:13:17,730 Because I need to shuffle something like a deck of cards, 273 00:13:17,730 --> 00:13:19,620 let me go ahead and not just import random. 274 00:13:19,620 --> 00:13:23,640 But let me give myself a variable called cards that's going to be of type list. 275 00:13:23,640 --> 00:13:25,740 And just so I have something to shuffle, I 276 00:13:25,740 --> 00:13:28,200 don't need all 52 cards in a typical deck. 277 00:13:28,200 --> 00:13:29,850 I'm just going to shuffle three cards. 278 00:13:29,850 --> 00:13:32,250 A Jack, a Queen, and a King. 279 00:13:32,250 --> 00:13:34,050 I could call those strings anything I want, 280 00:13:34,050 --> 00:13:37,260 but I just wanted a list of some values so as to shuffle them up. 281 00:13:37,260 --> 00:13:39,480 That is randomize the order therein. 282 00:13:39,480 --> 00:13:40,860 Well, how does this now work? 283 00:13:40,860 --> 00:13:43,080 If you read the documentation for random.shuffle, 284 00:13:43,080 --> 00:13:47,430 you'll see that it shuffles the argument in place. 285 00:13:47,430 --> 00:13:49,620 That is unlike many of the functions we have seen. 286 00:13:49,620 --> 00:13:52,590 It doesn't return to you a value that contains 287 00:13:52,590 --> 00:13:54,370 the shuffled cards in this case. 288 00:13:54,370 --> 00:13:57,730 It actually shuffles the list it's given itself. 289 00:13:57,730 --> 00:13:59,700 So what this means for my code is that I need 290 00:13:59,700 --> 00:14:02,490 to do something like this-- random.shuffle 291 00:14:02,490 --> 00:14:06,510 and pass in the variable containing those cards. 292 00:14:06,510 --> 00:14:11,160 And then on a final line here, how might I go about printing the cards? 293 00:14:11,160 --> 00:14:14,130 Well, I could do this, and I could say print card. 294 00:14:14,130 --> 00:14:17,640 But if I do that, I'm actually going to see Python syntax for lists. 295 00:14:17,640 --> 00:14:21,150 And it's just going to format in its own way using commas and the like. 296 00:14:21,150 --> 00:14:23,130 I want to print these cards out one at a time 297 00:14:23,130 --> 00:14:26,580 just because I think it'll look a little better so we can use some of our syntax 298 00:14:26,580 --> 00:14:28,710 from loops and say something like this-- 299 00:14:28,710 --> 00:14:33,660 for card in cards, go ahead and print out the current card. 300 00:14:33,660 --> 00:14:35,460 So what's now happening here? 301 00:14:35,460 --> 00:14:39,060 Line three, I'm defining a list of three cards in this order-- 302 00:14:39,060 --> 00:14:41,340 Jack, Queen, King. 303 00:14:41,340 --> 00:14:44,010 I'm then shuffling those same cards on line four. 304 00:14:44,010 --> 00:14:46,170 And then on line five, I'm using a for loop 305 00:14:46,170 --> 00:14:50,970 for each of the cards in that list printed out one at a time 306 00:14:50,970 --> 00:14:53,880 and because I'm using print one line at a time. 307 00:14:53,880 --> 00:14:55,080 Well, let's see the results. 308 00:14:55,080 --> 00:14:56,830 Down here in my terminal window, I'm going 309 00:14:56,830 --> 00:14:58,800 to run Python of generate.py and hit Enter. 310 00:14:58,800 --> 00:15:02,610 Queen, King, Jack seemingly shuffled because that's not 311 00:15:02,610 --> 00:15:04,050 the order I defined earlier. 312 00:15:04,050 --> 00:15:05,580 Let's do it again. 313 00:15:05,580 --> 00:15:07,185 Queen, King, Jack. 314 00:15:07,185 --> 00:15:09,300 Hmm, OK, that happens to be the same. 315 00:15:09,300 --> 00:15:10,080 But let's see. 316 00:15:10,080 --> 00:15:11,850 This could just be bad chance. 317 00:15:11,850 --> 00:15:12,600 There we go. 318 00:15:12,600 --> 00:15:14,310 Jack, Queen, King. 319 00:15:14,310 --> 00:15:16,230 Doesn't look like it's shuffled, but at least 320 00:15:16,230 --> 00:15:18,060 we're getting back different orderings now. 321 00:15:18,060 --> 00:15:20,325 Again, Jack, Queen, King. 322 00:15:20,325 --> 00:15:21,810 Hmm, not so good. 323 00:15:21,810 --> 00:15:23,250 Jack, Queen, King. 324 00:15:23,250 --> 00:15:23,760 Not so good. 325 00:15:23,760 --> 00:15:26,302 This is someone you probably want to play against with cards. 326 00:15:26,302 --> 00:15:27,990 Queen, Jack, King, there we go. 327 00:15:27,990 --> 00:15:30,130 But of course, we only have three cards here. 328 00:15:30,130 --> 00:15:32,700 So there's not that many permutations we might see. 329 00:15:32,700 --> 00:15:35,140 And if we do this over time, we will see all of them. 330 00:15:35,140 --> 00:15:37,620 But if we had, of course, 13 or 52 cards, 331 00:15:37,620 --> 00:15:40,210 we'd see a lot more permutations instead. 332 00:15:40,210 --> 00:15:43,590 So we have now these three ways to generate random information. 333 00:15:43,590 --> 00:15:47,220 One, a simple coin toss if you want to start some kind of athletic event. 334 00:15:47,220 --> 00:15:49,165 One, pick a number between 1 and 10 if you 335 00:15:49,165 --> 00:15:50,790 want to decide something based on that. 336 00:15:50,790 --> 00:15:54,090 And now, using shuffle, we can even take in a list of things 337 00:15:54,090 --> 00:15:58,120 and shuffle them about so that we get some kind of random behavior. 338 00:15:58,120 --> 00:16:00,120 Well, let me pause here and see if where there's 339 00:16:00,120 --> 00:16:06,480 any questions yet on random, on modules, or any of these three functions. 340 00:16:06,480 --> 00:16:09,210 AUDIENCE: Yeah, can we increase or decrease 341 00:16:09,210 --> 00:16:14,760 the probability of cards if we want to? 342 00:16:14,760 --> 00:16:16,260 For example, there are three. 343 00:16:16,260 --> 00:16:19,980 There is a 33% chance of probable B. So is there 344 00:16:19,980 --> 00:16:22,230 any chance to increase or decrease the probability? 345 00:16:22,230 --> 00:16:24,360 DAVID MALAN: Can you set these probabilities 346 00:16:24,360 --> 00:16:26,790 not using these same functions? 347 00:16:26,790 --> 00:16:28,110 Can you set the probabilities? 348 00:16:28,110 --> 00:16:31,110 But you can absolutely implement some of your own functions 349 00:16:31,110 --> 00:16:34,710 or use more sophisticated functions that do exist in this library and others 350 00:16:34,710 --> 00:16:36,300 to exercise more control. 351 00:16:36,300 --> 00:16:39,300 These are meant to be very user-friendly and simple functions, certainly 352 00:16:39,300 --> 00:16:42,490 the ones we looked at, that give you equal probability for all of those. 353 00:16:42,490 --> 00:16:44,975 But absolutely you could skew things, though, hopefully, 354 00:16:44,975 --> 00:16:47,100 if you're implementing a gambling game or the like, 355 00:16:47,100 --> 00:16:50,910 you're not actually making some cards more probable than others. 356 00:16:50,910 --> 00:16:55,110 Allow me to turn back now to our implementation here of this randomness 357 00:16:55,110 --> 00:16:58,440 and consider how we might leverage other types of functionality that 358 00:16:58,440 --> 00:17:01,390 aren't necessarily in this specific library here. 359 00:17:01,390 --> 00:17:04,800 Well, it turns out that Python also comes with a statistics library. 360 00:17:04,800 --> 00:17:06,930 And this contains all sorts of functions for doing 361 00:17:06,930 --> 00:17:10,050 things more statistical in nature, namely calculating 362 00:17:10,050 --> 00:17:14,640 means or medians or modes or other aspects of a data set 363 00:17:14,640 --> 00:17:16,530 that you might want to analyze. 364 00:17:16,530 --> 00:17:19,022 So how might we use the statistics module in Python? 365 00:17:19,022 --> 00:17:21,480 Well, we might first just take a look at it's documentation 366 00:17:21,480 --> 00:17:23,238 like any other module in Python. 367 00:17:23,238 --> 00:17:26,280 And we'll see within that library that there's a whole bunch of function. 368 00:17:26,280 --> 00:17:28,840 And one of those functions is one that's quite simple. 369 00:17:28,840 --> 00:17:29,730 It's average. 370 00:17:29,730 --> 00:17:33,120 A function that allows you to calculate the average of some numbers 371 00:17:33,120 --> 00:17:34,230 that you've passed in. 372 00:17:34,230 --> 00:17:38,130 Let me go ahead and in VS Code in my terminal window, open up a new file 373 00:17:38,130 --> 00:17:39,510 called average.py. 374 00:17:39,510 --> 00:17:41,790 And at the top of this file, I'm going to import 375 00:17:41,790 --> 00:17:46,140 a different library this time, namely the statistics module in Python. 376 00:17:46,140 --> 00:17:49,440 And now, I'm going to go ahead and call a function that I know comes 377 00:17:49,440 --> 00:17:53,250 in that module, namely mean for the average of some values. 378 00:17:53,250 --> 00:17:55,710 And I'm going to call statistics.mean. 379 00:17:55,710 --> 00:18:00,122 And I'm going to pass into this function mean, a list of some values. 380 00:18:00,122 --> 00:18:01,830 And let's suppose that I'm quickly trying 381 00:18:01,830 --> 00:18:04,860 to calculate what my current grade average is in school. 382 00:18:04,860 --> 00:18:06,690 And I did really well on my first test. 383 00:18:06,690 --> 00:18:07,920 And I got 100%. 384 00:18:07,920 --> 00:18:10,060 And on my second, I did well but not as well. 385 00:18:10,060 --> 00:18:10,890 And I got a 90. 386 00:18:10,890 --> 00:18:13,140 And ironically, I'm not very good with math. 387 00:18:13,140 --> 00:18:16,630 So I'd like to figure out what my average now is between those two tests. 388 00:18:16,630 --> 00:18:19,260 So let me go ahead now and in this list, type in the number 389 00:18:19,260 --> 00:18:25,110 100, comma, 90, thereby passing in a list of two values, two INTs, 190. 390 00:18:25,110 --> 00:18:28,140 And outside of those are the parentheses because, of course, 391 00:18:28,140 --> 00:18:31,290 this is now the argument I'm passing to the function called mean. 392 00:18:31,290 --> 00:18:35,550 And this function mean is in the module called statistics. 393 00:18:35,550 --> 00:18:38,820 Well, it's not that interesting to just calculate the mean if I don't actually 394 00:18:38,820 --> 00:18:39,700 see what it is. 395 00:18:39,700 --> 00:18:43,290 So let me additionally pass the return value of that mean function 396 00:18:43,290 --> 00:18:45,300 to the print function as usual. 397 00:18:45,300 --> 00:18:47,910 Let me now in my terminal window in VS Code, type 398 00:18:47,910 --> 00:18:50,340 in Python of average.py and hit Enter. 399 00:18:50,340 --> 00:18:54,125 And voila, as you might expect, my average is 95%. 400 00:18:54,125 --> 00:18:57,000 So the difference here is that I'm just using a different module that 401 00:18:57,000 --> 00:18:58,000 still comes with Python. 402 00:18:58,000 --> 00:19:02,370 But I need to import it instead of, for instance, the random module instead. 403 00:19:02,370 --> 00:19:04,260 And this time, I know from the documentation 404 00:19:04,260 --> 00:19:06,850 that there exists a function called mean. 405 00:19:06,850 --> 00:19:10,590 Well, it turns out there's even more functionality that comes with Python 406 00:19:10,590 --> 00:19:13,650 and that comes with other modules in Python. 407 00:19:13,650 --> 00:19:16,630 And there's this feature generally known as command line arguments. 408 00:19:16,630 --> 00:19:19,170 This is a feature, not just of Python, but of languages 409 00:19:19,170 --> 00:19:22,590 more generally that allow you to provide input not when 410 00:19:22,590 --> 00:19:27,780 prompted inside of a program as happens whenever we call the Python function 411 00:19:27,780 --> 00:19:28,560 input. 412 00:19:28,560 --> 00:19:32,100 But rather, there's this feature, command line arguments of programs, 413 00:19:32,100 --> 00:19:34,260 that allows you to provide arguments that 414 00:19:34,260 --> 00:19:38,473 is input to the program of just when you're executing at the command line. 415 00:19:38,473 --> 00:19:40,890 So up until now, for instance, recall that we've generally 416 00:19:40,890 --> 00:19:42,990 run Python of something.py. 417 00:19:42,990 --> 00:19:45,360 For instance, Python of hello.py. 418 00:19:45,360 --> 00:19:49,230 And I've never once really executed any words or phrases 419 00:19:49,230 --> 00:19:52,380 after the name of the file, but I could. 420 00:19:52,380 --> 00:19:57,270 In fact, when you're running programs in a command-like environment like we are, 421 00:19:57,270 --> 00:20:02,418 you can provide any number of words or numbers or phrases after the command 422 00:20:02,418 --> 00:20:03,210 that you're typing. 423 00:20:03,210 --> 00:20:08,020 And all of those will somehow be passed in as inputs to the program itself. 424 00:20:08,020 --> 00:20:11,790 You don't have to prompt the user for one thing at a time 425 00:20:11,790 --> 00:20:14,230 by manually calling that input function. 426 00:20:14,230 --> 00:20:15,810 So what does this mean in real terms? 427 00:20:15,810 --> 00:20:18,270 Well, let me go ahead back into VS Code here. 428 00:20:18,270 --> 00:20:23,940 And let me propose that we consider how we might leverage a certain module. 429 00:20:23,940 --> 00:20:27,930 I'm going to go ahead and create a file called name.py. 430 00:20:27,930 --> 00:20:30,420 And I'd like to use a new module this time that's 431 00:20:30,420 --> 00:20:35,610 going to give me access to values that have been typed at the command line. 432 00:20:35,610 --> 00:20:37,170 But what's this module going to be? 433 00:20:37,170 --> 00:20:39,060 Well, this one's going to be called sys. 434 00:20:39,060 --> 00:20:42,480 And sys, short for system, contains a whole lot of functionality 435 00:20:42,480 --> 00:20:46,770 that's specific to the system itself and the commands that you and I are typing. 436 00:20:46,770 --> 00:20:49,800 The documentation for this module is at this URL here. 437 00:20:49,800 --> 00:20:53,100 And it lists all of the various functions and variables and the like 438 00:20:53,100 --> 00:20:54,758 that come with that module. 439 00:20:54,758 --> 00:20:57,300 But we're going to focus on something a little more specific, 440 00:20:57,300 --> 00:20:58,980 namely this thing here. 441 00:20:58,980 --> 00:21:01,950 It turns out in the sys module in Python, 442 00:21:01,950 --> 00:21:06,900 there is a variable that just magically exists for you called argv. 443 00:21:06,900 --> 00:21:10,650 It stands for argument vector which is a fancy way of describing 444 00:21:10,650 --> 00:21:15,090 the list of all of the words that the human typed in at their prompt 445 00:21:15,090 --> 00:21:16,650 before they hit Enter. 446 00:21:16,650 --> 00:21:21,360 All of those are seemingly magically provided to you via Python 447 00:21:21,360 --> 00:21:24,270 in a variable called sys.argv. 448 00:21:24,270 --> 00:21:27,882 This variable is a list, which means that the first element is going 449 00:21:27,882 --> 00:21:29,340 to be the first word that you type. 450 00:21:29,340 --> 00:21:30,870 The second element is going to be the second word 451 00:21:30,870 --> 00:21:32,200 that you typed in, so forth. 452 00:21:32,200 --> 00:21:34,800 And by way of this list, then, can you figure out 453 00:21:34,800 --> 00:21:38,280 what words did the human actually type at the prompt and maybe use that 454 00:21:38,280 --> 00:21:41,340 to influence the behavior of your own program? 455 00:21:41,340 --> 00:21:43,110 So what does this mean now in real terms? 456 00:21:43,110 --> 00:21:47,760 Well, in this new tab called name.py, let me go ahead and import sys. 457 00:21:47,760 --> 00:21:52,650 Within that sys module is going to give me access to sys.argv, but how might 458 00:21:52,650 --> 00:21:53,550 I want to use it? 459 00:21:53,550 --> 00:21:54,570 Well, let's do this. 460 00:21:54,570 --> 00:21:58,500 Instead of writing a Hello World program that all of these times 461 00:21:58,500 --> 00:22:02,040 has just looked for the return value of input 462 00:22:02,040 --> 00:22:04,530 to figure out what the user wants me to print, 463 00:22:04,530 --> 00:22:06,900 let's go ahead and just expect the user to tell us 464 00:22:06,900 --> 00:22:10,140 when they run the Python program itself, what their name is. 465 00:22:10,140 --> 00:22:13,350 And suppose this time, I'd like to generate a whole bunch of name tags, 466 00:22:13,350 --> 00:22:14,490 initially just one. 467 00:22:14,490 --> 00:22:17,730 And in the US here, it's very common to wear a sticker on your lapel that 468 00:22:17,730 --> 00:22:19,350 says Hello, my name is David. 469 00:22:19,350 --> 00:22:21,750 So I want to print out some text that resembles that. 470 00:22:21,750 --> 00:22:24,483 The idea being maybe I could enhance this program someday 471 00:22:24,483 --> 00:22:26,400 to even send that text straight to the printer 472 00:22:26,400 --> 00:22:28,950 and dynamically generate those name tags. 473 00:22:28,950 --> 00:22:30,610 Well, let me go ahead now and do this. 474 00:22:30,610 --> 00:22:32,853 Let me go ahead and print out as always, Hello. 475 00:22:32,853 --> 00:22:34,770 But I'll say a little something more this time 476 00:22:34,770 --> 00:22:36,103 to make things more interesting. 477 00:22:36,103 --> 00:22:38,580 Hello, my name "is," quote, unquote. 478 00:22:38,580 --> 00:22:41,610 And then after that, I normally have been 479 00:22:41,610 --> 00:22:45,900 in the habit of calling input, storing the return value in a variable, 480 00:22:45,900 --> 00:22:48,570 and passing in the name of that variable here. 481 00:22:48,570 --> 00:22:50,790 But I'm going to instead jump right to this-- 482 00:22:50,790 --> 00:22:53,880 sys.argvbracket1. 483 00:22:53,880 --> 00:22:55,260 And that's it. 484 00:22:55,260 --> 00:22:59,010 I'm going to have a program here that says Hello, my name is followed 485 00:22:59,010 --> 00:23:02,640 by whatever is in sys.argvbracket1. 486 00:23:02,640 --> 00:23:04,860 And notice, this .argv again is a list. 487 00:23:04,860 --> 00:23:07,830 And recall from our discussion of loops and in turn list, 488 00:23:07,830 --> 00:23:11,790 we use this square bracket notation to get at the various elements 489 00:23:11,790 --> 00:23:12,900 inside of a list. 490 00:23:12,900 --> 00:23:15,120 All right, let me go down now into my terminal window 491 00:23:15,120 --> 00:23:17,100 and run Python of name.py. 492 00:23:17,100 --> 00:23:19,440 But this time, rather than just hit Enter 493 00:23:19,440 --> 00:23:21,690 and wait for the program to prompt me for my name, 494 00:23:21,690 --> 00:23:24,990 let me proactively just tell this program what my name is 495 00:23:24,990 --> 00:23:26,550 at the so-called command line. 496 00:23:26,550 --> 00:23:27,210 Here we go. 497 00:23:27,210 --> 00:23:31,980 D-A-V-I-D separated with a space from the name of the file so that now when I 498 00:23:31,980 --> 00:23:37,410 execute Python, name.py David, I see on the screen, voila, Hello, 499 00:23:37,410 --> 00:23:38,460 my name is David. 500 00:23:38,460 --> 00:23:41,400 So based on this demonstration alone, I think 501 00:23:41,400 --> 00:23:44,280 we can infer exactly what's going on in sys.argv 502 00:23:44,280 --> 00:23:48,450 even though it sounds certainly at first glance, rather complicated here. 503 00:23:48,450 --> 00:23:49,170 Let's look up. 504 00:23:49,170 --> 00:23:53,160 At sys.argv, I'm going to bracket1 here. 505 00:23:53,160 --> 00:24:01,320 So clearly, sys.argvbracket1 is storing D-A-V-I-D. But it's one. 506 00:24:01,320 --> 00:24:03,750 In the past when we looked at loops, recall 507 00:24:03,750 --> 00:24:06,030 that we said that they were zero index. 508 00:24:06,030 --> 00:24:07,890 That is the first element is zero. 509 00:24:07,890 --> 00:24:09,450 The next element is one. 510 00:24:09,450 --> 00:24:12,040 This next element is two and so forth. 511 00:24:12,040 --> 00:24:14,520 And yet, here I am treating it as though my name 512 00:24:14,520 --> 00:24:16,320 is at the start of the list one. 513 00:24:16,320 --> 00:24:23,180 Well, let me ask this question, what is probably in sys.argv of 0? 514 00:24:23,180 --> 00:24:27,710 What is probably in sys.argv of 0-- 515 00:24:27,710 --> 00:24:30,680 the very first element actually in that list? 516 00:24:30,680 --> 00:24:32,360 AUDIENCE: Oh, yeah. 517 00:24:32,360 --> 00:24:37,625 I think it's like in C, the name of program. 518 00:24:37,625 --> 00:24:40,280 DAVID MALAN: Indeed, it's indeed like in C. Another language 519 00:24:40,280 --> 00:24:41,750 is the name of the program. 520 00:24:41,750 --> 00:24:44,090 Well, if we consider what it was I typed, 521 00:24:44,090 --> 00:24:47,330 I certainly typed Python because that's the name of my interpreter. 522 00:24:47,330 --> 00:24:50,480 And we don't really need to know that because we're using Python itself. 523 00:24:50,480 --> 00:24:52,460 But after that, I did type two things. 524 00:24:52,460 --> 00:24:55,670 I typed name.py as I've done so many times any time 525 00:24:55,670 --> 00:24:58,130 I want Python to the interpreter program I've written. 526 00:24:58,130 --> 00:25:00,170 And it turns out by convention, what Python 527 00:25:00,170 --> 00:25:05,750 does is it stores in sys.argv the name of the file that you're executing 528 00:25:05,750 --> 00:25:10,170 or interpreting followed by any number of other words that you type. 529 00:25:10,170 --> 00:25:12,618 So all this time, we could have been accessing 530 00:25:12,618 --> 00:25:15,410 the name of the program, which frankly, isn't all that interesting. 531 00:25:15,410 --> 00:25:20,450 But we can also now access words that are typed after that prompt as well. 532 00:25:20,450 --> 00:25:25,628 But of course, if I don't type anything in, what might happen here? 533 00:25:25,628 --> 00:25:27,920 This might be naive of me to assume that there's always 534 00:25:27,920 --> 00:25:30,920 going to be something at location1 in sys.argv. 535 00:25:30,920 --> 00:25:32,330 Let me go ahead and try this. 536 00:25:32,330 --> 00:25:33,950 Python, name.py. 537 00:25:33,950 --> 00:25:36,500 And I'm not giving you my name because at this point, 538 00:25:36,500 --> 00:25:39,350 I might not even know that you want my name to be typed. 539 00:25:39,350 --> 00:25:40,790 So let me hit Enter now. 540 00:25:40,790 --> 00:25:43,160 And uh, oh, we see now an error. 541 00:25:43,160 --> 00:25:46,160 A so-called exception in Python, this one's a new one. 542 00:25:46,160 --> 00:25:51,110 This one's an index error that elaborates list index out of range. 543 00:25:51,110 --> 00:25:53,870 And turns out this is actually one of the most common mistakes 544 00:25:53,870 --> 00:25:56,690 in programming, whether you're using a list in Python 545 00:25:56,690 --> 00:25:59,300 or arrays or vectors in other languages, is 546 00:25:59,300 --> 00:26:02,240 to try to access some element that does not exist. 547 00:26:02,240 --> 00:26:03,920 You try to go too far to the left. 548 00:26:03,920 --> 00:26:08,150 Or you try to go too far to the right in this object that 549 00:26:08,150 --> 00:26:10,500 is just a list of some values. 550 00:26:10,500 --> 00:26:13,070 So of course, the mistake here is that I'm 551 00:26:13,070 --> 00:26:15,500 assuming there's going to be something at location1 552 00:26:15,500 --> 00:26:17,930 when really, it's location0. 553 00:26:17,930 --> 00:26:19,580 That's the only one that has a value. 554 00:26:19,580 --> 00:26:23,300 But fixing this is not going to amount to doing bracket0 555 00:26:23,300 --> 00:26:27,330 because now if I go ahead and rerun this program with no other words 556 00:26:27,330 --> 00:26:31,492 after name.py, it says Hello, my name is name.py, which is fine 557 00:26:31,492 --> 00:26:33,950 if we're making a name tag for the program, but that's not, 558 00:26:33,950 --> 00:26:36,390 of course, what my goal here is instead. 559 00:26:36,390 --> 00:26:40,260 So if the fix is not just to change the one to a zero, 560 00:26:40,260 --> 00:26:43,730 how else might I handle this error? 561 00:26:43,730 --> 00:26:46,190 How else might I handle this error? 562 00:26:46,190 --> 00:26:49,910 This index error that happens if the user just doesn't remember to 563 00:26:49,910 --> 00:26:53,510 or doesn't know to type their actual name at the prompt. 564 00:26:53,510 --> 00:26:56,630 AUDIENCE: We could always put an exception into the program, 565 00:26:56,630 --> 00:27:03,510 say, if there's nothing at location1, we just come out 566 00:27:03,510 --> 00:27:06,290 and say, OK, we haven't got parameter or something. 567 00:27:06,290 --> 00:27:09,615 But if there is, we continue along with the program. 568 00:27:09,615 --> 00:27:10,490 DAVID MALAN: Perfect. 569 00:27:10,490 --> 00:27:13,902 So if I might simplify, we can try to execute this line of code, 570 00:27:13,902 --> 00:27:16,610 except if there's an error, we'll deal with it in some other way. 571 00:27:16,610 --> 00:27:19,670 Now, ideally-- and once I'm a strong enough programmer, 572 00:27:19,670 --> 00:27:22,730 I would have anticipated this and written the following code 573 00:27:22,730 --> 00:27:23,630 from the get go. 574 00:27:23,630 --> 00:27:25,970 But when you're learning, it's certainly reasonable to see an error. 575 00:27:25,970 --> 00:27:28,160 Oh, I didn't realize I should detect that and then 576 00:27:28,160 --> 00:27:29,540 go back and improve your code. 577 00:27:29,540 --> 00:27:31,680 But of course, if you read the documentation, 578 00:27:31,680 --> 00:27:33,930 you ingrain some of the lessons learned from the past. 579 00:27:33,930 --> 00:27:37,610 You'll get into the habit of trying and checking for some of these exceptions 580 00:27:37,610 --> 00:27:38,250 yourself. 581 00:27:38,250 --> 00:27:41,450 So let me solve this in one possible way as you've proposed here. 582 00:27:41,450 --> 00:27:43,950 Let's try to handle this exception as follows. 583 00:27:43,950 --> 00:27:44,870 Let me go ahead now. 584 00:27:44,870 --> 00:27:47,420 And instead of just blindly calling this print line, 585 00:27:47,420 --> 00:27:51,770 let me try to print out Hello, my name is such and such, 586 00:27:51,770 --> 00:27:56,630 except if there is an issue, specifically an index error, then 587 00:27:56,630 --> 00:27:58,250 what do I want to go ahead and do? 588 00:27:58,250 --> 00:28:01,250 I'm going to say something like too few arguments. 589 00:28:01,250 --> 00:28:03,270 I could be more explanatory than that. 590 00:28:03,270 --> 00:28:05,480 But for now, I'm just going to explain to the user 591 00:28:05,480 --> 00:28:08,760 that they gave me too few arguments, too few words at the prompt. 592 00:28:08,760 --> 00:28:12,243 So now, it's still not going to work in quite the way I want. 593 00:28:12,243 --> 00:28:14,660 I'm still not going to be able to generate their name tag. 594 00:28:14,660 --> 00:28:17,368 But at least, they're not going to see some cryptic error message 595 00:28:17,368 --> 00:28:20,070 and think that they themselves broke the program. 596 00:28:20,070 --> 00:28:23,740 Let me go ahead now and run Python of name.py Enter and too few arguments. 597 00:28:23,740 --> 00:28:28,970 OK, let me go ahead now and do Python of name.py and type in my name, David. 598 00:28:28,970 --> 00:28:30,350 And now we're back in business. 599 00:28:30,350 --> 00:28:33,680 And I see that my name is on the screen too. 600 00:28:33,680 --> 00:28:37,460 But strictly speaking, I don't have to try to do this. 601 00:28:37,460 --> 00:28:41,090 I could actually be a little more defensive in writing this code. 602 00:28:41,090 --> 00:28:44,540 And maybe I could check whether or not the user has indeed 603 00:28:44,540 --> 00:28:48,740 provided a name or multiple names at the prompt so as to give them 604 00:28:48,740 --> 00:28:51,300 more refined error messages as well. 605 00:28:51,300 --> 00:28:52,620 So how might I do this? 606 00:28:52,620 --> 00:28:56,150 Well, me go and undo the exception handling I've added. 607 00:28:56,150 --> 00:28:59,220 And why don't I instead more modestly try to do this? 608 00:28:59,220 --> 00:29:01,700 Let me go ahead and introduce a conditional here. 609 00:29:01,700 --> 00:29:09,740 If the length of sys.argv is less than 2 or equivalently equal to just one 610 00:29:09,740 --> 00:29:10,440 value-- 611 00:29:10,440 --> 00:29:12,860 but I'll just stick with less than 2 for now, 612 00:29:12,860 --> 00:29:17,030 then go ahead and print out two few arguments. 613 00:29:17,030 --> 00:29:19,070 So I want ultimately two arguments. 614 00:29:19,070 --> 00:29:21,890 I want the name of the program at location0. 615 00:29:21,890 --> 00:29:24,380 And I want the name of the human at location1. 616 00:29:24,380 --> 00:29:26,010 So that's a total of two arguments. 617 00:29:26,010 --> 00:29:28,070 So if I have fewer than two arguments, let's 618 00:29:28,070 --> 00:29:32,780 tell the user with this print line, L if the length of sys.argv 619 00:29:32,780 --> 00:29:36,710 is say greater than 2, like they typed in too many words at the prompt, well, 620 00:29:36,710 --> 00:29:40,610 let's tell them, print, quote, unquote, "too" many arguments. 621 00:29:40,610 --> 00:29:44,900 Else if they did get it right, and they gave me exactly two arguments. 622 00:29:44,900 --> 00:29:48,072 Else, let's go ahead and print what I actually care about. 623 00:29:48,072 --> 00:29:50,030 All right, let me go down to my terminal window 624 00:29:50,030 --> 00:29:52,760 here and run Python of name.py and voila. 625 00:29:52,760 --> 00:29:55,520 Uh, oh, a completely different type of error. 626 00:29:55,520 --> 00:29:58,260 This one a syntax error, which we've seen in the past. 627 00:29:58,260 --> 00:30:01,970 Now, a syntax error recall is mea culpa, like, I messed up here. 628 00:30:01,970 --> 00:30:03,740 And I wrote invalid syntax. 629 00:30:03,740 --> 00:30:07,038 And so no amount of conditionals or exception handling's 630 00:30:07,038 --> 00:30:08,330 really going to catch this one. 631 00:30:08,330 --> 00:30:09,890 I need to go back and just get my program 632 00:30:09,890 --> 00:30:11,557 to work because it's not running at all. 633 00:30:11,557 --> 00:30:14,000 Well, let me go up here and see. 634 00:30:14,000 --> 00:30:16,100 Line four is the issue. 635 00:30:16,100 --> 00:30:19,880 And indeed, it looks like I have an unterminated string here. 636 00:30:19,880 --> 00:30:22,490 I need to go ahead and now add this double quote. 637 00:30:22,490 --> 00:30:23,910 So let me go ahead now. 638 00:30:23,910 --> 00:30:27,800 And with that red herring gone, let me rerun Python of name.py and hit Enter. 639 00:30:27,800 --> 00:30:29,630 And now, we see too few arguments. 640 00:30:29,630 --> 00:30:31,610 OK, maybe it wants my full name. 641 00:30:31,610 --> 00:30:35,210 Let me go ahead now and run Python of name.py, David Malan, 642 00:30:35,210 --> 00:30:39,200 typing in both words after the name of the file and hit Enter. 643 00:30:39,200 --> 00:30:41,220 And now, of course, it's too many arguments. 644 00:30:41,220 --> 00:30:41,720 Fine. 645 00:30:41,720 --> 00:30:44,930 Now, I'll oblige and do Python of name.py and just David. 646 00:30:44,930 --> 00:30:46,020 And there we have it. 647 00:30:46,020 --> 00:30:48,230 My name tag printed on the screen. 648 00:30:48,230 --> 00:30:51,200 So strictly speaking, we don't have to handle exceptions 649 00:30:51,200 --> 00:30:54,080 if we can be a little smarter about it and just check for the things 650 00:30:54,080 --> 00:30:56,210 that we're worried about, especially if we want 651 00:30:56,210 --> 00:30:58,437 to give the user more refined advice. 652 00:30:58,437 --> 00:31:00,770 We don't want to just tell them no, something went wrong 653 00:31:00,770 --> 00:31:01,910 or we don't want to pass. 654 00:31:01,910 --> 00:31:05,790 We want to tell them no, that's too few or no, that's too many. 655 00:31:05,790 --> 00:31:08,360 We have conditionals in our vocabulary already 656 00:31:08,360 --> 00:31:11,030 via which we can now express that. 657 00:31:11,030 --> 00:31:13,640 Well, let me pause here and see if there's any questions now 658 00:31:13,640 --> 00:31:16,970 on how we handled the error before with the index error 659 00:31:16,970 --> 00:31:21,980 or how now we're just proactively avoiding all index errors altogether 660 00:31:21,980 --> 00:31:24,560 by just checking first, is it too few? 661 00:31:24,560 --> 00:31:25,310 Is it too many? 662 00:31:25,310 --> 00:31:27,290 Or is it exactly what we want? 663 00:31:27,290 --> 00:31:28,970 AUDIENCE: Hi, yeah, thank you. 664 00:31:28,970 --> 00:31:32,525 So I was wondering, you touched upon using your full name. 665 00:31:32,525 --> 00:31:36,470 666 00:31:36,470 --> 00:31:40,640 Is there a way going forwards that perhaps we 667 00:31:40,640 --> 00:31:44,390 have people that want their full names and want just their first name 668 00:31:44,390 --> 00:31:47,840 that we separate that into, oh, this person has full name. 669 00:31:47,840 --> 00:31:50,785 This person has just the one name? 670 00:31:50,785 --> 00:31:55,470 DAVID MALAN: Absolutely, and allow me to propose we come back 671 00:31:55,470 --> 00:31:57,660 to that support for multiple names. 672 00:31:57,660 --> 00:31:59,070 But indeed, we could do that. 673 00:31:59,070 --> 00:32:02,010 And I should note too, though, we can support 674 00:32:02,010 --> 00:32:04,140 full names right now if I do this. 675 00:32:04,140 --> 00:32:08,490 Instead of typing in David space Malan, which is problematic because again, 676 00:32:08,490 --> 00:32:11,730 by definition of how are argv works, each word 677 00:32:11,730 --> 00:32:14,220 ends up in a specific location in the list. 678 00:32:14,220 --> 00:32:18,610 But if I add quotes, single quotes or double quotes at the command line, 679 00:32:18,610 --> 00:32:21,270 now, Python will view this as two total things. 680 00:32:21,270 --> 00:32:23,370 The name of the file and this full name. 681 00:32:23,370 --> 00:32:25,590 And now, when I hit Enter, I don't see the quotes. 682 00:32:25,590 --> 00:32:28,020 The whole thing is passed in as my full name. 683 00:32:28,020 --> 00:32:30,750 And if I want to adapt this further for multiple people, 684 00:32:30,750 --> 00:32:32,530 we'll be able to do that as well. 685 00:32:32,530 --> 00:32:37,350 Other questions now on this version with if, elif, else, or on except before. 686 00:32:37,350 --> 00:32:39,850 AUDIENCE: Python. 687 00:32:39,850 --> 00:32:43,673 I want to ask you, can we use multiple else's statement? 688 00:32:43,673 --> 00:32:45,840 DAVID MALAN: Can you use multiple else's statements? 689 00:32:45,840 --> 00:32:48,930 No, else is the last catchall statement that you can have. 690 00:32:48,930 --> 00:32:55,310 You can have multiple elif statements in the middle but not multiple elses. 691 00:32:55,310 --> 00:32:56,715 AUDIENCE: [INAUDIBLE] 692 00:32:56,715 --> 00:32:57,735 DAVID MALAN: All right. 693 00:32:57,735 --> 00:33:00,360 All right, well, let's turn our attention back now to this code 694 00:33:00,360 --> 00:33:02,820 and see if we can't refine it a bit more by adding 695 00:33:02,820 --> 00:33:06,870 in some additional functionality that we get with modules like the sys module. 696 00:33:06,870 --> 00:33:09,540 One of the things I don't love about this version of the code 697 00:33:09,540 --> 00:33:14,920 even though arguably it is now correct is that the essence of my program, 698 00:33:14,920 --> 00:33:19,530 which is just to print out the name tag, is relegated to this else clause. 699 00:33:19,530 --> 00:33:20,670 And that's fine. 700 00:33:20,670 --> 00:33:24,010 Logically, it's correct, but generally speaking, 701 00:33:24,010 --> 00:33:26,700 there is something nice about keeping all of your error 702 00:33:26,700 --> 00:33:30,330 handling separate from the code that you really 703 00:33:30,330 --> 00:33:34,320 care about having all of these ifs, elifs, perhaps at the top of your code 704 00:33:34,320 --> 00:33:37,950 that are checking to make sure that all of the data's as expected. 705 00:33:37,950 --> 00:33:41,160 But then it would be nice if only for design sake 706 00:33:41,160 --> 00:33:45,630 not to hide in this else statement the actual code that you care about. 707 00:33:45,630 --> 00:33:49,050 I would prefer, for instance, to do something logically like this. 708 00:33:49,050 --> 00:33:51,930 I could check for errors up top. 709 00:33:51,930 --> 00:33:54,810 And then down here, print the name tag. 710 00:33:54,810 --> 00:33:58,440 It would be nice if those are distinct blocks of code all of which 711 00:33:58,440 --> 00:33:59,760 are here left aligned. 712 00:33:59,760 --> 00:34:02,490 But there's a problem with what I've just done here. 713 00:34:02,490 --> 00:34:08,130 Logically, what bug did I just introduce by getting rid of the else 714 00:34:08,130 --> 00:34:12,480 and introducing line 10 on its own with no indentation 715 00:34:12,480 --> 00:34:14,639 outside of the conditional? 716 00:34:14,639 --> 00:34:16,530 What bug have I just introduced? 717 00:34:16,530 --> 00:34:19,851 What mistake to be clear? 718 00:34:19,851 --> 00:34:20,964 AUDIENCE: Name error. 719 00:34:20,964 --> 00:34:25,270 DAVID MALAN: Ironically, it's a name error but not a name error exception. 720 00:34:25,270 --> 00:34:30,100 It's an error with my name, but I think you're frozen for me. 721 00:34:30,100 --> 00:34:32,889 It's going to raise an exception because even 722 00:34:32,889 --> 00:34:36,370 though I'm checking the length of sys.argv up top 723 00:34:36,370 --> 00:34:39,880 and even though I'm checking it again for being greater than 2, not just less 724 00:34:39,880 --> 00:34:44,020 than 2, but greater, I'm still then blindly and incorrectly assuming 725 00:34:44,020 --> 00:34:45,230 it's now going to exist. 726 00:34:45,230 --> 00:34:50,199 So just to be clear, if I run Python of name.py and I don't type any argument-- 727 00:34:50,199 --> 00:34:51,580 I've got too few-- 728 00:34:51,580 --> 00:34:53,710 I think I'm going to see that I have too few, 729 00:34:53,710 --> 00:34:56,972 but I'm also going to see that same exception. 730 00:34:56,972 --> 00:34:58,930 At the very top of my terminal window's output, 731 00:34:58,930 --> 00:35:01,000 there's my error message, too few arguments. 732 00:35:01,000 --> 00:35:05,800 But again, on line 10, I blindly proceed to still index into my list 733 00:35:05,800 --> 00:35:08,480 at location1 which does not exist. 734 00:35:08,480 --> 00:35:11,890 So it turns out there's a better way to handle errors like this, especially 735 00:35:11,890 --> 00:35:14,680 if you're writing a program in Python that's just meant 736 00:35:14,680 --> 00:35:17,380 to run briefly and then exit anyway. 737 00:35:17,380 --> 00:35:22,330 But maybe we could start to exit prematurely if the program itself just 738 00:35:22,330 --> 00:35:23,110 can't proceed. 739 00:35:23,110 --> 00:35:25,330 If the user has not given us the data we want, 740 00:35:25,330 --> 00:35:30,070 perhaps, we should just exit the program earlier than we might otherwise. 741 00:35:30,070 --> 00:35:31,940 So let me go ahead and do this. 742 00:35:31,940 --> 00:35:35,380 Let me go ahead and remove my comments so as to focus only on the code here. 743 00:35:35,380 --> 00:35:39,550 And let me propose that instead of just printing, 744 00:35:39,550 --> 00:35:43,300 quote, unquote, "too" few arguments, I'm going to use one other function that 745 00:35:43,300 --> 00:35:44,890 comes with the sys module. 746 00:35:44,890 --> 00:35:48,040 I'm going to go ahead and call sys.exit. 747 00:35:48,040 --> 00:35:50,920 And as the name suggests, it's going to do exactly that. 748 00:35:50,920 --> 00:35:55,030 With the system's help, it's going to exit my program then and there 749 00:35:55,030 --> 00:35:56,260 on line four. 750 00:35:56,260 --> 00:35:57,522 Why is that OK? 751 00:35:57,522 --> 00:35:59,230 Well, if you gave me too few arguments, I 752 00:35:59,230 --> 00:36:01,120 have nothing more to say to you, the user. 753 00:36:01,120 --> 00:36:03,460 I might as well exit a bit prematurely. 754 00:36:03,460 --> 00:36:05,410 And I can do this as well on line six. 755 00:36:05,410 --> 00:36:08,990 Let's go ahead and not just print that, but sys.exit, quote, unquote, 756 00:36:08,990 --> 00:36:10,060 "too" many arguments. 757 00:36:10,060 --> 00:36:12,790 Print out that message and just exit right there. 758 00:36:12,790 --> 00:36:16,480 Now, I can trust that by the time I get to line eight, 759 00:36:16,480 --> 00:36:19,390 every error condition has been checked for. 760 00:36:19,390 --> 00:36:25,150 And so it's safe for me to assume that there is in fact an item at location1 761 00:36:25,150 --> 00:36:26,740 in sys.argv. 762 00:36:26,740 --> 00:36:29,860 So let me go ahead now and run this, Python 763 00:36:29,860 --> 00:36:32,800 of name.py, Enter, too few arguments. 764 00:36:32,800 --> 00:36:34,540 But I'm back at my prompt. 765 00:36:34,540 --> 00:36:36,220 Nothing more has happened. 766 00:36:36,220 --> 00:36:37,120 Let me run it again. 767 00:36:37,120 --> 00:36:41,020 Python of name.py David Malan with no quotes, Enter. 768 00:36:41,020 --> 00:36:42,970 Too many arguments is now printed here. 769 00:36:42,970 --> 00:36:46,900 Finally, Python of name.py just David, Enter. 770 00:36:46,900 --> 00:36:48,940 Hello, my name is David. 771 00:36:48,940 --> 00:36:52,040 So we have then in sys two forms of functionality. 772 00:36:52,040 --> 00:36:55,630 Now, we have access to this variable, sys.argv, this argument vector, 773 00:36:55,630 --> 00:36:58,330 that gives me all of the words that were typed at the prompt, 774 00:36:58,330 --> 00:37:00,370 including the program's own file name. 775 00:37:00,370 --> 00:37:03,040 And it turns out if we read further in the documentation, 776 00:37:03,040 --> 00:37:06,280 there's an exit function that can take different types of input. 777 00:37:06,280 --> 00:37:10,450 But if I pass out a string like this, it will indeed print that string for me 778 00:37:10,450 --> 00:37:13,780 and then exit from my program then and there. 779 00:37:13,780 --> 00:37:17,980 Questions now on exiting from programs like this. 780 00:37:17,980 --> 00:37:22,360 To be clear, all of this time once Python gets to the bottom of your file, 781 00:37:22,360 --> 00:37:23,800 it's going to exit anyway. 782 00:37:23,800 --> 00:37:28,000 So I'm using sys.exit now just to make sure that I exit earlier than 783 00:37:28,000 --> 00:37:28,900 otherwise. 784 00:37:28,900 --> 00:37:32,410 AUDIENCE: My question is about the sys that arg-- 785 00:37:32,410 --> 00:37:33,730 argv. 786 00:37:33,730 --> 00:37:40,130 So is that capable of accepting or taking multiple elements at once? 787 00:37:40,130 --> 00:37:45,280 Let's say, for example, Python name.py, David Malan. 788 00:37:45,280 --> 00:37:48,610 I'm a male, 20 years old. 789 00:37:48,610 --> 00:37:53,990 And if let's say I only want to access your name, which is at the first index. 790 00:37:53,990 --> 00:37:59,200 And then your age is, say, at the sixth index. 791 00:37:59,200 --> 00:38:07,380 Can I say sys.argv1 and another one for six to access what I just want? 792 00:38:07,380 --> 00:38:10,335 Is that both for sys.argv? 793 00:38:10,335 --> 00:38:13,950 DAVID MALAN: Short answer-- yes, I think if I understand your question 794 00:38:13,950 --> 00:38:15,870 correctly, whereby, you're proposing to have 795 00:38:15,870 --> 00:38:17,790 many words at the end of the command. 796 00:38:17,790 --> 00:38:19,710 And you want to access those individual words. 797 00:38:19,710 --> 00:38:20,850 Absolutely. 798 00:38:20,850 --> 00:38:24,180 At some point, it gets a little fragile, I would say, 799 00:38:24,180 --> 00:38:28,900 if you're typing so many words at the prompt that the order really matters. 800 00:38:28,900 --> 00:38:30,900 And so it turns out there's a lot of programs. 801 00:38:30,900 --> 00:38:32,733 And there's functionality in Python that can 802 00:38:32,733 --> 00:38:36,540 allow you to provide those values, like name or age 803 00:38:36,540 --> 00:38:39,120 or any number of other fields in any order 804 00:38:39,120 --> 00:38:43,200 you want, but a pass in a bit more information textually 805 00:38:43,200 --> 00:38:45,160 that tells the program how you want to use it. 806 00:38:45,160 --> 00:38:47,800 So in short, what you're describing is possible. 807 00:38:47,800 --> 00:38:51,820 And let me do a small incarnation of it as follows. 808 00:38:51,820 --> 00:38:54,420 Let me propose that we go back to my code here. 809 00:38:54,420 --> 00:38:56,520 And let's propose that we actually now want 810 00:38:56,520 --> 00:38:58,840 to support multiple values at the prompt. 811 00:38:58,840 --> 00:39:01,680 So there's going to be no such thing as too many arguments. 812 00:39:01,680 --> 00:39:05,610 Suppose that I want to generate name tags not just for David, but for David, 813 00:39:05,610 --> 00:39:08,610 for Carter, for Rongshin, for others in the group who 814 00:39:08,610 --> 00:39:10,048 all want their name tags as well. 815 00:39:10,048 --> 00:39:11,590 So I'm going to go ahead and do this. 816 00:39:11,590 --> 00:39:13,470 I'm going to get rid of my elif condition 817 00:39:13,470 --> 00:39:16,200 because I don't want to limit the maximum number of words 818 00:39:16,200 --> 00:39:17,850 that are typed at the prompt anymore. 819 00:39:17,850 --> 00:39:23,538 I instead want to iterate over every name at the prompt. 820 00:39:23,538 --> 00:39:24,580 So I'm going to say this. 821 00:39:24,580 --> 00:39:32,080 For arginsys.argv, go ahead and print out this time, arg. 822 00:39:32,080 --> 00:39:33,770 So what am I doing here? 823 00:39:33,770 --> 00:39:36,050 Well, even though the syntax is a little different, 824 00:39:36,050 --> 00:39:38,800 the idea's the same as before when we've had loop. 825 00:39:38,800 --> 00:39:42,070 I'm using a for loop to iterate over a list. 826 00:39:42,070 --> 00:39:45,040 The list in question here is sys.argv. 827 00:39:45,040 --> 00:39:48,055 Arg is a variable that I'm creating on the fly. 828 00:39:48,055 --> 00:39:51,670 The for loop is going to make sure that the first time through this loop, arg 829 00:39:51,670 --> 00:39:53,820 is set to the first word on the command line. 830 00:39:53,820 --> 00:39:55,570 The second time through the loop, Python's 831 00:39:55,570 --> 00:39:58,370 going to make sure that arg is now set to the second thing on the command line 832 00:39:58,370 --> 00:39:58,840 and so forth. 833 00:39:58,840 --> 00:40:00,220 That's just how a for loop works. 834 00:40:00,220 --> 00:40:02,050 It updates the variable for us. 835 00:40:02,050 --> 00:40:03,280 I don't have to call it arg. 836 00:40:03,280 --> 00:40:07,070 I could call it name so long as I change it to name in both places. 837 00:40:07,070 --> 00:40:10,900 But arg is reasonable if I'm iterating over arguments more generally. 838 00:40:10,900 --> 00:40:14,410 If I now run this program, though, unfortunately, there's 839 00:40:14,410 --> 00:40:16,480 a little bit of a bug. 840 00:40:16,480 --> 00:40:20,950 Even if I type in David and Carter and Rongshin, 841 00:40:20,950 --> 00:40:25,420 I'm not going to get just three name tags. 842 00:40:25,420 --> 00:40:29,680 In your mind, does anyone see the bug I'm about to trip over? 843 00:40:29,680 --> 00:40:34,360 It's not a huge deal if I've got enough name tags to go around. 844 00:40:34,360 --> 00:40:36,220 But I'm going to be wasting one because this 845 00:40:36,220 --> 00:40:40,660 is going to print not three, but four name tags, whereby, the first contains 846 00:40:40,660 --> 00:40:42,160 the name of the program itself. 847 00:40:42,160 --> 00:40:43,210 Maybe not a big deal. 848 00:40:43,210 --> 00:40:46,210 Maybe that's the sticker we don't bother handing out, but it's wasteful. 849 00:40:46,210 --> 00:40:47,630 And it does look wrong. 850 00:40:47,630 --> 00:40:52,270 So how could we get access to not all four elements of argv 851 00:40:52,270 --> 00:40:54,580 but just a slice of argv? 852 00:40:54,580 --> 00:40:58,210 And this is actually a technical term in Python and some other languages. 853 00:40:58,210 --> 00:41:01,960 To take a slice of a list means to take a subset of it 854 00:41:01,960 --> 00:41:04,690 maybe from the beginning, maybe the middle, maybe the end. 855 00:41:04,690 --> 00:41:08,710 But a slice is a subset of a data structure like a list. 856 00:41:08,710 --> 00:41:10,870 Well, how do I actually do this in code? 857 00:41:10,870 --> 00:41:14,020 Well, in Python, it's actually very easy to take a slice 858 00:41:14,020 --> 00:41:16,000 of a list that is a subset thereof. 859 00:41:16,000 --> 00:41:17,500 You can simply do this. 860 00:41:17,500 --> 00:41:22,480 At the end of the list name, sys.argv in this case, you can use square brackets. 861 00:41:22,480 --> 00:41:24,250 And then in those square brackets, you can 862 00:41:24,250 --> 00:41:29,320 specify the start and the end of the list that you want to retain. 863 00:41:29,320 --> 00:41:32,800 I want to start at element1, not zero. 864 00:41:32,800 --> 00:41:36,155 I want to start at element1, and I want to just go to the end. 865 00:41:36,155 --> 00:41:38,530 So I'm actually going to omit a second number altogether. 866 00:41:38,530 --> 00:41:40,690 It's not necessary to have a second number. 867 00:41:40,690 --> 00:41:44,593 But I do need that colon because this is going to give me a slice of the list. 868 00:41:44,593 --> 00:41:46,510 It's going to give me a slice of the list that 869 00:41:46,510 --> 00:41:48,970 starts at location1, not zero. 870 00:41:48,970 --> 00:41:51,280 And the colon and then a blank just means 871 00:41:51,280 --> 00:41:52,910 it's going to give me everything else. 872 00:41:52,910 --> 00:41:56,620 So this is in equivalently going to slice off the first element of the list 873 00:41:56,620 --> 00:42:00,700 and give me a new list that contains just those three human names, not 874 00:42:00,700 --> 00:42:02,140 the name of the file itself. 875 00:42:02,140 --> 00:42:03,730 Let me try running this again. 876 00:42:03,730 --> 00:42:07,840 I'm going to run Python of name.py, David Carter Rongshin. 877 00:42:07,840 --> 00:42:11,620 This time hopefully, I'm going to get three and only three name tags, 878 00:42:11,620 --> 00:42:12,490 hitting Enter. 879 00:42:12,490 --> 00:42:15,100 And indeed, I've done now just this. 880 00:42:15,100 --> 00:42:18,460 So again, using some relatively simple syntax in Python, 881 00:42:18,460 --> 00:42:22,420 we can use square brackets not just to go to specific elements like bracket0 882 00:42:22,420 --> 00:42:23,380 or bracket1. 883 00:42:23,380 --> 00:42:26,710 We can also get subsets of the list, slices of the list 884 00:42:26,710 --> 00:42:30,490 by doing bracket something colon something where each of those 885 00:42:30,490 --> 00:42:32,695 some things is a number, the beginning or the end, 886 00:42:32,695 --> 00:42:34,570 and they're optional depending on whether you 887 00:42:34,570 --> 00:42:37,480 want all of them or just some. 888 00:42:37,480 --> 00:42:42,850 Any questions now on this version, which adds the loop and these slices 889 00:42:42,850 --> 00:42:45,172 with that new syntax? 890 00:42:45,172 --> 00:42:50,145 AUDIENCE: Can we slice starting from the end of the argument-- argument vector? 891 00:42:50,145 --> 00:42:51,360 DAVID MALAN: You can. 892 00:42:51,360 --> 00:42:54,030 You can slice something from the end of the argument vector. 893 00:42:54,030 --> 00:42:57,340 And this might blow one's mind a little bit. 894 00:42:57,340 --> 00:43:00,370 Let me go ahead and do this. 895 00:43:00,370 --> 00:43:00,990 Let's see. 896 00:43:00,990 --> 00:43:03,210 Let me go ahead and do negative one at the end. 897 00:43:03,210 --> 00:43:06,000 Using a negative number here and running the same command, 898 00:43:06,000 --> 00:43:10,150 we've just uninvited Rongshin from receiving a name tag here. 899 00:43:10,150 --> 00:43:12,780 So if you use a negative number, it has the effect 900 00:43:12,780 --> 00:43:17,203 of counting in the other direction from the end of the list. 901 00:43:17,203 --> 00:43:18,120 A good question there. 902 00:43:18,120 --> 00:43:23,737 Other questions now on slices, on looping over sys.argv? 903 00:43:23,737 --> 00:43:26,760 AUDIENCE: Hi, so I remember very early on when 904 00:43:26,760 --> 00:43:31,695 we were talking about only having two decimal places in float value. 905 00:43:31,695 --> 00:43:34,590 906 00:43:34,590 --> 00:43:39,390 Is that in the same vein, like, because we use the code on 0.2F? 907 00:43:39,390 --> 00:43:42,060 908 00:43:42,060 --> 00:43:44,010 Is that the same thing then? 909 00:43:44,010 --> 00:43:50,220 Why would the F be included then in the 0.2F as opposed to here when you just 910 00:43:50,220 --> 00:43:51,905 have the numbers? 911 00:43:51,905 --> 00:43:53,500 DAVID MALAN: A really good question. 912 00:43:53,500 --> 00:43:56,180 And it's just the short answer's that context matters. 913 00:43:56,180 --> 00:43:59,630 So there's only so many keys on our keyboard. 914 00:43:59,630 --> 00:44:02,630 And so we sometimes use the same symbols for different things. 915 00:44:02,630 --> 00:44:05,710 So what you're alluding to is the format code 916 00:44:05,710 --> 00:44:10,570 in an F string for actually formatting a number using a colon, using a period, 917 00:44:10,570 --> 00:44:13,130 using a number, using the letter F and so forth. 918 00:44:13,130 --> 00:44:16,990 And that is very specific to the F string feature of Python. 919 00:44:16,990 --> 00:44:20,500 This case has nothing to do with any of that syntax per se. 920 00:44:20,500 --> 00:44:22,990 This is just using a colon in a different context 921 00:44:22,990 --> 00:44:25,300 to solve this problem to implement a slice. 922 00:44:25,300 --> 00:44:28,060 The authors of Python could have chosen another symbol. 923 00:44:28,060 --> 00:44:29,980 But honestly looking down at my keyboard here, 924 00:44:29,980 --> 00:44:32,560 we don't have that many to choose from that are easy to type. 925 00:44:32,560 --> 00:44:34,480 So sometimes they have different meanings. 926 00:44:34,480 --> 00:44:36,400 A good question as well. 927 00:44:36,400 --> 00:44:39,490 Allow me to propose now, that we take things further 928 00:44:39,490 --> 00:44:43,990 and move away from using only those modules, those libraries that Python 929 00:44:43,990 --> 00:44:47,740 comes with to talk about more generally packages that exist. 930 00:44:47,740 --> 00:44:51,460 One of the reasons that Python is so popular and powerful these days 931 00:44:51,460 --> 00:44:54,070 is that there's a lot of third-party libraries 932 00:44:54,070 --> 00:44:56,830 out there as well, otherwise known as packages. 933 00:44:56,830 --> 00:45:01,120 Strictly speaking, Python itself has a term of art 934 00:45:01,120 --> 00:45:04,690 called a package, which is a module essentially 935 00:45:04,690 --> 00:45:08,170 that's implemented in a folder, not just a file but a folder. 936 00:45:08,170 --> 00:45:12,685 But more generally, a package is a third-party library that you, 937 00:45:12,685 --> 00:45:16,780 that I can install on our own Mac or PC or our cloud server 938 00:45:16,780 --> 00:45:19,240 and gain access to even more functionality 939 00:45:19,240 --> 00:45:21,760 that other people have implemented for us. 940 00:45:21,760 --> 00:45:24,790 Now, one of the locations you can get all of these packages 941 00:45:24,790 --> 00:45:30,940 is called the PYTI website, the Python Package Index which lives at this URL 942 00:45:30,940 --> 00:45:31,450 here. 943 00:45:31,450 --> 00:45:34,450 And this is a website that is searchable via the command line, 944 00:45:34,450 --> 00:45:37,900 as well as via the web, that allows you to download and install 945 00:45:37,900 --> 00:45:39,340 all sorts of packages. 946 00:45:39,340 --> 00:45:43,522 Even CS50 has some of its own packages in services like these. 947 00:45:43,522 --> 00:45:46,480 Now, there's a fun one out there that's a throwback to a command that's 948 00:45:46,480 --> 00:45:49,930 been around for years in command line environments called cowsay. 949 00:45:49,930 --> 00:45:55,030 Cowsay is a package in Python that allows you to have a cow say something 950 00:45:55,030 --> 00:45:56,240 on your screen. 951 00:45:56,240 --> 00:45:58,870 If curious to read up on it, its own documentation 952 00:45:58,870 --> 00:46:02,560 is on pi.py.org specifically at this URL here. 953 00:46:02,560 --> 00:46:06,100 But how do you actually get the package into your system? 954 00:46:06,100 --> 00:46:09,400 Well, technically, you could figure out how to download the file 955 00:46:09,400 --> 00:46:13,300 and maybe unzip it and put it into the right location on your Mac or PC. 956 00:46:13,300 --> 00:46:15,880 But nowadays, a lot of languages, Python among them, 957 00:46:15,880 --> 00:46:18,220 has what's called its own package manager. 958 00:46:18,220 --> 00:46:20,530 This one here called pip which is just one. 959 00:46:20,530 --> 00:46:25,930 So pip is a program that generally comes with Python itself, nowadays, 960 00:46:25,930 --> 00:46:29,710 that allows you to install packages onto your own Macs or PCs 961 00:46:29,710 --> 00:46:32,380 or cloud environment by just running a command. 962 00:46:32,380 --> 00:46:36,700 And then voila, you have access to a whole new library in Python 963 00:46:36,700 --> 00:46:38,480 that didn't come with Python itself. 964 00:46:38,480 --> 00:46:41,990 But now it's available on your system for you. 965 00:46:41,990 --> 00:46:43,360 Let's go back to VS Code here. 966 00:46:43,360 --> 00:46:48,010 And in my terminal window, I'm going to go ahead and type pip install cowsay. 967 00:46:48,010 --> 00:46:49,330 Now, what's going on here? 968 00:46:49,330 --> 00:46:51,370 Pip is the command, the package manager. 969 00:46:51,370 --> 00:46:53,650 And I want to install what package? 970 00:46:53,650 --> 00:46:55,090 The package called cowsay. 971 00:46:55,090 --> 00:46:56,830 I'm going to go ahead and hit Enter here. 972 00:46:56,830 --> 00:47:00,910 And after a little bit of output, it has successfully installed cowsay. 973 00:47:00,910 --> 00:47:01,970 Now, what does that mean? 974 00:47:01,970 --> 00:47:05,710 That means I can now go about importing this into my own code. 975 00:47:05,710 --> 00:47:07,720 Well, let's go ahead and see what this means. 976 00:47:07,720 --> 00:47:11,200 So let me go ahead and create a new file with code called say.py 977 00:47:11,200 --> 00:47:13,420 because I want something to be said on the screen. 978 00:47:13,420 --> 00:47:17,290 And in my new tab here, I'm going to go ahead and import cowsay, 979 00:47:17,290 --> 00:47:19,630 which presumably is now installed. 980 00:47:19,630 --> 00:47:22,360 I'm now going to import sys as well because I'd 981 00:47:22,360 --> 00:47:25,060 like to use some command line arguments in this program 982 00:47:25,060 --> 00:47:26,560 just so that I can run it quickly. 983 00:47:26,560 --> 00:47:30,220 And without using the input function, I can get the user's name 984 00:47:30,220 --> 00:47:31,720 immediately from the prompt. 985 00:47:31,720 --> 00:47:33,170 And let me go ahead and do this. 986 00:47:33,170 --> 00:47:35,800 I'm going to do a bit of error checking proactively this time. 987 00:47:35,800 --> 00:47:37,930 And rather than use less than or greater than, I'm 988 00:47:37,930 --> 00:47:43,600 this time going to say if the length of sys.argv does equal 2. 989 00:47:43,600 --> 00:47:45,730 So if the human is provided just the name 990 00:47:45,730 --> 00:47:49,460 of the program and their own first name, we're good to go. 991 00:47:49,460 --> 00:47:51,170 I'm going to do the following. 992 00:47:51,170 --> 00:47:56,980 I'm going to call a function called COW in the package called cowsay. 993 00:47:56,980 --> 00:48:00,700 And I'm going to pass in a string, hello, comma. 994 00:48:00,700 --> 00:48:03,750 And then as in the past, I'm going to pass in just one string 995 00:48:03,750 --> 00:48:06,250 because according to its documentation, it's not like print. 996 00:48:06,250 --> 00:48:08,170 I can't pass in comma this, comma that. 997 00:48:08,170 --> 00:48:09,740 I can only pass in one string. 998 00:48:09,740 --> 00:48:14,320 So I'm going to concatenate it the contents of sys.argv, bracket1. 999 00:48:14,320 --> 00:48:20,360 So long as then I type in my name David after the name of this program, 1000 00:48:20,360 --> 00:48:24,670 it should end up in sys.argv1 in which case, this line five of code 1001 00:48:24,670 --> 00:48:28,090 should concatenate hello with my name with a space in between. 1002 00:48:28,090 --> 00:48:30,500 And apparently, a cow is going to say it. 1003 00:48:30,500 --> 00:48:32,470 So let's see what happens here. 1004 00:48:32,470 --> 00:48:35,110 Let me go ahead and clear my screen and increase 1005 00:48:35,110 --> 00:48:36,830 the size of my terminal window. 1006 00:48:36,830 --> 00:48:42,760 Let me go ahead and run Python of say.py and type my name David and Enter. 1007 00:48:42,760 --> 00:48:44,800 There is the program called cowsay. 1008 00:48:44,800 --> 00:48:47,590 It literally has a cow say something on the screen. 1009 00:48:47,590 --> 00:48:50,080 And this is a throwback to a program from yesteryear 1010 00:48:50,080 --> 00:48:53,020 that tended to come with a lot of systems. 1011 00:48:53,020 --> 00:48:55,180 This is otherwise known as ASCII art. 1012 00:48:55,180 --> 00:48:57,760 It's a textual way using just keys on your keyboard 1013 00:48:57,760 --> 00:49:00,610 to print pictures of sorts on the screen. 1014 00:49:00,610 --> 00:49:02,980 Now, we can really go down the rabbit hole here. 1015 00:49:02,980 --> 00:49:05,260 And there's questionable academic value of doing so. 1016 00:49:05,260 --> 00:49:06,490 So I'll do so just once. 1017 00:49:06,490 --> 00:49:10,520 Turns out the cowsay package comes with other functions as well. 1018 00:49:10,520 --> 00:49:13,360 One of those functions, for instance, is T-Rex. 1019 00:49:13,360 --> 00:49:16,073 And if I now increase the size of my terminal window, 1020 00:49:16,073 --> 00:49:17,990 we'll perhaps see where we're going with this. 1021 00:49:17,990 --> 00:49:20,230 Let me now run again, Python of say.py. 1022 00:49:20,230 --> 00:49:23,380 This time, let me not provide my name just to see if it's broken. 1023 00:49:23,380 --> 00:49:26,410 It's still OK because we have that if condition 1024 00:49:26,410 --> 00:49:31,870 if the length of sys.argv equals equals 2 and only if it equals equals 2, 1025 00:49:31,870 --> 00:49:32,960 do we do anything. 1026 00:49:32,960 --> 00:49:34,780 That's why we're not seeing anything here. 1027 00:49:34,780 --> 00:49:38,620 Let me go ahead and cooperate now, say.py space David. 1028 00:49:38,620 --> 00:49:40,360 And it's no longer a cow. 1029 00:49:40,360 --> 00:49:44,260 But if I zoom out on my screen, a T-Rex. 1030 00:49:44,260 --> 00:49:45,190 Why? 1031 00:49:45,190 --> 00:49:48,430 Just because these are the things you can do once you know how to program. 1032 00:49:48,430 --> 00:49:51,305 You can even package them up and make them freely available to others 1033 00:49:51,305 --> 00:49:52,600 as open source software. 1034 00:49:52,600 --> 00:49:56,590 For us, it's demonstrative of a feature more generally here 1035 00:49:56,590 --> 00:49:59,710 namely being able to install these third-party packages and how 1036 00:49:59,710 --> 00:50:01,437 you might do so in Python. 1037 00:50:01,437 --> 00:50:03,520 Now, I'll leave this up on the screen for a moment 1038 00:50:03,520 --> 00:50:06,070 and see if there's any questions about cows 1039 00:50:06,070 --> 00:50:11,090 or Tyrannosaurus rex's or packages more generally. 1040 00:50:11,090 --> 00:50:14,570 I'm really qualified to speak to just one of those. 1041 00:50:14,570 --> 00:50:19,130 AUDIENCE: Hi, I've got two questions it's a bit earlier than what's 1042 00:50:19,130 --> 00:50:20,940 supposed to be. 1043 00:50:20,940 --> 00:50:25,430 So the first question is the packages that you're 1044 00:50:25,430 --> 00:50:32,990 calling to use in the program, are they the same 1045 00:50:32,990 --> 00:50:42,680 as, let's say, something Java the same as calling a class, a Java file 1046 00:50:42,680 --> 00:50:45,950 in order to use its functions? 1047 00:50:45,950 --> 00:50:52,250 And my second question is, what's the actual purpose of using command line 1048 00:50:52,250 --> 00:51:00,350 arguments as you used because is not really the best way to, as you say, 1049 00:51:00,350 --> 00:51:06,470 be user friendly where as in let's say the person who's 1050 00:51:06,470 --> 00:51:10,340 using the program doesn't know what they want-- 1051 00:51:10,340 --> 00:51:12,140 what the program's asking them? 1052 00:51:12,140 --> 00:51:13,710 DAVID MALAN: Really good question. 1053 00:51:13,710 --> 00:51:17,060 The first question about the comparison with Java, Python packages 1054 00:51:17,060 --> 00:51:20,932 are similar to Java packages where you have something.something.something 1055 00:51:20,932 --> 00:51:22,640 at the top of your program that gives you 1056 00:51:22,640 --> 00:51:24,650 access to a class or something else. 1057 00:51:24,650 --> 00:51:26,600 Python itself supports classes. 1058 00:51:26,600 --> 00:51:27,890 More on those down the road. 1059 00:51:27,890 --> 00:51:32,120 And you can do very similar things in Python as you can do with Java. 1060 00:51:32,120 --> 00:51:36,350 But the analog really is Python packages to Java packages here. 1061 00:51:36,350 --> 00:51:39,380 As for command line arguments, you ask a good question. 1062 00:51:39,380 --> 00:51:42,830 Why do we use them, especially if they are literally user friendly? 1063 00:51:42,830 --> 00:51:45,440 They're a little less user friendly to people 1064 00:51:45,440 --> 00:51:47,540 who aren't in this Zoom to be honest. 1065 00:51:47,540 --> 00:51:50,270 You and I as we learn more and more about programming 1066 00:51:50,270 --> 00:51:52,430 and more about command line arguments, I daresay 1067 00:51:52,430 --> 00:51:54,800 we'll become more comfortable with and tend 1068 00:51:54,800 --> 00:51:58,560 to prefer the ability to customize commands using these command line 1069 00:51:58,560 --> 00:51:59,060 arguments. 1070 00:51:59,060 --> 00:51:59,560 Why? 1071 00:51:59,560 --> 00:52:00,388 Productivity. 1072 00:52:00,388 --> 00:52:02,180 It tends to make you faster because you get 1073 00:52:02,180 --> 00:52:03,980 into the habit of knowing exactly how you 1074 00:52:03,980 --> 00:52:07,640 can configure your software without having to manually answer questions. 1075 00:52:07,640 --> 00:52:08,690 And case in point. 1076 00:52:08,690 --> 00:52:13,760 All of this time have we been running Python of something.py. 1077 00:52:13,760 --> 00:52:15,560 You could imagine not doing that. 1078 00:52:15,560 --> 00:52:18,060 You can imagine typing only Python, hitting Enter. 1079 00:52:18,060 --> 00:52:20,810 And then you're prompted for the name of the file you want to run. 1080 00:52:20,810 --> 00:52:23,210 So you type in something.py, and then it runs. 1081 00:52:23,210 --> 00:52:26,240 Not a big deal, but I would argue that over time, you're 1082 00:52:26,240 --> 00:52:28,100 going to get a little tired of that TDM. 1083 00:52:28,100 --> 00:52:29,870 And you would much prefer to just automate 1084 00:52:29,870 --> 00:52:33,260 the command again and again and again, especially with little conveniences 1085 00:52:33,260 --> 00:52:36,470 like being able to hit up and down in your keyboard history 1086 00:52:36,470 --> 00:52:38,300 so as to rerun those same command. 1087 00:52:38,300 --> 00:52:41,600 Automation is big too if you emerge from a class like this 1088 00:52:41,600 --> 00:52:44,720 and start using Python to automate processes 1089 00:52:44,720 --> 00:52:46,670 at work or for personal projects or the like, 1090 00:52:46,670 --> 00:52:49,370 the ability to specify all of your inputs on the one line 1091 00:52:49,370 --> 00:52:51,750 just means you can get work done more quickly. 1092 00:52:51,750 --> 00:52:53,810 So hands down, absolutely. 1093 00:52:53,810 --> 00:52:58,400 Using command line arguments is a more arcane feature of systems 1094 00:52:58,400 --> 00:53:01,130 that most of us are no longer as familiar with because 1095 00:53:01,130 --> 00:53:03,740 of Windows and Mac OS and other operating systems that 1096 00:53:03,740 --> 00:53:05,360 have buttons and GUIs and menus. 1097 00:53:05,360 --> 00:53:08,280 But the more comfortable you get with programming, 1098 00:53:08,280 --> 00:53:12,170 I daresay the more you will tend to prefer these capabilities because they 1099 00:53:12,170 --> 00:53:15,010 allow you to do things more quickly. 1100 00:53:15,010 --> 00:53:19,510 With that said, allow me to propose that we take a turn toward, yet, 1101 00:53:19,510 --> 00:53:23,890 another package that's particularly popular and just as easy 1102 00:53:23,890 --> 00:53:27,100 to install all toward an end of using APIs. 1103 00:53:27,100 --> 00:53:29,980 Now, APIs are not something that's Python-specific. 1104 00:53:29,980 --> 00:53:33,790 More generally, an API is an application programming interface. 1105 00:53:33,790 --> 00:53:37,330 And it can refer to Python files and functions. 1106 00:53:37,330 --> 00:53:41,020 But often, APIs really refer to third-party services 1107 00:53:41,020 --> 00:53:44,050 that you and I can write code that talk to. 1108 00:53:44,050 --> 00:53:47,680 Many APIs, but not all, live on the internet these days 1109 00:53:47,680 --> 00:53:50,080 so that so long as you have a browser or so long 1110 00:53:50,080 --> 00:53:53,290 as you have some experience with Python programming or programming 1111 00:53:53,290 --> 00:53:58,240 in any language, you can write code that in effect pretends to be a browser, 1112 00:53:58,240 --> 00:54:01,750 connects to that third-party API on a server, 1113 00:54:01,750 --> 00:54:05,740 and download some data that you can then incorporate into your own program. 1114 00:54:05,740 --> 00:54:07,130 Now, how do you do this? 1115 00:54:07,130 --> 00:54:10,000 Well, Python has a very popular package that you 1116 00:54:10,000 --> 00:54:12,730 can install via pip called requests. 1117 00:54:12,730 --> 00:54:16,360 The requests library allows you to make web request, 1118 00:54:16,360 --> 00:54:20,110 internet request using Python code essentially 1119 00:54:20,110 --> 00:54:22,690 as though you were a browser yourself. 1120 00:54:22,690 --> 00:54:25,510 You can automate, therefore, the retrieval of URLs 1121 00:54:25,510 --> 00:54:28,510 that start with HTTP or HTTPS. 1122 00:54:28,510 --> 00:54:31,240 The documentation for this library is that a URL like this, 1123 00:54:31,240 --> 00:54:33,320 but it too can be installed at the command line. 1124 00:54:33,320 --> 00:54:35,070 And even though it's third party, it's one 1125 00:54:35,070 --> 00:54:38,380 of the most popular and commonly used packages out there in Python. 1126 00:54:38,380 --> 00:54:42,790 And this too is one of the reasons again that Python is so popular. 1127 00:54:42,790 --> 00:54:44,890 There's just so many solutions to problems 1128 00:54:44,890 --> 00:54:47,710 that you and I have or are invariably going to have 1129 00:54:47,710 --> 00:54:49,570 when we write projects of our own. 1130 00:54:49,570 --> 00:54:53,440 There's just a really vibrant ecosystem, a really vibrant community 1131 00:54:53,440 --> 00:54:57,160 of open source software that's that easy for us to install. 1132 00:54:57,160 --> 00:54:59,170 Let me go back to my terminal window now and run 1133 00:54:59,170 --> 00:55:03,310 pip install requests in order to install this package on my own system. 1134 00:55:03,310 --> 00:55:06,890 And after some lines of output, I'll see that it's successfully installed. 1135 00:55:06,890 --> 00:55:09,130 Now, let's go ahead and create a new file here. 1136 00:55:09,130 --> 00:55:11,710 For instance, itunes.py. 1137 00:55:11,710 --> 00:55:15,152 It turns out that Apple has its own API for their iTunes service. 1138 00:55:15,152 --> 00:55:17,110 The software that provides you with the ability 1139 00:55:17,110 --> 00:55:20,510 to download and search for music and songs and other information as well. 1140 00:55:20,510 --> 00:55:23,290 And it turns out that-- let me go back over to my computer 1141 00:55:23,290 --> 00:55:25,480 here and open up a browser like Chrome. 1142 00:55:25,480 --> 00:55:27,940 And let me go ahead and visit this URL here, 1143 00:55:27,940 --> 00:55:32,240 https://itunes.apple.com/ search?entity=song&limit=1&term=weezer. 1144 00:55:32,240 --> 00:55:39,790 Search?entity=song& limit=1&term=weezer. 1145 00:55:39,790 --> 00:55:42,610 Now, I constructed this URL manually by reading 1146 00:55:42,610 --> 00:55:44,950 the documentation for Apple's API-- 1147 00:55:44,950 --> 00:55:47,320 application programming interface for iTune. 1148 00:55:47,320 --> 00:55:51,550 And what they told me is that if I want to search for information about songs 1149 00:55:51,550 --> 00:55:54,160 in their database, I should specify entity 1150 00:55:54,160 --> 00:55:58,000 equals song so that songs and not albums or artists or something like that. 1151 00:55:58,000 --> 00:56:00,430 If I just want to get back information on one song, 1152 00:56:00,430 --> 00:56:02,350 I'm going to provide limit equals 1. 1153 00:56:02,350 --> 00:56:05,410 And if the band I want to search for, the artist is Weezer, 1154 00:56:05,410 --> 00:56:07,870 I should specify term equals Weezer. 1155 00:56:07,870 --> 00:56:11,830 So with this, if I go ahead and hit Enter and visit this URL, 1156 00:56:11,830 --> 00:56:15,370 I actually end up with a text file in my Downloads folder on my Mac. 1157 00:56:15,370 --> 00:56:18,310 If I go ahead and open that text file that my browser just downloaded, 1158 00:56:18,310 --> 00:56:20,620 we'll see all of this text here, which at first glance 1159 00:56:20,620 --> 00:56:23,840 might look a bit cryptic, but it actually follows a pattern. 1160 00:56:23,840 --> 00:56:26,590 Notice this curly brace at the start and notice this 1161 00:56:26,590 --> 00:56:28,400 closed curly brace at the end. 1162 00:56:28,400 --> 00:56:32,800 Notice this open square bracket here and notice this closed square bracket here. 1163 00:56:32,800 --> 00:56:35,800 And in between those pieces of syntax are 1164 00:56:35,800 --> 00:56:37,850 a whole bunch of strings and values. 1165 00:56:37,850 --> 00:56:40,120 In fact, a whole bunch of key value pairs. 1166 00:56:40,120 --> 00:56:43,630 What we're looking at here is a standard text format known as JSON-- 1167 00:56:43,630 --> 00:56:47,530 JavaScript Object Notation, which yes, is technically related to yet, 1168 00:56:47,530 --> 00:56:49,660 another programming language called JavaScript. 1169 00:56:49,660 --> 00:56:52,690 But JSON itself is typically used nowadays 1170 00:56:52,690 --> 00:56:57,970 as a language agnostic format for exchanging data between computers. 1171 00:56:57,970 --> 00:57:00,940 By language agnostic, I mean you don't have to use JavaScript. 1172 00:57:00,940 --> 00:57:05,140 You can use Python or any other language to read JSON or write it as well. 1173 00:57:05,140 --> 00:57:07,510 And it's a completely text-based format, which 1174 00:57:07,510 --> 00:57:11,380 means that if I visit that URL with my browser, what gets downloaded 1175 00:57:11,380 --> 00:57:12,640 is just a bunch of text. 1176 00:57:12,640 --> 00:57:16,900 But that text is formatted in a standard way using curly braces 1177 00:57:16,900 --> 00:57:21,670 and square bracket using quotes and some colons that ultimately contains 1178 00:57:21,670 --> 00:57:25,960 all of the information in Apple's database on Weezer's song, at least, 1179 00:57:25,960 --> 00:57:29,230 the first one because I limited it to one in their database. 1180 00:57:29,230 --> 00:57:32,020 And that's an API, an application programming interface. 1181 00:57:32,020 --> 00:57:35,920 A mechanism whereby I can access data on someone else's server 1182 00:57:35,920 --> 00:57:39,370 and somehow integrate it into my own program. 1183 00:57:39,370 --> 00:57:42,410 Now, of course, my browser, Chrome, is not something I wrote. 1184 00:57:42,410 --> 00:57:45,340 I should actually write some Python code that perhaps pretends 1185 00:57:45,340 --> 00:57:47,870 to be a browser to grab this same data. 1186 00:57:47,870 --> 00:57:48,920 So let's do that. 1187 00:57:48,920 --> 00:57:50,230 Let me go back to VS Code here. 1188 00:57:50,230 --> 00:57:53,680 And let me write a program with code, itunes.py. 1189 00:57:53,680 --> 00:57:59,050 And we're going to write some code via which I can then use the iTunes API 1190 00:57:59,050 --> 00:58:03,700 and in turn, Python to get information about any band that I might want. 1191 00:58:03,700 --> 00:58:06,760 I'm going to go here and import first the requests 1192 00:58:06,760 --> 00:58:11,410 library, which I installed earlier in order to make those HTTP requests. 1193 00:58:11,410 --> 00:58:15,420 I'm going to go ahead and import the sys library via which I'll have the ability 1194 00:58:15,420 --> 00:58:18,750 to use command line arguments like specification of the band 1195 00:58:18,750 --> 00:58:20,730 that I want to search for if not Weezer. 1196 00:58:20,730 --> 00:58:24,960 And then down here, I'm going to go ahead and insert some error checking 1197 00:58:24,960 --> 00:58:30,330 to say if the length of sys.argv does not equal to-- 1198 00:58:30,330 --> 00:58:33,060 so if the user does not provide me with the name of the file 1199 00:58:33,060 --> 00:58:36,990 they want to run and the name of a band, and that's it, you know what. 1200 00:58:36,990 --> 00:58:39,510 Let's just go ahead and exit for now. 1201 00:58:39,510 --> 00:58:41,470 I could provide a more explanatory message. 1202 00:58:41,470 --> 00:58:43,303 But for now, I'm going to keep things simple 1203 00:58:43,303 --> 00:58:46,890 and just exit the program prematurely so that I can trust hereafter 1204 00:58:46,890 --> 00:58:49,500 that sys.argv has what I want. 1205 00:58:49,500 --> 00:58:54,000 And now, I have the opportunity to use the requests library to write 1206 00:58:54,000 --> 00:58:56,640 some Python code that effectively is pretending 1207 00:58:56,640 --> 00:59:00,840 to be a web browser so as to connect to that same HTTPS 1208 00:59:00,840 --> 00:59:03,400 URL on Apple's own server. 1209 00:59:03,400 --> 00:59:06,090 So now that I've guaranteed that the user has typed in 1210 00:59:06,090 --> 00:59:10,170 not just the name of the file, but also the name of a band at the prompt 1211 00:59:10,170 --> 00:59:13,530 giving me a length of two for sys.argv, let's go ahead 1212 00:59:13,530 --> 00:59:18,300 and execute request stockget, which is a function inside of the request package 1213 00:59:18,300 --> 00:59:21,030 that will literally get some response from a server. 1214 00:59:21,030 --> 00:59:24,210 And the URL that I want to get is the exactly the same as before. 1215 00:59:24,210 --> 00:59:33,885 https://itunes.apple.com/ search?entity=song& limit=1& 1216 00:59:33,885 --> 00:59:36,750 term=previouslyweezer. 1217 00:59:36,750 --> 00:59:39,090 But let's make this program a little interactive 1218 00:59:39,090 --> 00:59:42,930 and actually allow the human to specify at the command line what 1219 00:59:42,930 --> 00:59:44,770 artists they'd like to search for. 1220 00:59:44,770 --> 00:59:47,940 So I'm going to go ahead and close my quote early and just 1221 00:59:47,940 --> 00:59:54,480 append using the concatenation operator as in the past, sys.argv bracket1. 1222 00:59:54,480 --> 00:59:57,360 And now, it actually be nice to store the response 1223 00:59:57,360 --> 00:59:59,020 from the server in a variable. 1224 00:59:59,020 --> 01:00:01,830 So I'm going to go ahead and say response equals 1225 01:00:01,830 --> 01:00:04,020 and to store all of the response that comes back 1226 01:00:04,020 --> 01:00:06,120 from the server in a variable called response. 1227 01:00:06,120 --> 01:00:08,670 Down here now, I'd like to just understand 1228 01:00:08,670 --> 01:00:12,420 what the server's returning to me to make sure I know how next to proceed. 1229 01:00:12,420 --> 01:00:14,170 So this isn't going to be very pretty yet. 1230 01:00:14,170 --> 01:00:17,220 But I'm going to go and print out response.json, 1231 01:00:17,220 --> 01:00:21,270 which ensures that the data I'm getting back is formatted on my screen 1232 01:00:21,270 --> 01:00:25,980 as exactly that, JSON, the same text format as we saw on my screen. 1233 01:00:25,980 --> 01:00:27,510 It's not a useful program yet. 1234 01:00:27,510 --> 01:00:29,640 I'm really just learning along the way. 1235 01:00:29,640 --> 01:00:32,790 But let me go ahead now and increase the size of my terminal window 1236 01:00:32,790 --> 01:00:37,590 and run Python of itunes.py and type in the name of a band like Weezer 1237 01:00:37,590 --> 01:00:39,030 and hit Enter. 1238 01:00:39,030 --> 01:00:42,030 And what we see on the screen formatted almost the same 1239 01:00:42,030 --> 01:00:44,730 as before is exactly that same text. 1240 01:00:44,730 --> 01:00:48,240 But what you'll see here is that this has been standardized now 1241 01:00:48,240 --> 01:00:50,310 as a Python dictionary. 1242 01:00:50,310 --> 01:00:54,360 What indeed Apple's returning is technically a JSON response, 1243 01:00:54,360 --> 01:00:55,980 JavaScript Object Notation. 1244 01:00:55,980 --> 01:00:59,190 But Python, the request library is converting it 1245 01:00:59,190 --> 01:01:04,020 to a Python dictionary which happens to use wonderfully coincidentally, almost 1246 01:01:04,020 --> 01:01:05,130 the same syntax. 1247 01:01:05,130 --> 01:01:08,130 It uses curly braces to represent the dictionary here 1248 01:01:08,130 --> 01:01:10,920 and a close curly brace to represent the end of it here. 1249 01:01:10,920 --> 01:01:14,280 For any lists therein, it uses a square bracket here 1250 01:01:14,280 --> 01:01:16,560 and a closed square bracket down here. 1251 01:01:16,560 --> 01:01:20,640 It uses quotes-- single quotes in this case or equivalently double quotes 1252 01:01:20,640 --> 01:01:23,250 to represent the keys in that dictionary. 1253 01:01:23,250 --> 01:01:27,180 And after a colon, it stores the value of that key. 1254 01:01:27,180 --> 01:01:31,860 And so you'll see that indeed we have a result count key whose value is 1, 1255 01:01:31,860 --> 01:01:35,940 but then a more interesting Result key called results whose 1256 01:01:35,940 --> 01:01:38,940 value is this entire list of data. 1257 01:01:38,940 --> 01:01:41,377 Now, honestly, this is such a big blob of text 1258 01:01:41,377 --> 01:01:44,460 that it's going to take me forever to wrap my mind around what I'm seeing. 1259 01:01:44,460 --> 01:01:48,840 So let me propose temporarily we use another library in Python that 1260 01:01:48,840 --> 01:01:52,200 will allow me to format my data a little more cleanly. 1261 01:01:52,200 --> 01:01:56,460 It turns out that Python also comes with a special library called 1262 01:01:56,460 --> 01:01:59,400 JSON that allows you to manipulate JSON data 1263 01:01:59,400 --> 01:02:02,820 and even just printy print it that is formatted in a way that's going to be 1264 01:02:02,820 --> 01:02:04,900 way easier for you and I to understand. 1265 01:02:04,900 --> 01:02:07,260 So let me go back to my code here. 1266 01:02:07,260 --> 01:02:09,600 Let me shrink my terminal window. 1267 01:02:09,600 --> 01:02:13,210 And let me propose that just temporarily again we do this. 1268 01:02:13,210 --> 01:02:16,830 Let me import this additional library, JSON, which comes with Python. 1269 01:02:16,830 --> 01:02:19,140 So I don't need to install it manually with pip. 1270 01:02:19,140 --> 01:02:21,990 And let me go ahead now and not just print out 1271 01:02:21,990 --> 01:02:26,070 response.json which was that big blob of hard-to-understand text. 1272 01:02:26,070 --> 01:02:31,290 Let me go ahead and use one other function here called json.dumps 1273 01:02:31,290 --> 01:02:36,930 for dump string and pass to that function that response.json return 1274 01:02:36,930 --> 01:02:37,570 value. 1275 01:02:37,570 --> 01:02:39,780 So again, I'm just introducing another function 1276 01:02:39,780 --> 01:02:43,500 who I claim has a purpose in life of pretty printing, 1277 01:02:43,500 --> 01:02:46,560 nicely formatting on the screen the exact same information. 1278 01:02:46,560 --> 01:02:49,380 And I know this from the documentation having done this before. 1279 01:02:49,380 --> 01:02:51,540 But I'd like things to be nicely indented. 1280 01:02:51,540 --> 01:02:56,160 And according to the documentation, if I pass in a named parameter of indent 1281 01:02:56,160 --> 01:02:59,700 equals 2, that's going to indent everything at least two spaces. 1282 01:02:59,700 --> 01:03:01,170 I could do four or something else. 1283 01:03:01,170 --> 01:03:04,290 But it's going to be enough to help me wrap my mind around what 1284 01:03:04,290 --> 01:03:05,760 the data is I'm getting back. 1285 01:03:05,760 --> 01:03:08,250 Because again, I'm just learning along with you. 1286 01:03:08,250 --> 01:03:10,870 So let me increase the size of my terminal window again. 1287 01:03:10,870 --> 01:03:12,720 Let me run Python of itunes.py. 1288 01:03:12,720 --> 01:03:15,110 And again, let's search for Weezer and hit Enter. 1289 01:03:15,110 --> 01:03:18,440 And now, notice it's still a little bit cryptic 1290 01:03:18,440 --> 01:03:20,030 because there's a lot going on here. 1291 01:03:20,030 --> 01:03:24,110 But my gosh, I can totally read this more easily now. 1292 01:03:24,110 --> 01:03:27,860 Notice now that I still see the first curly brace, which means hey, 1293 01:03:27,860 --> 01:03:29,630 this is a dictionary in Python. 1294 01:03:29,630 --> 01:03:31,740 A collection of keys and values. 1295 01:03:31,740 --> 01:03:33,890 The first key is called result count. 1296 01:03:33,890 --> 01:03:35,895 It happens to be displayed in double quotes now. 1297 01:03:35,895 --> 01:03:37,520 But that's just an issue of formatting. 1298 01:03:37,520 --> 01:03:39,980 It could be double or single so long as we're consistent. 1299 01:03:39,980 --> 01:03:42,050 The value of that key is one. 1300 01:03:42,050 --> 01:03:42,560 Why? 1301 01:03:42,560 --> 01:03:46,670 Well, I told the URL to only limit the responses to one Weezer song 1302 01:03:46,670 --> 01:03:48,470 so I've gotten a result set of one. 1303 01:03:48,470 --> 01:03:51,260 If I increase that limit, I could probably get more. 1304 01:03:51,260 --> 01:03:55,010 Then the interesting part of this response is really the data itself. 1305 01:03:55,010 --> 01:03:59,690 Notice in the results key here, there's a really big value. 1306 01:03:59,690 --> 01:04:05,810 The value is a Python list as implied by this square bracket. 1307 01:04:05,810 --> 01:04:07,490 What does this list contain? 1308 01:04:07,490 --> 01:04:11,690 Well, I know from skimming it earlier that this contains one dictionary. 1309 01:04:11,690 --> 01:04:15,570 And that's why we see another curly brace here. 1310 01:04:15,570 --> 01:04:18,290 So again, if this gets a little more complicated, 1311 01:04:18,290 --> 01:04:22,770 keep in mind that a dictionary is just a collection of key value pairs. 1312 01:04:22,770 --> 01:04:25,730 And Python uses curly braces to indicate as much. 1313 01:04:25,730 --> 01:04:28,940 It is perfectly reasonable for a dictionary 1314 01:04:28,940 --> 01:04:33,680 to be inside of another dictionary if the value of some key itself 1315 01:04:33,680 --> 01:04:35,142 is another dictionary. 1316 01:04:35,142 --> 01:04:36,350 So this is a common paradigm. 1317 01:04:36,350 --> 01:04:38,183 And even though it might seem a bit cryptic, 1318 01:04:38,183 --> 01:04:42,590 it's just something that allows us to associate more keys with more value. 1319 01:04:42,590 --> 01:04:45,230 Now, most of this information, I probably don't care about. 1320 01:04:45,230 --> 01:04:48,920 For instance, according to Apple, the unique identifier for Weezer 1321 01:04:48,920 --> 01:04:52,310 is apparently 115,234. 1322 01:04:52,310 --> 01:04:54,655 That might be useful if I'm making my own database 1323 01:04:54,655 --> 01:04:56,030 and I want this to be searchable. 1324 01:04:56,030 --> 01:05:00,090 But for today's purposes, all I care about is the name of the track, 1325 01:05:00,090 --> 01:05:02,660 otherwise called track name as key. 1326 01:05:02,660 --> 01:05:05,810 And the first song and only song because we limited it to one 1327 01:05:05,810 --> 01:05:08,990 that we got back from iTunes here is the song 1328 01:05:08,990 --> 01:05:12,050 that you might know by Weezer called Say It Ain't So. 1329 01:05:12,050 --> 01:05:17,480 So now, I have a bit of a clue if my goal here is to implement a program 1330 01:05:17,480 --> 01:05:21,200 called itunes.py that doesn't just dump the response from the server, 1331 01:05:21,200 --> 01:05:22,730 which is admittedly very cryptic-- 1332 01:05:22,730 --> 01:05:28,040 but to print out all of the songs that iTunes has for the band called Weezer, 1333 01:05:28,040 --> 01:05:30,710 maybe I can iterate over this somehow. 1334 01:05:30,710 --> 01:05:31,940 So let me backtrack. 1335 01:05:31,940 --> 01:05:34,100 Here's the key call track name. 1336 01:05:34,100 --> 01:05:39,990 It is inside of a dictionary that is the value of results here. 1337 01:05:39,990 --> 01:05:42,270 So how can I go about getting this? 1338 01:05:42,270 --> 01:05:44,010 Well, let me go ahead and try this. 1339 01:05:44,010 --> 01:05:47,330 Let me go ahead and shrink my terminal window back down 1340 01:05:47,330 --> 01:05:49,760 and let me propose now for one final flourish. 1341 01:05:49,760 --> 01:05:52,040 We don't just lazily print out the contents 1342 01:05:52,040 --> 01:05:55,100 of that response because that's not interesting or pretty for anyone. 1343 01:05:55,100 --> 01:05:56,400 Let's do this. 1344 01:05:56,400 --> 01:05:58,580 Let me go ahead and create a new variable 1345 01:05:58,580 --> 01:06:01,310 just for the sake of discussion called O for object. 1346 01:06:01,310 --> 01:06:06,620 And I'm going to go ahead and call o equals response.json just 1347 01:06:06,620 --> 01:06:11,450 to store that JSON response specifically in a variable called o, 1348 01:06:11,450 --> 01:06:13,010 but I could name it anything I want. 1349 01:06:13,010 --> 01:06:14,600 And now, I'm going to do this. 1350 01:06:14,600 --> 01:06:21,440 For each result in that object's key called results, 1351 01:06:21,440 --> 01:06:26,180 go ahead and print out that result's track name. 1352 01:06:26,180 --> 01:06:29,450 And notice I have used exactly the same capitalization. 1353 01:06:29,450 --> 01:06:32,840 Track name has a capital N. Result is all lowercase. 1354 01:06:32,840 --> 01:06:35,300 And let me rewind before we run the actual program. 1355 01:06:35,300 --> 01:06:38,420 In line eight, we are making an HTTP request 1356 01:06:38,420 --> 01:06:41,780 using Python to the server just like you and I as humans type URLs 1357 01:06:41,780 --> 01:06:43,370 into a browser and hit Enter. 1358 01:06:43,370 --> 01:06:45,560 This is the Python equivalent thereof. 1359 01:06:45,560 --> 01:06:49,610 I am then on line 10 just grabbing from that variable that 1360 01:06:49,610 --> 01:06:53,900 contains the server's response, the JSON object that I care about. 1361 01:06:53,900 --> 01:06:57,960 The thing between those curly braces at the very top and the bottom. 1362 01:06:57,960 --> 01:07:00,320 But because we've poked around and because I 1363 01:07:00,320 --> 01:07:03,980 read the documentation earlier, I know that that object 1364 01:07:03,980 --> 01:07:06,150 has a key called results. 1365 01:07:06,150 --> 01:07:08,120 And that results key again is a list. 1366 01:07:08,120 --> 01:07:11,240 Now, at the moment, that list contains only one song, 1367 01:07:11,240 --> 01:07:14,360 Say It Ain't So, because I limited my response to one. 1368 01:07:14,360 --> 01:07:16,027 But even so, my loop will work. 1369 01:07:16,027 --> 01:07:17,360 It's just going to iterate once. 1370 01:07:17,360 --> 01:07:19,152 And each time through that loop, it's going 1371 01:07:19,152 --> 01:07:22,310 to print the current result's track name. 1372 01:07:22,310 --> 01:07:24,270 If I want to make this even more interesting, 1373 01:07:24,270 --> 01:07:26,180 let me change this limit now from 1 to 50 1374 01:07:26,180 --> 01:07:29,660 so I'll at least get back 50 track names instead. 1375 01:07:29,660 --> 01:07:33,080 Let me go ahead now and increase the size of my terminal once more 1376 01:07:33,080 --> 01:07:36,980 and go ahead now and run Python of itunes.py searching again 1377 01:07:36,980 --> 01:07:38,450 for a band like Weezer. 1378 01:07:38,450 --> 01:07:40,130 And here we go. 1379 01:07:40,130 --> 01:07:44,720 And voila, there are 50 songs that iTunes has for Weezer. 1380 01:07:44,720 --> 01:07:47,000 And if we scroll back up to the top here, 1381 01:07:47,000 --> 01:07:51,080 we'll see that the very first one there is, indeed, Say It Ain't So. 1382 01:07:51,080 --> 01:07:52,430 But now, we got Undone-- 1383 01:07:52,430 --> 01:07:54,110 The Sweater Song, Buddy Holly. 1384 01:07:54,110 --> 01:07:56,780 Apparently another rendition of Say It Ain't So perhaps 1385 01:07:56,780 --> 01:08:01,880 from another album, another Buddy Holly undone, my name is Jonas, and so forth. 1386 01:08:01,880 --> 01:08:06,920 Questions now on this program which integrates Python with a real world 1387 01:08:06,920 --> 01:08:10,301 third party API? 1388 01:08:10,301 --> 01:08:11,770 AUDIENCE: Yeah, hi. 1389 01:08:11,770 --> 01:08:15,040 Can we use break instead of system.exit? 1390 01:08:15,040 --> 01:08:16,870 DAVID MALAN: Good question, but no. 1391 01:08:16,870 --> 01:08:21,160 Break again is used to break out of things like loops like we saw earlier. 1392 01:08:21,160 --> 01:08:25,390 Sys.exit is used to break out of the whole program itself. 1393 01:08:25,390 --> 01:08:28,420 Use break for loops for now and use sys.exit to terminate 1394 01:08:28,420 --> 01:08:29,319 the whole program. 1395 01:08:29,319 --> 01:08:30,892 Good question. 1396 01:08:30,892 --> 01:08:32,850 Other questions now on this program are others? 1397 01:08:32,850 --> 01:08:36,600 AUDIENCE: From where we bring the name of the key results? 1398 01:08:36,600 --> 01:08:38,850 DAVID MALAN: From where do we get the name of the key? 1399 01:08:38,850 --> 01:08:40,350 AUDIENCE: Results itself. 1400 01:08:40,350 --> 01:08:42,670 Yeah, and can we change the results, the name? 1401 01:08:42,670 --> 01:08:43,890 DAVID MALAN: You cannot. 1402 01:08:43,890 --> 01:08:45,460 So we could in our program. 1403 01:08:45,460 --> 01:08:48,479 So the keys that come back in that JSON response, to be clear, 1404 01:08:48,479 --> 01:08:51,569 come from iTunes.Apple.com. 1405 01:08:51,569 --> 01:08:55,979 Some team of engineers decided for us what all of those keys would be called, 1406 01:08:55,979 --> 01:08:59,550 including track name, results, result count, and everything else. 1407 01:08:59,550 --> 01:09:03,359 You and I can absolutely store those same values in variables 1408 01:09:03,359 --> 01:09:06,600 just like I'm doing here with O, just like I'm doing here with result. 1409 01:09:06,600 --> 01:09:10,020 You can rename those keys anything you want using Python variables. 1410 01:09:10,020 --> 01:09:14,938 But the JSON response is coming from that third party server. 1411 01:09:14,938 --> 01:09:15,605 Other questions. 1412 01:09:15,605 --> 01:09:16,560 AUDIENCE: Yes, sir. 1413 01:09:16,560 --> 01:09:21,210 So I have a question related to cowsay package. 1414 01:09:21,210 --> 01:09:23,319 So like, yes. 1415 01:09:23,319 --> 01:09:29,100 So sir, what sort of ASCII graphics is it capable of putting? 1416 01:09:29,100 --> 01:09:31,140 DAVID MALAN: The cowsay package. 1417 01:09:31,140 --> 01:09:33,240 I would refer you to the URL in the slides 1418 01:09:33,240 --> 01:09:36,090 earlier if only because it's more thorough. 1419 01:09:36,090 --> 01:09:38,670 They have not just cows, but Tyrannosaurus rex's 1420 01:09:38,670 --> 01:09:40,218 and several other animals as well. 1421 01:09:40,218 --> 01:09:42,510 I should emphasize that this is not a package I suspect 1422 01:09:42,510 --> 01:09:44,160 you will use much in the real world. 1423 01:09:44,160 --> 01:09:47,220 It's really just meant to be representative of the types of packages 1424 01:09:47,220 --> 01:09:48,000 you can install. 1425 01:09:48,000 --> 01:09:51,090 But allow me to refer to the documentation for what more is there. 1426 01:09:51,090 --> 01:09:57,000 But ASCII art is all we had before there were emojis, let alone GIFs and JPEGs 1427 01:09:57,000 --> 01:09:57,630 and pings. 1428 01:09:57,630 --> 01:10:00,790 But it's what's is immortalized in cowsay. 1429 01:10:00,790 --> 01:10:06,390 Well, allow me to transition us back now to one final capability of Python which 1430 01:10:06,390 --> 01:10:10,710 is that you yourselves have the ability to make your own libraries. 1431 01:10:10,710 --> 01:10:14,700 Up until now, we've been writing all of our functions in our one 1432 01:10:14,700 --> 01:10:17,280 file, Hello py and everything since. 1433 01:10:17,280 --> 01:10:22,740 And now that we've introduced modules in Python, random and statistics, 1434 01:10:22,740 --> 01:10:25,050 we can import those that come with Python. 1435 01:10:25,050 --> 01:10:26,760 But that's other people's code as well. 1436 01:10:26,760 --> 01:10:29,490 And we've now used pip, this package manager to install 1437 01:10:29,490 --> 01:10:31,740 third-party packages as well in the system 1438 01:10:31,740 --> 01:10:33,780 and using other people's code still. 1439 01:10:33,780 --> 01:10:36,450 But to come full circle, what if you yourself 1440 01:10:36,450 --> 01:10:40,440 find yourself implementing the same kinds of functions again and again, 1441 01:10:40,440 --> 01:10:42,960 or you find yourself opening up old programs, 1442 01:10:42,960 --> 01:10:45,870 copying and pasting code you wrote into new programs 1443 01:10:45,870 --> 01:10:47,940 because you have the same problem yet again? 1444 01:10:47,940 --> 01:10:53,010 A good practice would be to somehow bundle up that code you keep reusing 1445 01:10:53,010 --> 01:10:56,160 and make your own Python module or package. 1446 01:10:56,160 --> 01:10:59,130 You can keep it local on your own Mac or PC or cloud server. 1447 01:10:59,130 --> 01:11:02,700 Or you can go through the steps of actually bundling it up, making 1448 01:11:02,700 --> 01:11:06,540 it free and open source, and putting it on something like py, pi for others 1449 01:11:06,540 --> 01:11:07,830 to use as well? 1450 01:11:07,830 --> 01:11:10,710 OK, I'm going to go ahead and run code of sayings.py 1451 01:11:10,710 --> 01:11:13,140 to create a brand new file called sayings.py which 1452 01:11:13,140 --> 01:11:15,580 is going to be my own sayings module. 1453 01:11:15,580 --> 01:11:18,090 I'm going to define a couple of simple functions in there. 1454 01:11:18,090 --> 01:11:20,160 I'm going to define a Hello function that's going 1455 01:11:20,160 --> 01:11:22,230 to take a name parameter as input. 1456 01:11:22,230 --> 01:11:25,110 And that function is simply going to print out 1457 01:11:25,110 --> 01:11:28,830 an F string that contains hello, comma, and then in curly braces, 1458 01:11:28,830 --> 01:11:31,405 whatever that person's name actually is. 1459 01:11:31,405 --> 01:11:33,780 Then I'm going to go ahead and define one other function, 1460 01:11:33,780 --> 01:11:37,470 a goodbye function, that has def, goodbye, also 1461 01:11:37,470 --> 01:11:39,120 takes a name as its input. 1462 01:11:39,120 --> 01:11:41,340 And then that prints out by contrast and F 1463 01:11:41,340 --> 01:11:45,720 string that says goodbye, comma, and then in curly braces, name. 1464 01:11:45,720 --> 01:11:48,780 And now, just for good measure just so I can be sure 1465 01:11:48,780 --> 01:11:50,677 that these functions are working as expected, 1466 01:11:50,677 --> 01:11:53,010 I'm going to go ahead and define a main function in here 1467 01:11:53,010 --> 01:11:55,080 too just for the purposes of testing. 1468 01:11:55,080 --> 01:11:57,780 And I'm going to go ahead and define a main function that 1469 01:11:57,780 --> 01:11:59,760 simply does a couple of tests. 1470 01:11:59,760 --> 01:12:05,370 For instance, it calls Hello of, quote, unquote, "world" shall we say? 1471 01:12:05,370 --> 01:12:09,153 And then it's going to call good bye of, quote, unquote, "world" as well. 1472 01:12:09,153 --> 01:12:11,070 And hopefully what I'll see on the screen then 1473 01:12:11,070 --> 01:12:13,960 is Hello world and Goodbye world when I run this program. 1474 01:12:13,960 --> 01:12:16,140 Of course, as always, I need to explicitly tell 1475 01:12:16,140 --> 01:12:17,620 Python to call that function. 1476 01:12:17,620 --> 01:12:20,280 So I'm going to call main at the very bottom of this file. 1477 01:12:20,280 --> 01:12:21,510 All right, let's try it out. 1478 01:12:21,510 --> 01:12:24,420 Python of sayings.py, Enter. 1479 01:12:24,420 --> 01:12:26,872 And indeed, I see Hello world and Goodbye world. 1480 01:12:26,872 --> 01:12:28,830 And so I think it's reasonable for me to assume 1481 01:12:28,830 --> 01:12:32,860 that these functions, albeit simple, are pretty correct at this point. 1482 01:12:32,860 --> 01:12:36,180 But now, suppose that I want to use these functions as though I've indeed 1483 01:12:36,180 --> 01:12:40,500 created my own library, my own Python module and that makes available 1484 01:12:40,500 --> 01:12:42,900 a Hello function for me or anyone else who wants to use 1485 01:12:42,900 --> 01:12:44,940 it or a Goodbye function as well. 1486 01:12:44,940 --> 01:12:49,140 Well, let me go ahead and open up again say.py but start fresh. 1487 01:12:49,140 --> 01:12:52,470 And rather than have the cow say anything, let me go ahead 1488 01:12:52,470 --> 01:12:55,530 and have my own library do the talking. 1489 01:12:55,530 --> 01:12:58,830 So I'm going to go ahead and as before, import sys so that I 1490 01:12:58,830 --> 01:13:00,720 have access to command line arguments. 1491 01:13:00,720 --> 01:13:05,100 And from my own module called sayings, I'm going to import Hello. 1492 01:13:05,100 --> 01:13:10,590 So because I created a file called sayings.py, I can say from sayings. 1493 01:13:10,590 --> 01:13:13,212 And it's inferred by Python that I mean sayings.py, 1494 01:13:13,212 --> 01:13:14,670 at least in this current directory. 1495 01:13:14,670 --> 01:13:17,420 But I specifically ain't going to import just one of the functions 1496 01:13:17,420 --> 01:13:19,050 for now, namely Hello. 1497 01:13:19,050 --> 01:13:20,760 And now, I can do something like this. 1498 01:13:20,760 --> 01:13:24,540 If the user obliges by giving me two command line arguments, which 1499 01:13:24,540 --> 01:13:27,840 I can check by just checking the length of sys.argv, 1500 01:13:27,840 --> 01:13:32,020 I'm going to then go ahead and call this new Hello function passing 1501 01:13:32,020 --> 01:13:36,670 as its input, sys.argvbracket1, which should hopefully be the person's name 1502 01:13:36,670 --> 01:13:38,960 which I'm going to expect them to type at the prompt. 1503 01:13:38,960 --> 01:13:39,778 So here we go. 1504 01:13:39,778 --> 01:13:41,570 I'm going to go down to my terminal window, 1505 01:13:41,570 --> 01:13:46,390 run Python of say.py and my own name because I want my own name to end up 1506 01:13:46,390 --> 01:13:49,270 in the command line arguments and therefore, be part of the Hello 1507 01:13:49,270 --> 01:13:52,630 so when I hit Enter in just a moment, I should hopefully see Hello, 1508 01:13:52,630 --> 01:13:53,560 comma, David. 1509 01:13:53,560 --> 01:13:55,780 So here we go, Enter. 1510 01:13:55,780 --> 01:13:59,110 And huh, I see Hello world, Goodbye world. 1511 01:13:59,110 --> 01:14:01,510 And then I see Hello, David. 1512 01:14:01,510 --> 01:14:04,400 So why is this happening? 1513 01:14:04,400 --> 01:14:06,580 Well, it turns out even though I've done everything 1514 01:14:06,580 --> 01:14:10,750 according to our own past practice, it's not really 1515 01:14:10,750 --> 01:14:13,870 the right way to go about calling main after all. 1516 01:14:13,870 --> 01:14:17,050 If I'm blindly calling main here at the bottom of my file, that 1517 01:14:17,050 --> 01:14:20,620 means whenever this file is loaded by Python, main is going to get called. 1518 01:14:20,620 --> 01:14:25,150 And unfortunately, that's true even if I'm importing this file or just 1519 01:14:25,150 --> 01:14:29,050 a function from this file as I am here in my say.py program. 1520 01:14:29,050 --> 01:14:32,440 This is to say on line three here, when I say from sayings, 1521 01:14:32,440 --> 01:14:34,990 import Hello, this effectively tells Python 1522 01:14:34,990 --> 01:14:39,370 to go find that module, sayings.py, read it from top to bottom, left to right, 1523 01:14:39,370 --> 01:14:41,990 and then import specifically the Hello function. 1524 01:14:41,990 --> 01:14:44,800 Unfortunately by the time Python has read the file from top 1525 01:14:44,800 --> 01:14:49,350 to bottom, left to right, that last line of code recall is to call main. 1526 01:14:49,350 --> 01:14:51,380 Main gets called no matter what. 1527 01:14:51,380 --> 01:14:55,690 So really, the right way to go about using a main function, which 1528 01:14:55,690 --> 01:14:58,760 does solve that problem of ensuring that we can order our functions 1529 01:14:58,760 --> 01:15:00,580 however we want, and all the functions will 1530 01:15:00,580 --> 01:15:03,040 be defined at the time they're invoked, I 1531 01:15:03,040 --> 01:15:06,340 shouldn't be unconditionally calling main at the bottom of this 1532 01:15:06,340 --> 01:15:08,080 or really any of my programs. 1533 01:15:08,080 --> 01:15:09,970 I should instead use this technique. 1534 01:15:09,970 --> 01:15:22,660 I should say if__name__=="__main__", then and only then should you actually 1535 01:15:22,660 --> 01:15:23,980 call main. 1536 01:15:23,980 --> 01:15:30,250 Well, it turns out that this variable is a special symbol in Python, __name__. 1537 01:15:30,250 --> 01:15:32,290 And notice that VS Code because of its font 1538 01:15:32,290 --> 01:15:34,210 isn't quite showing those two underscores. 1539 01:15:34,210 --> 01:15:36,335 But they're indeed there to the left and the right. 1540 01:15:36,335 --> 01:15:40,330 This is a special variable whose value is automatically set by Python to be, 1541 01:15:40,330 --> 01:15:45,130 quote, unquote, "main" when you run a file from the command line 1542 01:15:45,130 --> 01:15:48,130 as by running Python of sayings.py. 1543 01:15:48,130 --> 01:15:52,780 So watch what happens now with this additional conditional in sayings.py. 1544 01:15:52,780 --> 01:15:59,530 If I run Python of sayings.py, it still works as before because name will be 1545 01:15:59,530 --> 01:16:07,900 automatically set to __main__ when I run this file using Python of sayings.py. 1546 01:16:07,900 --> 01:16:09,190 But notice this. 1547 01:16:09,190 --> 01:16:12,197 Name is not going to be set to, quote, unquote, "main." 1548 01:16:12,197 --> 01:16:15,280 It's going to be set to something else, technically the name of the module 1549 01:16:15,280 --> 01:16:19,250 when I instead import the file like I do here. 1550 01:16:19,250 --> 01:16:21,250 So this highlighted line of code even though it 1551 01:16:21,250 --> 01:16:25,010 will cause Python to go find sayings.py, read it from top to bottom, 1552 01:16:25,010 --> 01:16:27,972 left to right, it's going to ignore the call to main this time 1553 01:16:27,972 --> 01:16:29,680 because it's wrapped in that conditional. 1554 01:16:29,680 --> 01:16:33,940 In this case, when I'm importing a file and not running it directly 1555 01:16:33,940 --> 01:16:36,520 at the command line, main will not get called 1556 01:16:36,520 --> 01:16:38,900 by definition of that names value. 1557 01:16:38,900 --> 01:16:40,360 So let me go ahead and try this. 1558 01:16:40,360 --> 01:16:42,880 Instead of running Python of sayings.py, which 1559 01:16:42,880 --> 01:16:45,610 is the module, which contains that conditional main, 1560 01:16:45,610 --> 01:16:49,000 let me go ahead here, run Python of say.py, 1561 01:16:49,000 --> 01:16:54,312 which is the program here before me that imports Hello from sayings. 1562 01:16:54,312 --> 01:16:56,020 But because of that conditional, it's not 1563 01:16:56,020 --> 01:17:00,940 going to say Hello to anyone else except me in this case. 1564 01:17:00,940 --> 01:17:02,980 All right, we're here at the end of our week. 1565 01:17:02,980 --> 01:17:06,040 It's only appropriate, I think, to import something other than Hello. 1566 01:17:06,040 --> 01:17:09,490 Why don't I go ahead and import not Hello, but Goodbye from here. 1567 01:17:09,490 --> 01:17:12,700 Let me go ahead and call Goodbye instead of Hello. 1568 01:17:12,700 --> 01:17:15,010 And this time when I run Python of say.py, 1569 01:17:15,010 --> 01:17:16,450 I'm not going to type my own name. 1570 01:17:16,450 --> 01:17:18,830 Allow me if I may to type in the whole world 1571 01:17:18,830 --> 01:17:22,480 so that our final sentiment today is Goodbye world. 1572 01:17:22,480 --> 01:17:23,930 Indeed, that's it for this week. 1573 01:17:23,930 --> 01:17:26,580 We will see you next time. 1574 01:17:26,580 --> 01:17:28,000