Full transcript
Introduction
0:00[MUSIC PLAYING]
0:23DAVID MALAN: All right, this is CS50, Introduction
Libraries
0:27to Programming with Python.
0:28My name is David Malan, and this is our week on library.
0:31So libraries are generally files of code that other people
0:35have written that you can use in your own programs or a library's code
0:39that you've written that you can use in your own program,
0:41but maybe not just this program, but another and another as well.
0:45So Python supports exactly this idea.
0:47This ability to share code with others, share code across your own projects.
0:51And it does so by way of what it calls module.
Modules
0:54A module in Python is just a library that
0:57typically has one or more functions or other features built into it.
1:01Generally, the purpose of a library or a module
1:03specifically is to encourage reusability of code
1:06if you find yourself using the same types of functions again and again,
1:10the same functionality.
1:11If you find yourself copying and pasting from an old project
1:15into your new project, odds are there's an opportunity there to factor out
1:20that code that you keep copying and pasting that you keep reusing and put
1:24it into a library that you can then load into your programs moving forward
1:28so as to not just copy and paste it and have
1:30all these different copies all over.
1:32So what are some of the modules or libraries that Python comes with?
1:36Well, Python comes with a random library literally,
1:39which is to say that when you install the Python
1:41interpreter on your Mac or PC or somewhere
1:44in the cloud, not only do you get Python,
1:46you get a whole bunch of modules as well.
1:48Now, these modules provide you with functions
1:50that you don't have access to just by default like you do print and input.
1:54Print and input and other such functions just work in Python.
1:58But sometimes functions are tucked away in these modules,
2:02so you have to be more deliberate about loading them
2:04into the computer's memory.
2:06So somewhere on the computer's hard drive, once you've installed Python,
2:09there is also, it turns out a file, probably called random.py
2:13that someone else wrote probably long ago but that you have access to.
2:17And in that random.py file, there's probably one or more functions
2:20that you yourself can use in order to do things randomly.
2:25That is to say how could you flip a coin in a program in Python?
2:29How could you pick a random number between 1 and 10 in Python?
2:33Well, you need a bit of randomness.
2:34And while you could figure out mathematically
2:37how to write functions like that yourself,
2:39it's a lot easier to stand on the shoulders of others who've already
2:42solved that problem for you so you can focus on the problem
2:45that you yourself want to solve.
2:48So for documentation on most any Python module,
2:51you go to the official Python docs.
2:52And you go to a URL like this where the documentation for that specific module
2:57lives.
2:57And within the documentation, you'll see a list
2:59of the functions or other functionality that some module provide.
3:03But how do you go about loading a module into your own program
3:08so that you can use the functions in that module?
3:10Well, we need a new keyword in Python and namely it's import.
import
3:14The import keyword in Python allows you to import the contents of the functions
3:20from some module in Python.
3:23Well, how might I go about using this in practice?
3:26Well, let me propose that there exists in that random module
3:29this function among others.
3:31So I have copied and pasted from the documentation
3:34this summary of a function called Choice.
3:38Now, the function exists in the random module, so to speak,
3:42not a random module, the random module.
3:45And so generally the documentation describes it fully like this.
3:48random.choice is how you would technically call this function,
3:52though, we'll see alternatives to that.
3:54In parentheses, there is a parameter called S-E-Q for sequence.
3:58And sequence generally means a list or something
4:01that is list-like if you have a list of numbers or strings or anything else.
4:05And the documentation elaborate.
4:06Well, how can I go about using this function to solve, perhaps,
4:09a familiar problem?
4:11Well, let me go ahead and open up VS Code here.
4:13And let me propose that we implement a program that simulates flipping a coin.
4:17A coin that in the US has heads or tails, the idea of which
4:21is to pick a decision with 50/50 probability.
4:2550% probability of heads, 50% probability of tails.
4:29Or you can use some other mechanism like that.
4:31Well, let me go ahead and open a program with code called generate.py
4:35because I want to start generating a whole bunch of random information.
4:39The first of which is just going to be a coin toss.
4:41Now, how do I go about using that function?
4:43Well, I first have to import the random library.
4:46So literally the first or among the first lines of my file
4:49should be import random.
4:51And that just gives me access to all of the functions in that specific module.
4:56Now, suppose I want to flip a coin.
4:58Well, I can do random.choice per the documentation a moment ago.
5:03And that again takes a sequence.
5:05What's a sequence?
5:05It's a list or something that's list-like.
5:07And we know about lists.
5:08We've used lists to iterate over numbers.
5:11We've used lists to iterate over students at Hogwarts.
5:13Let's go ahead now and iterate over just a list of two sides of a coin,
5:18"heads," quote, unquote, or tails.
5:20Now, I could call these anything I want.
5:22These are my string.
5:23I just want to simulate a tossing a coin.
5:25So I'm just going to say in all lowercase, heads and tail.
5:28But notice the syntax.
5:30I have "heads" and "tails" in double quotes.
5:32That's because they're strings.
5:33I could also use single quotes so long as I'm consistent.
5:36There's a comma between them, which means the list has two elements.
5:38They're square brackets to the right and the left, which
5:42indicates that this is indeed a list.
5:44That's the syntax recall for defining a list in Python.
5:47And then lastly, there's something more familiar.
5:49There's the parentheses outside of those square brackets.
5:52But those are just the parentheses that belong to the Choice function
5:55and specify where its parameter gets passed in.
5:58But again, unlike past function, I have to specify what module
6:03this function is in at least for now.
6:05And so I do random.choice to call the specific function.
6:09All right, well, it's one thing to flip a coin picking between those
6:12with 50% probability.
6:14And that's what random.choice does.
6:15It takes in a list, and it returns to one of those values randomly
6:19with equal probability.
6:21Because I've passed in two items, I've got a 50/50 chance.
6:24If I passed in three items, it'd be a 33% chance for each of those items
6:28and so forth.
6:29Python does the math for you.
6:30But I want to store the value of this in a variable.
6:33So let's define a variable called coin equals whatever the return value is.
6:37So this is indeed like flipping a coin.
6:39I'm going to store in a variable called coin, whatever
6:42that value is, heads or tails.
6:43And now, just so I can see what's going on, let's go ahead
6:46and print out the value of that string coin
6:49All right, let me go ahead now and run this program in my terminal window.
6:52Python of generate.py, Enter.
6:55And it looks like the first coin toss was the heads.
6:58Let's go ahead and run it again.
7:00And it looks like it was heads again.
7:02Maybe you want to chime into the chat here.
7:03If I run it a third time, what's it going to be this time?
7:06If you want to type your thoughts in the chat,
7:10you might think there's a bug here.
7:11But this is probability in action.
7:14If I go ahead and hit Enter a third time there,
7:16it's actually now tails And again, tails and again tails and again tails
7:21and again tails and again heads.
7:23Now, if we did this an infinite number of times,
7:25it would indeed work out to be 50/50.
7:27If we only do it a few times, it might not work out as cleanly.
7:31But that's how probabilities indeed work.
7:33All right, so I've got that now working.
from
7:35Could I have implemented this in a different way?
7:37Well, let me show you an alternative to actually using the import keyword alone
7:42and let me introduce the keyword from in Python.
7:45So from is a keyword in Python that you can use when importing functions
7:50from a module, but it allows you to be a little more specific than import alone.
7:55So if I go back to my code here, it's worth
7:57noting that what technically I'm doing here by importing random
8:01is I'm technically importing everything that's in that module.
8:04So not just the function called random.choice but a few other functions
8:09as well.
8:10So instead of using this line of code at the top of my file,
8:12import random, which will technically give me access
8:15to all of the contents they're in, a downside of that
8:18is that I have to type in random.choice, random.this,
8:22random.that because all of the functions I'm calling
8:24have to be associated with the scope of that module.
8:28Well, suppose that I just want to call the function as its name, choice.
8:31I can do that as well.
8:32Let me replace this first line here with from random import choice.
8:37And what this does effectively is it loads the function's name choice
8:42into my current namespace into the scope of the file I'm working in.
8:47What that means is that I now no longer have to specify
8:50which choice function I mean.
8:52I can just say choice.
8:53And so it loads it into the local namespace
8:56that is into my local vocabulary, if you will, so I can just now say choice.
9:00This might be advantageous in what cases, do you think?
9:05When might you want to import the name of the function explicitly like this
9:10as opposed to just saying random.choice--
9:12random.choice throughout your code when calling a function?
9:16Any instincts here for this alternative import using from?
9:21AUDIENCE: Hello, I'm Mohammed Omar from Egypt.
9:23And maybe if we have a variable that its name is basically like choice
9:29if I have a variable called the choice.
9:30So I need to differentiate which trays I choose.
9:33So I'm going to choose random data choice.
9:36DAVID MALAN: Yeah, really good instincts.
9:38By using the first approach by just importing random,
9:40you're making sure that all of its contents
9:42are associated with or scoped to the random module
9:46so that you can have your own choice function.
9:49You can have your own choice variable.
9:51You can use the same names as all of the functions or variables that
9:54are stored inside of that file without them colliding, so to speak.
9:58And this is a good thing.
9:59In older languages, it was the case that if you imported someone's library,
10:03you better hope that you're not using the same functions
10:05or variables as they are because you might
10:08in fact have some kind of conflict.
10:09Python and certain other languages allow you
10:11to scope the names of those functions and variables to the file or the module
10:16that they come from.
10:16So that's a good thing.
10:17But honestly, this is such a short program.
10:20Or equivalently, maybe I'm using the choice function
10:23in so many places calling random.choice, random.choice, random.choice.
10:28It's just making my code longer and longer and longer.
10:31Marginally so, but hey, just getting ugly and annoying,
10:34I can simply import choice and now tighten up my code a little bit.
10:38So as with so many decisions in the past,
10:40there's not necessarily one right approach or another.
10:43It depends.
10:43But I think for those very reasons, sometimes
10:45it's better to do what we did the first time, which
10:48is only import the module so as to retain the scope therein.
10:52Well, let me propose that we transition to another function that
10:55comes with Python's random module.
10:57And that's this here from the documentation randint.
11:01It's a bit hard to say, but it implies get back a random int.
11:04And if you read the documentation, it's a random int that's between A and B
11:08inclusive.
11:09So if you were to pass in 1 for A and 10 for B,
11:12you would get back a number between 1 and 10 inclusive, including the 1
11:17and including the 10 potentially.
11:18Each with a 10% probability.
11:21So how might I go about using a program like this?
randint, shuffle
11:23Well, let me come back to my generate the py file.
11:26And why don't we go ahead and try generating
11:28a random number between 1 and 10?
11:29You might do this frequently in the real world.
11:31When you just want someone to pick a random number,
11:32you tell them as much in the human response.
11:34Let's get the computer to do the same here.
11:37Let me go ahead and delete my two lines of code at the bottom
11:39but keep my import random.
11:41And let's go ahead and define a variable this time called number,
11:44set it equal to the return value of random.randint
11:47and now passing A, a value of 1 and B, a value of 10.
11:52And now, let's go ahead and print the number.
11:55I'm going to go ahead in my terminal window
11:57and run Python of generate.py and hit Enter.
12:004.
12:01A Python of generate.py and hit Enter.
12:048, again, 9, again, 7, again, 10, again, 2, again.
12:11And we can do this all day long.
12:13And if we add all of those up, they should end up
12:15being with 10% probability each.
12:17Now, how might you use this information?
12:19Well, maybe we're playing a guessing game.
12:21Or maybe we're trying to randomize the behavior of some character in the game.
12:25You can imagine using very simple building blocks like this just
12:29spicing up your program by getting it to do things
12:32a little less predictably because you're choosing these values seemingly
12:36randomly.
12:36And you're deferring to Python to actually do
12:38the generation of these numbers using its own algorithms and its own math.
12:43Well, what more could we do here?
12:44Let me propose that we introduce another function that
12:46comes from this random library.
12:48Yet, another that you yourself don't have to implement, shuffle.
12:52If you read the documentation for shuffle in the same random module,
12:55you'll see that it takes in a list, for instance, of values
12:58and just shuffles them up.
13:00It randomize them like a deck of cards.
13:02Here, you might shuffle them so as to put them into seemingly random order.
13:06Well, how do I use this based on this function's name?
13:09Well, let me propose that we go back to VS Code here.
13:11And let me go ahead and this time do the following.
13:14Because I need to shuffle something like a deck of cards,
13:17let me go ahead and not just import random.
13:19But let me give myself a variable called cards that's going to be of type list.
13:23And just so I have something to shuffle, I
13:25don't need all 52 cards in a typical deck.
13:28I'm just going to shuffle three cards.
13:29A Jack, a Queen, and a King.
13:32I could call those strings anything I want,
13:34but I just wanted a list of some values so as to shuffle them up.
13:37That is randomize the order therein.
13:39Well, how does this now work?
13:40If you read the documentation for random.shuffle,
13:43you'll see that it shuffles the argument in place.
13:47That is unlike many of the functions we have seen.
13:49It doesn't return to you a value that contains
13:52the shuffled cards in this case.
13:54It actually shuffles the list it's given itself.
13:57So what this means for my code is that I need
13:59to do something like this-- random.shuffle
14:02and pass in the variable containing those cards.
14:06And then on a final line here, how might I go about printing the cards?
14:11Well, I could do this, and I could say print card.
14:14But if I do that, I'm actually going to see Python syntax for lists.
14:17And it's just going to format in its own way using commas and the like.
14:21I want to print these cards out one at a time
14:23just because I think it'll look a little better so we can use some of our syntax
14:26from loops and say something like this--
14:28for card in cards, go ahead and print out the current card.
14:33So what's now happening here?
14:35Line three, I'm defining a list of three cards in this order--
14:39Jack, Queen, King.
14:41I'm then shuffling those same cards on line four.
14:44And then on line five, I'm using a for loop
14:46for each of the cards in that list printed out one at a time
14:50and because I'm using print one line at a time.
14:53Well, let's see the results.
14:55Down here in my terminal window, I'm going
14:56to run Python of generate.py and hit Enter.
14:58Queen, King, Jack seemingly shuffled because that's not
15:02the order I defined earlier.
15:04Let's do it again.
15:05Queen, King, Jack.
15:07Hmm, OK, that happens to be the same.
15:09But let's see.
15:10This could just be bad chance.
15:11There we go.
15:12Jack, Queen, King.
15:14Doesn't look like it's shuffled, but at least
15:16we're getting back different orderings now.
15:18Again, Jack, Queen, King.
15:20Hmm, not so good.
15:21Jack, Queen, King.
15:23Not so good.
15:23This is someone you probably want to play against with cards.
15:26Queen, Jack, King, there we go.
15:27But of course, we only have three cards here.
15:30So there's not that many permutations we might see.
15:32And if we do this over time, we will see all of them.
15:35But if we had, of course, 13 or 52 cards,
15:37we'd see a lot more permutations instead.
15:40So we have now these three ways to generate random information.
15:43One, a simple coin toss if you want to start some kind of athletic event.
15:47One, pick a number between 1 and 10 if you
15:49want to decide something based on that.
15:50And now, using shuffle, we can even take in a list of things
15:54and shuffle them about so that we get some kind of random behavior.
15:58Well, let me pause here and see if where there's
16:00any questions yet on random, on modules, or any of these three functions.
16:06AUDIENCE: Yeah, can we increase or decrease
16:09the probability of cards if we want to?
16:14For example, there are three.
16:16There is a 33% chance of probable B. So is there
16:19any chance to increase or decrease the probability?
16:22DAVID MALAN: Can you set these probabilities
16:24not using these same functions?
16:26Can you set the probabilities?
16:28But you can absolutely implement some of your own functions
16:31or use more sophisticated functions that do exist in this library and others
16:34to exercise more control.
16:36These are meant to be very user-friendly and simple functions, certainly
16:39the ones we looked at, that give you equal probability for all of those.
16:42But absolutely you could skew things, though, hopefully,
16:44if you're implementing a gambling game or the like,
16:47you're not actually making some cards more probable than others.
16:50Allow me to turn back now to our implementation here of this randomness
16:55and consider how we might leverage other types of functionality that
16:58aren't necessarily in this specific library here.
statistics
17:01Well, it turns out that Python also comes with a statistics library.
17:04And this contains all sorts of functions for doing
17:06things more statistical in nature, namely calculating
17:10means or medians or modes or other aspects of a data set
17:14that you might want to analyze.
17:16So how might we use the statistics module in Python?
17:19Well, we might first just take a look at it's documentation
17:21like any other module in Python.
17:23And we'll see within that library that there's a whole bunch of function.
17:26And one of those functions is one that's quite simple.
17:28It's average.
17:29A function that allows you to calculate the average of some numbers
17:33that you've passed in.
17:34Let me go ahead and in VS Code in my terminal window, open up a new file
17:38called average.py.
17:39And at the top of this file, I'm going to import
17:41a different library this time, namely the statistics module in Python.
17:46And now, I'm going to go ahead and call a function that I know comes
17:49in that module, namely mean for the average of some values.
17:53And I'm going to call statistics.mean.
17:55And I'm going to pass into this function mean, a list of some values.
18:00And let's suppose that I'm quickly trying
18:01to calculate what my current grade average is in school.
18:04And I did really well on my first test.
18:06And I got 100%.
18:07And on my second, I did well but not as well.
18:10And I got a 90.
18:10And ironically, I'm not very good with math.
18:13So I'd like to figure out what my average now is between those two tests.
18:16So let me go ahead now and in this list, type in the number
18:19100, comma, 90, thereby passing in a list of two values, two INTs, 190.
18:25And outside of those are the parentheses because, of course,
18:28this is now the argument I'm passing to the function called mean.
18:31And this function mean is in the module called statistics.
18:35Well, it's not that interesting to just calculate the mean if I don't actually
18:38see what it is.
18:39So let me additionally pass the return value of that mean function
18:43to the print function as usual.
18:45Let me now in my terminal window in VS Code, type
18:47in Python of average.py and hit Enter.
18:50And voila, as you might expect, my average is 95%.
18:54So the difference here is that I'm just using a different module that
18:57still comes with Python.
18:58But I need to import it instead of, for instance, the random module instead.
19:02And this time, I know from the documentation
19:04that there exists a function called mean.
19:06Well, it turns out there's even more functionality that comes with Python
19:10and that comes with other modules in Python.
Command-line Arguments, sys
19:13And there's this feature generally known as command line arguments.
19:16This is a feature, not just of Python, but of languages
19:19more generally that allow you to provide input not when
19:22prompted inside of a program as happens whenever we call the Python function
19:27input.
19:28But rather, there's this feature, command line arguments of programs,
19:32that allows you to provide arguments that
19:34is input to the program of just when you're executing at the command line.
19:38So up until now, for instance, recall that we've generally
19:40run Python of something.py.
19:42For instance, Python of hello.py.
19:45And I've never once really executed any words or phrases
19:49after the name of the file, but I could.
19:52In fact, when you're running programs in a command-like environment like we are,
19:57you can provide any number of words or numbers or phrases after the command
20:02that you're typing.
20:03And all of those will somehow be passed in as inputs to the program itself.
20:08You don't have to prompt the user for one thing at a time
20:11by manually calling that input function.
20:14So what does this mean in real terms?
20:15Well, let me go ahead back into VS Code here.
20:18And let me propose that we consider how we might leverage a certain module.
20:23I'm going to go ahead and create a file called name.py.
20:27And I'd like to use a new module this time that's
20:30going to give me access to values that have been typed at the command line.
20:35But what's this module going to be?
20:37Well, this one's going to be called sys.
20:39And sys, short for system, contains a whole lot of functionality
20:42that's specific to the system itself and the commands that you and I are typing.
20:46The documentation for this module is at this URL here.
20:49And it lists all of the various functions and variables and the like
20:53that come with that module.
20:54But we're going to focus on something a little more specific,
20:57namely this thing here.
20:58It turns out in the sys module in Python,
21:01there is a variable that just magically exists for you called argv.
21:06It stands for argument vector which is a fancy way of describing
21:10the list of all of the words that the human typed in at their prompt
21:15before they hit Enter.
21:16All of those are seemingly magically provided to you via Python
21:21in a variable called sys.argv.
21:24This variable is a list, which means that the first element is going
21:27to be the first word that you type.
21:29The second element is going to be the second word
21:30that you typed in, so forth.
21:32And by way of this list, then, can you figure out
21:34what words did the human actually type at the prompt and maybe use that
21:38to influence the behavior of your own program?
21:41So what does this mean now in real terms?
21:43Well, in this new tab called name.py, let me go ahead and import sys.
21:47Within that sys module is going to give me access to sys.argv, but how might
21:52I want to use it?
21:53Well, let's do this.
21:54Instead of writing a Hello World program that all of these times
21:58has just looked for the return value of input
22:02to figure out what the user wants me to print,
22:04let's go ahead and just expect the user to tell us
22:06when they run the Python program itself, what their name is.
22:10And suppose this time, I'd like to generate a whole bunch of name tags,
22:13initially just one.
22:14And in the US here, it's very common to wear a sticker on your lapel that
22:17says Hello, my name is David.
22:19So I want to print out some text that resembles that.
22:21The idea being maybe I could enhance this program someday
22:24to even send that text straight to the printer
22:26and dynamically generate those name tags.
22:28Well, let me go ahead now and do this.
22:30Let me go ahead and print out as always, Hello.
22:32But I'll say a little something more this time
22:34to make things more interesting.
22:36Hello, my name "is," quote, unquote.
22:38And then after that, I normally have been
22:41in the habit of calling input, storing the return value in a variable,
22:45and passing in the name of that variable here.
22:48But I'm going to instead jump right to this--
22:50sys.argvbracket1.
22:53And that's it.
22:55I'm going to have a program here that says Hello, my name is followed
22:59by whatever is in sys.argvbracket1.
23:02And notice, this .argv again is a list.
23:04And recall from our discussion of loops and in turn list,
23:07we use this square bracket notation to get at the various elements
23:11inside of a list.
23:12All right, let me go down now into my terminal window
23:15and run Python of name.py.
23:17But this time, rather than just hit Enter
23:19and wait for the program to prompt me for my name,
23:21let me proactively just tell this program what my name is
23:24at the so-called command line.
23:26Here we go.
23:27D-A-V-I-D separated with a space from the name of the file so that now when I
23:31execute Python, name.py David, I see on the screen, voila, Hello,
23:37my name is David.
23:38So based on this demonstration alone, I think
23:41we can infer exactly what's going on in sys.argv
23:44even though it sounds certainly at first glance, rather complicated here.
23:48Let's look up.
23:49At sys.argv, I'm going to bracket1 here.
23:53So clearly, sys.argvbracket1 is storing D-A-V-I-D. But it's one.
24:01In the past when we looked at loops, recall
24:03that we said that they were zero index.
24:06That is the first element is zero.
24:07The next element is one.
24:09This next element is two and so forth.
24:12And yet, here I am treating it as though my name
24:14is at the start of the list one.
24:16Well, let me ask this question, what is probably in sys.argv of 0?
24:23What is probably in sys.argv of 0--
24:27the very first element actually in that list?
24:30AUDIENCE: Oh, yeah.
24:32I think it's like in C, the name of program.
24:37DAVID MALAN: Indeed, it's indeed like in C. Another language
24:40is the name of the program.
24:41Well, if we consider what it was I typed,
24:44I certainly typed Python because that's the name of my interpreter.
24:47And we don't really need to know that because we're using Python itself.
24:50But after that, I did type two things.
24:52I typed name.py as I've done so many times any time
24:55I want Python to the interpreter program I've written.
24:58And it turns out by convention, what Python
25:00does is it stores in sys.argv the name of the file that you're executing
25:05or interpreting followed by any number of other words that you type.
25:10So all this time, we could have been accessing
25:12the name of the program, which frankly, isn't all that interesting.
25:15But we can also now access words that are typed after that prompt as well.
25:20But of course, if I don't type anything in, what might happen here?
25:25This might be naive of me to assume that there's always
25:27going to be something at location1 in sys.argv.
25:30Let me go ahead and try this.
25:32Python, name.py.
25:33And I'm not giving you my name because at this point,
25:36I might not even know that you want my name to be typed.
25:39So let me hit Enter now.
25:40And uh, oh, we see now an error.
25:43A so-called exception in Python, this one's a new one.
25:46This one's an index error that elaborates list index out of range.
25:51And turns out this is actually one of the most common mistakes
25:53in programming, whether you're using a list in Python
25:56or arrays or vectors in other languages, is
25:59to try to access some element that does not exist.
26:02You try to go too far to the left.
26:03Or you try to go too far to the right in this object that
26:08is just a list of some values.
26:10So of course, the mistake here is that I'm
26:13assuming there's going to be something at location1
26:15when really, it's location0.
26:17That's the only one that has a value.
26:19But fixing this is not going to amount to doing bracket0
26:23because now if I go ahead and rerun this program with no other words
26:27after name.py, it says Hello, my name is name.py, which is fine
26:31if we're making a name tag for the program, but that's not,
26:33of course, what my goal here is instead.
26:36So if the fix is not just to change the one to a zero,
26:40how else might I handle this error?
26:43How else might I handle this error?
26:46This index error that happens if the user just doesn't remember to
26:49or doesn't know to type their actual name at the prompt.
26:53AUDIENCE: We could always put an exception into the program,
26:56say, if there's nothing at location1, we just come out
27:03and say, OK, we haven't got parameter or something.
27:06But if there is, we continue along with the program.
27:09DAVID MALAN: Perfect.
27:10So if I might simplify, we can try to execute this line of code,
27:13except if there's an error, we'll deal with it in some other way.
27:16Now, ideally-- and once I'm a strong enough programmer,
27:19I would have anticipated this and written the following code
27:22from the get go.
27:23But when you're learning, it's certainly reasonable to see an error.
27:25Oh, I didn't realize I should detect that and then
27:28go back and improve your code.
27:29But of course, if you read the documentation,
27:31you ingrain some of the lessons learned from the past.
27:33You'll get into the habit of trying and checking for some of these exceptions
27:37yourself.
27:38So let me solve this in one possible way as you've proposed here.
27:41Let's try to handle this exception as follows.
27:43Let me go ahead now.
27:44And instead of just blindly calling this print line,
27:47let me try to print out Hello, my name is such and such,
27:51except if there is an issue, specifically an index error, then
27:56what do I want to go ahead and do?
27:58I'm going to say something like too few arguments.
28:01I could be more explanatory than that.
28:03But for now, I'm just going to explain to the user
28:05that they gave me too few arguments, too few words at the prompt.
28:08So now, it's still not going to work in quite the way I want.
28:12I'm still not going to be able to generate their name tag.
28:14But at least, they're not going to see some cryptic error message
28:17and think that they themselves broke the program.
28:20Let me go ahead now and run Python of name.py Enter and too few arguments.
28:23OK, let me go ahead now and do Python of name.py and type in my name, David.
28:28And now we're back in business.
28:30And I see that my name is on the screen too.
28:33But strictly speaking, I don't have to try to do this.
28:37I could actually be a little more defensive in writing this code.
28:41And maybe I could check whether or not the user has indeed
28:44provided a name or multiple names at the prompt so as to give them
28:48more refined error messages as well.
28:51So how might I do this?
28:52Well, me go and undo the exception handling I've added.
28:56And why don't I instead more modestly try to do this?
28:59Let me go ahead and introduce a conditional here.
29:01If the length of sys.argv is less than 2 or equivalently equal to just one
29:09value--
29:10but I'll just stick with less than 2 for now,
29:12then go ahead and print out two few arguments.
29:17So I want ultimately two arguments.
29:19I want the name of the program at location0.
29:21And I want the name of the human at location1.
29:24So that's a total of two arguments.
29:26So if I have fewer than two arguments, let's
29:28tell the user with this print line, L if the length of sys.argv
29:32is say greater than 2, like they typed in too many words at the prompt, well,
29:36let's tell them, print, quote, unquote, "too" many arguments.
29:40Else if they did get it right, and they gave me exactly two arguments.
29:44Else, let's go ahead and print what I actually care about.
29:48All right, let me go down to my terminal window
29:50here and run Python of name.py and voila.
29:52Uh, oh, a completely different type of error.
29:55This one a syntax error, which we've seen in the past.
29:58Now, a syntax error recall is mea culpa, like, I messed up here.
30:01And I wrote invalid syntax.
30:03And so no amount of conditionals or exception handling's
30:07really going to catch this one.
30:08I need to go back and just get my program
30:09to work because it's not running at all.
30:11Well, let me go up here and see.
30:14Line four is the issue.
30:16And indeed, it looks like I have an unterminated string here.
30:19I need to go ahead and now add this double quote.
30:22So let me go ahead now.
30:23And with that red herring gone, let me rerun Python of name.py and hit Enter.
30:27And now, we see too few arguments.
30:29OK, maybe it wants my full name.
30:31Let me go ahead now and run Python of name.py, David Malan,
30:35typing in both words after the name of the file and hit Enter.
30:39And now, of course, it's too many arguments.
30:41Fine.
30:41Now, I'll oblige and do Python of name.py and just David.
30:44And there we have it.
30:46My name tag printed on the screen.
30:48So strictly speaking, we don't have to handle exceptions
30:51if we can be a little smarter about it and just check for the things
30:54that we're worried about, especially if we want
30:56to give the user more refined advice.
30:58We don't want to just tell them no, something went wrong
31:00or we don't want to pass.
31:01We want to tell them no, that's too few or no, that's too many.
31:05We have conditionals in our vocabulary already
31:08via which we can now express that.
31:11Well, let me pause here and see if there's any questions now
31:13on how we handled the error before with the index error
31:16or how now we're just proactively avoiding all index errors altogether
31:21by just checking first, is it too few?
31:24Is it too many?
31:25Or is it exactly what we want?
31:27AUDIENCE: Hi, yeah, thank you.
31:28So I was wondering, you touched upon using your full name.
31:36Is there a way going forwards that perhaps we
31:40have people that want their full names and want just their first name
31:44that we separate that into, oh, this person has full name.
31:47This person has just the one name?
31:50DAVID MALAN: Absolutely, and allow me to propose we come back
31:55to that support for multiple names.
31:57But indeed, we could do that.
31:59And I should note too, though, we can support
32:02full names right now if I do this.
32:04Instead of typing in David space Malan, which is problematic because again,
32:08by definition of how are argv works, each word
32:11ends up in a specific location in the list.
32:14But if I add quotes, single quotes or double quotes at the command line,
32:18now, Python will view this as two total things.
32:21The name of the file and this full name.
32:23And now, when I hit Enter, I don't see the quotes.
32:25The whole thing is passed in as my full name.
32:28And if I want to adapt this further for multiple people,
32:30we'll be able to do that as well.
32:32Other questions now on this version with if, elif, else, or on except before.
32:37AUDIENCE: Python.
32:39I want to ask you, can we use multiple else's statement?
32:43DAVID MALAN: Can you use multiple else's statements?
32:45No, else is the last catchall statement that you can have.
32:48You can have multiple elif statements in the middle but not multiple elses.
32:55AUDIENCE: [INAUDIBLE]
32:56DAVID MALAN: All right.
32:57All right, well, let's turn our attention back now to this code
sys.exit
33:00and see if we can't refine it a bit more by adding
33:02in some additional functionality that we get with modules like the sys module.
33:06One of the things I don't love about this version of the code
33:09even though arguably it is now correct is that the essence of my program,
33:14which is just to print out the name tag, is relegated to this else clause.
33:19And that's fine.
33:20Logically, it's correct, but generally speaking,
33:24there is something nice about keeping all of your error
33:26handling separate from the code that you really
33:30care about having all of these ifs, elifs, perhaps at the top of your code
33:34that are checking to make sure that all of the data's as expected.
33:37But then it would be nice if only for design sake
33:41not to hide in this else statement the actual code that you care about.
33:45I would prefer, for instance, to do something logically like this.
33:49I could check for errors up top.
33:51And then down here, print the name tag.
33:54It would be nice if those are distinct blocks of code all of which
33:58are here left aligned.
33:59But there's a problem with what I've just done here.
34:02Logically, what bug did I just introduce by getting rid of the else
34:08and introducing line 10 on its own with no indentation
34:12outside of the conditional?
34:14What bug have I just introduced?
34:16What mistake to be clear?
34:19AUDIENCE: Name error.
34:20DAVID MALAN: Ironically, it's a name error but not a name error exception.
34:25It's an error with my name, but I think you're frozen for me.
34:30It's going to raise an exception because even
34:32though I'm checking the length of sys.argv up top
34:36and even though I'm checking it again for being greater than 2, not just less
34:39than 2, but greater, I'm still then blindly and incorrectly assuming
34:44it's now going to exist.
34:45So just to be clear, if I run Python of name.py and I don't type any argument--
34:50I've got too few--
34:51I think I'm going to see that I have too few,
34:53but I'm also going to see that same exception.
34:56At the very top of my terminal window's output,
34:58there's my error message, too few arguments.
35:01But again, on line 10, I blindly proceed to still index into my list
35:05at location1 which does not exist.
35:08So it turns out there's a better way to handle errors like this, especially
35:11if you're writing a program in Python that's just meant
35:14to run briefly and then exit anyway.
35:17But maybe we could start to exit prematurely if the program itself just
35:22can't proceed.
35:23If the user has not given us the data we want,
35:25perhaps, we should just exit the program earlier than we might otherwise.
35:30So let me go ahead and do this.
35:31Let me go ahead and remove my comments so as to focus only on the code here.
35:35And let me propose that instead of just printing,
35:39quote, unquote, "too" few arguments, I'm going to use one other function that
35:43comes with the sys module.
35:44I'm going to go ahead and call sys.exit.
35:48And as the name suggests, it's going to do exactly that.
35:50With the system's help, it's going to exit my program then and there
35:55on line four.
35:56Why is that OK?
35:57Well, if you gave me too few arguments, I
35:59have nothing more to say to you, the user.
36:01I might as well exit a bit prematurely.
36:03And I can do this as well on line six.
36:05Let's go ahead and not just print that, but sys.exit, quote, unquote,
36:08"too" many arguments.
36:10Print out that message and just exit right there.
36:12Now, I can trust that by the time I get to line eight,
36:16every error condition has been checked for.
36:19And so it's safe for me to assume that there is in fact an item at location1
36:25in sys.argv.
36:26So let me go ahead now and run this, Python
36:29of name.py, Enter, too few arguments.
36:32But I'm back at my prompt.
36:34Nothing more has happened.
36:36Let me run it again.
36:37Python of name.py David Malan with no quotes, Enter.
36:41Too many arguments is now printed here.
36:42Finally, Python of name.py just David, Enter.
36:46Hello, my name is David.
36:48So we have then in sys two forms of functionality.
36:52Now, we have access to this variable, sys.argv, this argument vector,
36:55that gives me all of the words that were typed at the prompt,
36:58including the program's own file name.
37:00And it turns out if we read further in the documentation,
37:03there's an exit function that can take different types of input.
37:06But if I pass out a string like this, it will indeed print that string for me
37:10and then exit from my program then and there.
37:13Questions now on exiting from programs like this.
37:17To be clear, all of this time once Python gets to the bottom of your file,
37:22it's going to exit anyway.
37:23So I'm using sys.exit now just to make sure that I exit earlier than
37:28otherwise.
37:28AUDIENCE: My question is about the sys that arg--
37:32argv.
37:33So is that capable of accepting or taking multiple elements at once?
37:40Let's say, for example, Python name.py, David Malan.
37:45I'm a male, 20 years old.
37:48And if let's say I only want to access your name, which is at the first index.
37:53And then your age is, say, at the sixth index.
37:59Can I say sys.argv1 and another one for six to access what I just want?
38:07Is that both for sys.argv?
38:10DAVID MALAN: Short answer-- yes, I think if I understand your question
38:13correctly, whereby, you're proposing to have
38:15many words at the end of the command.
38:17And you want to access those individual words.
38:19Absolutely.
38:20At some point, it gets a little fragile, I would say,
38:24if you're typing so many words at the prompt that the order really matters.
38:28And so it turns out there's a lot of programs.
38:30And there's functionality in Python that can
38:32allow you to provide those values, like name or age
38:36or any number of other fields in any order
38:39you want, but a pass in a bit more information textually
38:43that tells the program how you want to use it.
38:45So in short, what you're describing is possible.
38:47And let me do a small incarnation of it as follows.
38:51Let me propose that we go back to my code here.
38:54And let's propose that we actually now want
38:56to support multiple values at the prompt.
38:58So there's going to be no such thing as too many arguments.
39:01Suppose that I want to generate name tags not just for David, but for David,
39:05for Carter, for Rongshin, for others in the group who
39:08all want their name tags as well.
39:10So I'm going to go ahead and do this.
39:11I'm going to get rid of my elif condition
39:13because I don't want to limit the maximum number of words
39:16that are typed at the prompt anymore.
39:17I instead want to iterate over every name at the prompt.
39:23So I'm going to say this.
39:24For arginsys.argv, go ahead and print out this time, arg.
39:32So what am I doing here?
39:33Well, even though the syntax is a little different,
39:36the idea's the same as before when we've had loop.
39:38I'm using a for loop to iterate over a list.
39:42The list in question here is sys.argv.
39:45Arg is a variable that I'm creating on the fly.
39:48The for loop is going to make sure that the first time through this loop, arg
39:51is set to the first word on the command line.
39:53The second time through the loop, Python's
39:55going to make sure that arg is now set to the second thing on the command line
39:58and so forth.
39:58That's just how a for loop works.
40:00It updates the variable for us.
40:02I don't have to call it arg.
40:03I could call it name so long as I change it to name in both places.
40:07But arg is reasonable if I'm iterating over arguments more generally.
40:10If I now run this program, though, unfortunately, there's
40:14a little bit of a bug.
40:16Even if I type in David and Carter and Rongshin,
40:20I'm not going to get just three name tags.
40:25In your mind, does anyone see the bug I'm about to trip over?
40:29It's not a huge deal if I've got enough name tags to go around.
40:34But I'm going to be wasting one because this
40:36is going to print not three, but four name tags, whereby, the first contains
40:40the name of the program itself.
40:42Maybe not a big deal.
40:43Maybe that's the sticker we don't bother handing out, but it's wasteful.
40:46And it does look wrong.
40:47So how could we get access to not all four elements of argv
40:52but just a slice of argv?
40:54And this is actually a technical term in Python and some other languages.
Slices
40:58To take a slice of a list means to take a subset of it
41:01maybe from the beginning, maybe the middle, maybe the end.
41:04But a slice is a subset of a data structure like a list.
41:08Well, how do I actually do this in code?
41:10Well, in Python, it's actually very easy to take a slice
41:14of a list that is a subset thereof.
41:16You can simply do this.
41:17At the end of the list name, sys.argv in this case, you can use square brackets.
41:22And then in those square brackets, you can
41:24specify the start and the end of the list that you want to retain.
41:29I want to start at element1, not zero.
41:32I want to start at element1, and I want to just go to the end.
41:36So I'm actually going to omit a second number altogether.
41:38It's not necessary to have a second number.
41:40But I do need that colon because this is going to give me a slice of the list.
41:44It's going to give me a slice of the list that
41:46starts at location1, not zero.
41:48And the colon and then a blank just means
41:51it's going to give me everything else.
41:52So this is in equivalently going to slice off the first element of the list
41:56and give me a new list that contains just those three human names, not
42:00the name of the file itself.
42:02Let me try running this again.
42:03I'm going to run Python of name.py, David Carter Rongshin.
42:07This time hopefully, I'm going to get three and only three name tags,
42:11hitting Enter.
42:12And indeed, I've done now just this.
42:15So again, using some relatively simple syntax in Python,
42:18we can use square brackets not just to go to specific elements like bracket0
42:22or bracket1.
42:23We can also get subsets of the list, slices of the list
42:26by doing bracket something colon something where each of those
42:30some things is a number, the beginning or the end,
42:32and they're optional depending on whether you
42:34want all of them or just some.
42:37Any questions now on this version, which adds the loop and these slices
42:42with that new syntax?
42:45AUDIENCE: Can we slice starting from the end of the argument-- argument vector?
42:50DAVID MALAN: You can.
42:51You can slice something from the end of the argument vector.
42:54And this might blow one's mind a little bit.
42:57Let me go ahead and do this.
43:00Let's see.
43:00Let me go ahead and do negative one at the end.
43:03Using a negative number here and running the same command,
43:06we've just uninvited Rongshin from receiving a name tag here.
43:10So if you use a negative number, it has the effect
43:12of counting in the other direction from the end of the list.
43:17A good question there.
43:18Other questions now on slices, on looping over sys.argv?
43:23AUDIENCE: Hi, so I remember very early on when
43:26we were talking about only having two decimal places in float value.
43:34Is that in the same vein, like, because we use the code on 0.2F?
43:42Is that the same thing then?
43:44Why would the F be included then in the 0.2F as opposed to here when you just
43:50have the numbers?
43:51DAVID MALAN: A really good question.
43:53And it's just the short answer's that context matters.
43:56So there's only so many keys on our keyboard.
43:59And so we sometimes use the same symbols for different things.
44:02So what you're alluding to is the format code
44:05in an F string for actually formatting a number using a colon, using a period,
44:10using a number, using the letter F and so forth.
44:13And that is very specific to the F string feature of Python.
44:16This case has nothing to do with any of that syntax per se.
44:20This is just using a colon in a different context
44:22to solve this problem to implement a slice.
44:25The authors of Python could have chosen another symbol.
44:28But honestly looking down at my keyboard here,
44:29we don't have that many to choose from that are easy to type.
44:32So sometimes they have different meanings.
44:34A good question as well.
44:36Allow me to propose now, that we take things further
44:39and move away from using only those modules, those libraries that Python
Packages, PyPI, pip
44:43comes with to talk about more generally packages that exist.
44:47One of the reasons that Python is so popular and powerful these days
44:51is that there's a lot of third-party libraries
44:54out there as well, otherwise known as packages.
44:56Strictly speaking, Python itself has a term of art
45:01called a package, which is a module essentially
45:04that's implemented in a folder, not just a file but a folder.
45:08But more generally, a package is a third-party library that you,
45:12that I can install on our own Mac or PC or our cloud server
45:16and gain access to even more functionality
45:19that other people have implemented for us.
45:21Now, one of the locations you can get all of these packages
45:24is called the PYTI website, the Python Package Index which lives at this URL
45:30here.
45:31And this is a website that is searchable via the command line,
45:34as well as via the web, that allows you to download and install
45:37all sorts of packages.
45:39Even CS50 has some of its own packages in services like these.
45:43Now, there's a fun one out there that's a throwback to a command that's
45:46been around for years in command line environments called cowsay.
45:49Cowsay is a package in Python that allows you to have a cow say something
45:55on your screen.
45:56If curious to read up on it, its own documentation
45:58is on pi.py.org specifically at this URL here.
46:02But how do you actually get the package into your system?
46:06Well, technically, you could figure out how to download the file
46:09and maybe unzip it and put it into the right location on your Mac or PC.
46:13But nowadays, a lot of languages, Python among them,
46:15has what's called its own package manager.
46:18This one here called pip which is just one.
46:20So pip is a program that generally comes with Python itself, nowadays,
46:25that allows you to install packages onto your own Macs or PCs
46:29or cloud environment by just running a command.
46:32And then voila, you have access to a whole new library in Python
46:36that didn't come with Python itself.
46:38But now it's available on your system for you.
46:41Let's go back to VS Code here.
46:43And in my terminal window, I'm going to go ahead and type pip install cowsay.
46:48Now, what's going on here?
46:49Pip is the command, the package manager.
46:51And I want to install what package?
46:53The package called cowsay.
46:55I'm going to go ahead and hit Enter here.
46:56And after a little bit of output, it has successfully installed cowsay.
47:00Now, what does that mean?
47:01That means I can now go about importing this into my own code.
47:05Well, let's go ahead and see what this means.
47:07So let me go ahead and create a new file with code called say.py
cowsay
47:11because I want something to be said on the screen.
47:13And in my new tab here, I'm going to go ahead and import cowsay,
47:17which presumably is now installed.
47:19I'm now going to import sys as well because I'd
47:22like to use some command line arguments in this program
47:25just so that I can run it quickly.
47:26And without using the input function, I can get the user's name
47:30immediately from the prompt.
47:31And let me go ahead and do this.
47:33I'm going to do a bit of error checking proactively this time.
47:35And rather than use less than or greater than, I'm
47:37this time going to say if the length of sys.argv does equal 2.
47:43So if the human is provided just the name
47:45of the program and their own first name, we're good to go.
47:49I'm going to do the following.
47:51I'm going to call a function called COW in the package called cowsay.
47:56And I'm going to pass in a string, hello, comma.
48:00And then as in the past, I'm going to pass in just one string
48:03because according to its documentation, it's not like print.
48:06I can't pass in comma this, comma that.
48:08I can only pass in one string.
48:09So I'm going to concatenate it the contents of sys.argv, bracket1.
48:14So long as then I type in my name David after the name of this program,
48:20it should end up in sys.argv1 in which case, this line five of code
48:24should concatenate hello with my name with a space in between.
48:28And apparently, a cow is going to say it.
48:30So let's see what happens here.
48:32Let me go ahead and clear my screen and increase
48:35the size of my terminal window.
48:36Let me go ahead and run Python of say.py and type my name David and Enter.
48:42There is the program called cowsay.
48:44It literally has a cow say something on the screen.
48:47And this is a throwback to a program from yesteryear
48:50that tended to come with a lot of systems.
48:53This is otherwise known as ASCII art.
48:55It's a textual way using just keys on your keyboard
48:57to print pictures of sorts on the screen.
49:00Now, we can really go down the rabbit hole here.
49:02And there's questionable academic value of doing so.
49:05So I'll do so just once.
49:06Turns out the cowsay package comes with other functions as well.
49:10One of those functions, for instance, is T-Rex.
49:13And if I now increase the size of my terminal window,
49:16we'll perhaps see where we're going with this.
49:17Let me now run again, Python of say.py.
49:20This time, let me not provide my name just to see if it's broken.
49:23It's still OK because we have that if condition
49:26if the length of sys.argv equals equals 2 and only if it equals equals 2,
49:31do we do anything.
49:32That's why we're not seeing anything here.
49:34Let me go ahead and cooperate now, say.py space David.
49:38And it's no longer a cow.
49:40But if I zoom out on my screen, a T-Rex.
49:44Why?
49:45Just because these are the things you can do once you know how to program.
49:48You can even package them up and make them freely available to others
49:51as open source software.
49:52For us, it's demonstrative of a feature more generally here
49:56namely being able to install these third-party packages and how
49:59you might do so in Python.
50:01Now, I'll leave this up on the screen for a moment
50:03and see if there's any questions about cows
50:06or Tyrannosaurus rex's or packages more generally.
50:11I'm really qualified to speak to just one of those.
50:14AUDIENCE: Hi, I've got two questions it's a bit earlier than what's
50:19supposed to be.
50:20So the first question is the packages that you're
50:25calling to use in the program, are they the same
50:32as, let's say, something Java the same as calling a class, a Java file
50:42in order to use its functions?
50:45And my second question is, what's the actual purpose of using command line
50:52arguments as you used because is not really the best way to, as you say,
51:00be user friendly where as in let's say the person who's
51:06using the program doesn't know what they want--
51:10what the program's asking them?
51:12DAVID MALAN: Really good question.
51:13The first question about the comparison with Java, Python packages
51:17are similar to Java packages where you have something.something.something
51:20at the top of your program that gives you
51:22access to a class or something else.
51:24Python itself supports classes.
51:26More on those down the road.
51:27And you can do very similar things in Python as you can do with Java.
51:32But the analog really is Python packages to Java packages here.
51:36As for command line arguments, you ask a good question.
51:39Why do we use them, especially if they are literally user friendly?
51:42They're a little less user friendly to people
51:45who aren't in this Zoom to be honest.
51:47You and I as we learn more and more about programming
51:50and more about command line arguments, I daresay
51:52we'll become more comfortable with and tend
51:54to prefer the ability to customize commands using these command line
51:58arguments.
51:59Why?
51:59Productivity.
52:00It tends to make you faster because you get
52:02into the habit of knowing exactly how you
52:03can configure your software without having to manually answer questions.
52:07And case in point.
52:08All of this time have we been running Python of something.py.
52:13You could imagine not doing that.
52:15You can imagine typing only Python, hitting Enter.
52:18And then you're prompted for the name of the file you want to run.
52:20So you type in something.py, and then it runs.
52:23Not a big deal, but I would argue that over time, you're
52:26going to get a little tired of that TDM.
52:28And you would much prefer to just automate
52:29the command again and again and again, especially with little conveniences
52:33like being able to hit up and down in your keyboard history
52:36so as to rerun those same command.
52:38Automation is big too if you emerge from a class like this
52:41and start using Python to automate processes
52:44at work or for personal projects or the like,
52:46the ability to specify all of your inputs on the one line
52:49just means you can get work done more quickly.
52:51So hands down, absolutely.
52:53Using command line arguments is a more arcane feature of systems
52:58that most of us are no longer as familiar with because
53:01of Windows and Mac OS and other operating systems that
53:03have buttons and GUIs and menus.
53:05But the more comfortable you get with programming,
53:08I daresay the more you will tend to prefer these capabilities because they
53:12allow you to do things more quickly.
53:15With that said, allow me to propose that we take a turn toward, yet,
53:19another package that's particularly popular and just as easy
53:23to install all toward an end of using APIs.
APIs, requests, JSON
53:27Now, APIs are not something that's Python-specific.
53:29More generally, an API is an application programming interface.
53:33And it can refer to Python files and functions.
53:37But often, APIs really refer to third-party services
53:41that you and I can write code that talk to.
53:44Many APIs, but not all, live on the internet these days
53:47so that so long as you have a browser or so long
53:50as you have some experience with Python programming or programming
53:53in any language, you can write code that in effect pretends to be a browser,
53:58connects to that third-party API on a server,
54:01and download some data that you can then incorporate into your own program.
54:05Now, how do you do this?
54:07Well, Python has a very popular package that you
54:10can install via pip called requests.
54:12The requests library allows you to make web request,
54:16internet request using Python code essentially
54:20as though you were a browser yourself.
54:22You can automate, therefore, the retrieval of URLs
54:25that start with HTTP or HTTPS.
54:28The documentation for this library is that a URL like this,
54:31but it too can be installed at the command line.
54:33And even though it's third party, it's one
54:35of the most popular and commonly used packages out there in Python.
54:38And this too is one of the reasons again that Python is so popular.
54:42There's just so many solutions to problems
54:44that you and I have or are invariably going to have
54:47when we write projects of our own.
54:49There's just a really vibrant ecosystem, a really vibrant community
54:53of open source software that's that easy for us to install.
54:57Let me go back to my terminal window now and run
54:59pip install requests in order to install this package on my own system.
55:03And after some lines of output, I'll see that it's successfully installed.
55:06Now, let's go ahead and create a new file here.
55:09For instance, itunes.py.
55:11It turns out that Apple has its own API for their iTunes service.
55:15The software that provides you with the ability
55:17to download and search for music and songs and other information as well.
55:20And it turns out that-- let me go back over to my computer
55:23here and open up a browser like Chrome.
55:25And let me go ahead and visit this URL here,
55:27https://itunes.apple.com/ search?entity=song&limit=1&term=weezer.
55:32Search?entity=song& limit=1&term=weezer.
55:39Now, I constructed this URL manually by reading
55:42the documentation for Apple's API--
55:44application programming interface for iTune.
55:47And what they told me is that if I want to search for information about songs
55:51in their database, I should specify entity
55:54equals song so that songs and not albums or artists or something like that.
55:58If I just want to get back information on one song,
56:00I'm going to provide limit equals 1.
56:02And if the band I want to search for, the artist is Weezer,
56:05I should specify term equals Weezer.
56:07So with this, if I go ahead and hit Enter and visit this URL,
56:11I actually end up with a text file in my Downloads folder on my Mac.
56:15If I go ahead and open that text file that my browser just downloaded,
56:18we'll see all of this text here, which at first glance
56:20might look a bit cryptic, but it actually follows a pattern.
56:23Notice this curly brace at the start and notice this
56:26closed curly brace at the end.
56:28Notice this open square bracket here and notice this closed square bracket here.
56:32And in between those pieces of syntax are
56:35a whole bunch of strings and values.
56:37In fact, a whole bunch of key value pairs.
56:40What we're looking at here is a standard text format known as JSON--
56:43JavaScript Object Notation, which yes, is technically related to yet,
56:47another programming language called JavaScript.
56:49But JSON itself is typically used nowadays
56:52as a language agnostic format for exchanging data between computers.
56:57By language agnostic, I mean you don't have to use JavaScript.
57:00You can use Python or any other language to read JSON or write it as well.
57:05And it's a completely text-based format, which
57:07means that if I visit that URL with my browser, what gets downloaded
57:11is just a bunch of text.
57:12But that text is formatted in a standard way using curly braces
57:16and square bracket using quotes and some colons that ultimately contains
57:21all of the information in Apple's database on Weezer's song, at least,
57:25the first one because I limited it to one in their database.
57:29And that's an API, an application programming interface.
57:32A mechanism whereby I can access data on someone else's server
57:35and somehow integrate it into my own program.
57:39Now, of course, my browser, Chrome, is not something I wrote.
57:42I should actually write some Python code that perhaps pretends
57:45to be a browser to grab this same data.
57:47So let's do that.
57:48Let me go back to VS Code here.
57:50And let me write a program with code, itunes.py.
57:53And we're going to write some code via which I can then use the iTunes API
57:59and in turn, Python to get information about any band that I might want.
58:03I'm going to go here and import first the requests
58:06library, which I installed earlier in order to make those HTTP requests.
58:11I'm going to go ahead and import the sys library via which I'll have the ability
58:15to use command line arguments like specification of the band
58:18that I want to search for if not Weezer.
58:20And then down here, I'm going to go ahead and insert some error checking
58:24to say if the length of sys.argv does not equal to--
58:30so if the user does not provide me with the name of the file
58:33they want to run and the name of a band, and that's it, you know what.
58:36Let's just go ahead and exit for now.
58:39I could provide a more explanatory message.
58:41But for now, I'm going to keep things simple
58:43and just exit the program prematurely so that I can trust hereafter
58:46that sys.argv has what I want.
58:49And now, I have the opportunity to use the requests library to write
58:54some Python code that effectively is pretending
58:56to be a web browser so as to connect to that same HTTPS
59:00URL on Apple's own server.
59:03So now that I've guaranteed that the user has typed in
59:06not just the name of the file, but also the name of a band at the prompt
59:10giving me a length of two for sys.argv, let's go ahead
59:13and execute request stockget, which is a function inside of the request package
59:18that will literally get some response from a server.
59:21And the URL that I want to get is the exactly the same as before.
59:24https://itunes.apple.com/ search?entity=song& limit=1&
59:33term=previouslyweezer.
59:36But let's make this program a little interactive
59:39and actually allow the human to specify at the command line what
59:42artists they'd like to search for.
59:44So I'm going to go ahead and close my quote early and just
59:47append using the concatenation operator as in the past, sys.argv bracket1.
59:54And now, it actually be nice to store the response
59:57from the server in a variable.
59:59So I'm going to go ahead and say response equals
1:00:01and to store all of the response that comes back
1:00:04from the server in a variable called response.
1:00:06Down here now, I'd like to just understand
1:00:08what the server's returning to me to make sure I know how next to proceed.
1:00:12So this isn't going to be very pretty yet.
1:00:14But I'm going to go and print out response.json,
1:00:17which ensures that the data I'm getting back is formatted on my screen
1:00:21as exactly that, JSON, the same text format as we saw on my screen.
1:00:25It's not a useful program yet.
1:00:27I'm really just learning along the way.
1:00:29But let me go ahead now and increase the size of my terminal window
1:00:32and run Python of itunes.py and type in the name of a band like Weezer
1:00:37and hit Enter.
1:00:39And what we see on the screen formatted almost the same
1:00:42as before is exactly that same text.
1:00:44But what you'll see here is that this has been standardized now
1:00:48as a Python dictionary.
1:00:50What indeed Apple's returning is technically a JSON response,
1:00:54JavaScript Object Notation.
1:00:55But Python, the request library is converting it
1:00:59to a Python dictionary which happens to use wonderfully coincidentally, almost
1:01:04the same syntax.
1:01:05It uses curly braces to represent the dictionary here
1:01:08and a close curly brace to represent the end of it here.
1:01:10For any lists therein, it uses a square bracket here
1:01:14and a closed square bracket down here.
1:01:16It uses quotes-- single quotes in this case or equivalently double quotes
1:01:20to represent the keys in that dictionary.
1:01:23And after a colon, it stores the value of that key.
1:01:27And so you'll see that indeed we have a result count key whose value is 1,
1:01:31but then a more interesting Result key called results whose
1:01:35value is this entire list of data.
1:01:38Now, honestly, this is such a big blob of text
1:01:41that it's going to take me forever to wrap my mind around what I'm seeing.
1:01:44So let me propose temporarily we use another library in Python that
1:01:48will allow me to format my data a little more cleanly.
1:01:52It turns out that Python also comes with a special library called
1:01:56JSON that allows you to manipulate JSON data
1:01:59and even just printy print it that is formatted in a way that's going to be
1:02:02way easier for you and I to understand.
1:02:04So let me go back to my code here.
1:02:07Let me shrink my terminal window.
1:02:09And let me propose that just temporarily again we do this.
1:02:13Let me import this additional library, JSON, which comes with Python.
1:02:16So I don't need to install it manually with pip.
1:02:19And let me go ahead now and not just print out
1:02:21response.json which was that big blob of hard-to-understand text.
1:02:26Let me go ahead and use one other function here called json.dumps
1:02:31for dump string and pass to that function that response.json return
1:02:36value.
1:02:37So again, I'm just introducing another function
1:02:39who I claim has a purpose in life of pretty printing,
1:02:43nicely formatting on the screen the exact same information.
1:02:46And I know this from the documentation having done this before.
1:02:49But I'd like things to be nicely indented.
1:02:51And according to the documentation, if I pass in a named parameter of indent
1:02:56equals 2, that's going to indent everything at least two spaces.
1:02:59I could do four or something else.
1:03:01But it's going to be enough to help me wrap my mind around what
1:03:04the data is I'm getting back.
1:03:05Because again, I'm just learning along with you.
1:03:08So let me increase the size of my terminal window again.
1:03:10Let me run Python of itunes.py.
1:03:12And again, let's search for Weezer and hit Enter.
1:03:15And now, notice it's still a little bit cryptic
1:03:18because there's a lot going on here.
1:03:20But my gosh, I can totally read this more easily now.
1:03:24Notice now that I still see the first curly brace, which means hey,
1:03:27this is a dictionary in Python.
1:03:29A collection of keys and values.
1:03:31The first key is called result count.
1:03:33It happens to be displayed in double quotes now.
1:03:35But that's just an issue of formatting.
1:03:37It could be double or single so long as we're consistent.
1:03:39The value of that key is one.
1:03:42Why?
1:03:42Well, I told the URL to only limit the responses to one Weezer song
1:03:46so I've gotten a result set of one.
1:03:48If I increase that limit, I could probably get more.
1:03:51Then the interesting part of this response is really the data itself.
1:03:55Notice in the results key here, there's a really big value.
1:03:59The value is a Python list as implied by this square bracket.
1:04:05What does this list contain?
1:04:07Well, I know from skimming it earlier that this contains one dictionary.
1:04:11And that's why we see another curly brace here.
1:04:15So again, if this gets a little more complicated,
1:04:18keep in mind that a dictionary is just a collection of key value pairs.
1:04:22And Python uses curly braces to indicate as much.
1:04:25It is perfectly reasonable for a dictionary
1:04:28to be inside of another dictionary if the value of some key itself
1:04:33is another dictionary.
1:04:35So this is a common paradigm.
1:04:36And even though it might seem a bit cryptic,
1:04:38it's just something that allows us to associate more keys with more value.
1:04:42Now, most of this information, I probably don't care about.
1:04:45For instance, according to Apple, the unique identifier for Weezer
1:04:48is apparently 115,234.
1:04:52That might be useful if I'm making my own database
1:04:54and I want this to be searchable.
1:04:56But for today's purposes, all I care about is the name of the track,
1:05:00otherwise called track name as key.
1:05:02And the first song and only song because we limited it to one
1:05:05that we got back from iTunes here is the song
1:05:08that you might know by Weezer called Say It Ain't So.
1:05:12So now, I have a bit of a clue if my goal here is to implement a program
1:05:17called itunes.py that doesn't just dump the response from the server,
1:05:21which is admittedly very cryptic--
1:05:22but to print out all of the songs that iTunes has for the band called Weezer,
1:05:28maybe I can iterate over this somehow.
1:05:30So let me backtrack.
1:05:31Here's the key call track name.
1:05:34It is inside of a dictionary that is the value of results here.
1:05:39So how can I go about getting this?
1:05:42Well, let me go ahead and try this.
1:05:44Let me go ahead and shrink my terminal window back down
1:05:47and let me propose now for one final flourish.
1:05:49We don't just lazily print out the contents
1:05:52of that response because that's not interesting or pretty for anyone.
1:05:55Let's do this.
1:05:56Let me go ahead and create a new variable
1:05:58just for the sake of discussion called O for object.
1:06:01And I'm going to go ahead and call o equals response.json just
1:06:06to store that JSON response specifically in a variable called o,
1:06:11but I could name it anything I want.
1:06:13And now, I'm going to do this.
1:06:14For each result in that object's key called results,
1:06:21go ahead and print out that result's track name.
1:06:26And notice I have used exactly the same capitalization.
1:06:29Track name has a capital N. Result is all lowercase.
1:06:32And let me rewind before we run the actual program.
1:06:35In line eight, we are making an HTTP request
1:06:38using Python to the server just like you and I as humans type URLs
1:06:41into a browser and hit Enter.
1:06:43This is the Python equivalent thereof.
1:06:45I am then on line 10 just grabbing from that variable that
1:06:49contains the server's response, the JSON object that I care about.
1:06:53The thing between those curly braces at the very top and the bottom.
1:06:57But because we've poked around and because I
1:07:00read the documentation earlier, I know that that object
1:07:03has a key called results.
1:07:06And that results key again is a list.
1:07:08Now, at the moment, that list contains only one song,
1:07:11Say It Ain't So, because I limited my response to one.
1:07:14But even so, my loop will work.
1:07:16It's just going to iterate once.
1:07:17And each time through that loop, it's going
1:07:19to print the current result's track name.
1:07:22If I want to make this even more interesting,
1:07:24let me change this limit now from 1 to 50
1:07:26so I'll at least get back 50 track names instead.
1:07:29Let me go ahead now and increase the size of my terminal once more
1:07:33and go ahead now and run Python of itunes.py searching again
1:07:36for a band like Weezer.
1:07:38And here we go.
1:07:40And voila, there are 50 songs that iTunes has for Weezer.
1:07:44And if we scroll back up to the top here,
1:07:47we'll see that the very first one there is, indeed, Say It Ain't So.
1:07:51But now, we got Undone--
1:07:52The Sweater Song, Buddy Holly.
1:07:54Apparently another rendition of Say It Ain't So perhaps
1:07:56from another album, another Buddy Holly undone, my name is Jonas, and so forth.
1:08:01Questions now on this program which integrates Python with a real world
1:08:06third party API?
1:08:10AUDIENCE: Yeah, hi.
1:08:11Can we use break instead of system.exit?
1:08:15DAVID MALAN: Good question, but no.
1:08:16Break again is used to break out of things like loops like we saw earlier.
1:08:21Sys.exit is used to break out of the whole program itself.
1:08:25Use break for loops for now and use sys.exit to terminate
1:08:28the whole program.
1:08:29Good question.
1:08:30Other questions now on this program are others?
1:08:32AUDIENCE: From where we bring the name of the key results?
1:08:36DAVID MALAN: From where do we get the name of the key?
1:08:38AUDIENCE: Results itself.
1:08:40Yeah, and can we change the results, the name?
1:08:42DAVID MALAN: You cannot.
1:08:43So we could in our program.
1:08:45So the keys that come back in that JSON response, to be clear,
1:08:48come from iTunes.Apple.com.
1:08:51Some team of engineers decided for us what all of those keys would be called,
1:08:55including track name, results, result count, and everything else.
1:08:59You and I can absolutely store those same values in variables
1:09:03just like I'm doing here with O, just like I'm doing here with result.
1:09:06You can rename those keys anything you want using Python variables.
1:09:10But the JSON response is coming from that third party server.
1:09:14Other questions.
1:09:15AUDIENCE: Yes, sir.
1:09:16So I have a question related to cowsay package.
1:09:21So like, yes.
1:09:23So sir, what sort of ASCII graphics is it capable of putting?
1:09:29DAVID MALAN: The cowsay package.
1:09:31I would refer you to the URL in the slides
1:09:33earlier if only because it's more thorough.
1:09:36They have not just cows, but Tyrannosaurus rex's
1:09:38and several other animals as well.
1:09:40I should emphasize that this is not a package I suspect
1:09:42you will use much in the real world.
1:09:44It's really just meant to be representative of the types of packages
1:09:47you can install.
1:09:48But allow me to refer to the documentation for what more is there.
1:09:51But ASCII art is all we had before there were emojis, let alone GIFs and JPEGs
1:09:57and pings.
1:09:57But it's what's is immortalized in cowsay.
1:10:00Well, allow me to transition us back now to one final capability of Python which
Custom Libraries
1:10:06is that you yourselves have the ability to make your own libraries.
1:10:10Up until now, we've been writing all of our functions in our one
1:10:14file, Hello py and everything since.
1:10:17And now that we've introduced modules in Python, random and statistics,
1:10:22we can import those that come with Python.
1:10:25But that's other people's code as well.
1:10:26And we've now used pip, this package manager to install
1:10:29third-party packages as well in the system
1:10:31and using other people's code still.
1:10:33But to come full circle, what if you yourself
1:10:36find yourself implementing the same kinds of functions again and again,
1:10:40or you find yourself opening up old programs,
1:10:42copying and pasting code you wrote into new programs
1:10:45because you have the same problem yet again?
1:10:47A good practice would be to somehow bundle up that code you keep reusing
1:10:53and make your own Python module or package.
1:10:56You can keep it local on your own Mac or PC or cloud server.
1:10:59Or you can go through the steps of actually bundling it up, making
1:11:02it free and open source, and putting it on something like py, pi for others
1:11:06to use as well?
1:11:07OK, I'm going to go ahead and run code of sayings.py
1:11:10to create a brand new file called sayings.py which
1:11:13is going to be my own sayings module.
1:11:15I'm going to define a couple of simple functions in there.
1:11:18I'm going to define a Hello function that's going
1:11:20to take a name parameter as input.
1:11:22And that function is simply going to print out
1:11:25an F string that contains hello, comma, and then in curly braces,
1:11:28whatever that person's name actually is.
1:11:31Then I'm going to go ahead and define one other function,
1:11:33a goodbye function, that has def, goodbye, also
1:11:37takes a name as its input.
1:11:39And then that prints out by contrast and F
1:11:41string that says goodbye, comma, and then in curly braces, name.
1:11:45And now, just for good measure just so I can be sure
1:11:48that these functions are working as expected,
1:11:50I'm going to go ahead and define a main function in here
1:11:53too just for the purposes of testing.
1:11:55And I'm going to go ahead and define a main function that
1:11:57simply does a couple of tests.
1:11:59For instance, it calls Hello of, quote, unquote, "world" shall we say?
1:12:05And then it's going to call good bye of, quote, unquote, "world" as well.
1:12:09And hopefully what I'll see on the screen then
1:12:11is Hello world and Goodbye world when I run this program.
1:12:13Of course, as always, I need to explicitly tell
1:12:16Python to call that function.
1:12:17So I'm going to call main at the very bottom of this file.
1:12:20All right, let's try it out.
1:12:21Python of sayings.py, Enter.
1:12:24And indeed, I see Hello world and Goodbye world.
1:12:26And so I think it's reasonable for me to assume
1:12:28that these functions, albeit simple, are pretty correct at this point.
1:12:32But now, suppose that I want to use these functions as though I've indeed
1:12:36created my own library, my own Python module and that makes available
1:12:40a Hello function for me or anyone else who wants to use
1:12:42it or a Goodbye function as well.
1:12:44Well, let me go ahead and open up again say.py but start fresh.
1:12:49And rather than have the cow say anything, let me go ahead
1:12:52and have my own library do the talking.
1:12:55So I'm going to go ahead and as before, import sys so that I
1:12:58have access to command line arguments.
1:13:00And from my own module called sayings, I'm going to import Hello.
1:13:05So because I created a file called sayings.py, I can say from sayings.
1:13:10And it's inferred by Python that I mean sayings.py,
1:13:13at least in this current directory.
1:13:14But I specifically ain't going to import just one of the functions
1:13:17for now, namely Hello.
1:13:19And now, I can do something like this.
1:13:20If the user obliges by giving me two command line arguments, which
1:13:24I can check by just checking the length of sys.argv,
1:13:27I'm going to then go ahead and call this new Hello function passing
1:13:32as its input, sys.argvbracket1, which should hopefully be the person's name
1:13:36which I'm going to expect them to type at the prompt.
1:13:38So here we go.
1:13:39I'm going to go down to my terminal window,
1:13:41run Python of say.py and my own name because I want my own name to end up
1:13:46in the command line arguments and therefore, be part of the Hello
1:13:49so when I hit Enter in just a moment, I should hopefully see Hello,
1:13:52comma, David.
1:13:53So here we go, Enter.
1:13:55And huh, I see Hello world, Goodbye world.
1:13:59And then I see Hello, David.
1:14:01So why is this happening?
1:14:04Well, it turns out even though I've done everything
1:14:06according to our own past practice, it's not really
1:14:10the right way to go about calling main after all.
1:14:13If I'm blindly calling main here at the bottom of my file, that
1:14:17means whenever this file is loaded by Python, main is going to get called.
1:14:20And unfortunately, that's true even if I'm importing this file or just
1:14:25a function from this file as I am here in my say.py program.
1:14:29This is to say on line three here, when I say from sayings,
1:14:32import Hello, this effectively tells Python
1:14:34to go find that module, sayings.py, read it from top to bottom, left to right,
1:14:39and then import specifically the Hello function.
1:14:41Unfortunately by the time Python has read the file from top
1:14:44to bottom, left to right, that last line of code recall is to call main.
1:14:49Main gets called no matter what.
1:14:51So really, the right way to go about using a main function, which
1:14:55does solve that problem of ensuring that we can order our functions
1:14:58however we want, and all the functions will
1:15:00be defined at the time they're invoked, I
1:15:03shouldn't be unconditionally calling main at the bottom of this
1:15:06or really any of my programs.
1:15:08I should instead use this technique.
1:15:09I should say if__name__=="__main__", then and only then should you actually
1:15:22call main.
1:15:23Well, it turns out that this variable is a special symbol in Python, __name__.
1:15:30And notice that VS Code because of its font
1:15:32isn't quite showing those two underscores.
1:15:34But they're indeed there to the left and the right.
1:15:36This is a special variable whose value is automatically set by Python to be,
1:15:40quote, unquote, "main" when you run a file from the command line
1:15:45as by running Python of sayings.py.
1:15:48So watch what happens now with this additional conditional in sayings.py.
1:15:52If I run Python of sayings.py, it still works as before because name will be
1:15:59automatically set to __main__ when I run this file using Python of sayings.py.
1:16:07But notice this.
1:16:09Name is not going to be set to, quote, unquote, "main."
1:16:12It's going to be set to something else, technically the name of the module
1:16:15when I instead import the file like I do here.
1:16:19So this highlighted line of code even though it
1:16:21will cause Python to go find sayings.py, read it from top to bottom,
1:16:25left to right, it's going to ignore the call to main this time
1:16:27because it's wrapped in that conditional.
1:16:29In this case, when I'm importing a file and not running it directly
1:16:33at the command line, main will not get called
1:16:36by definition of that names value.
1:16:38So let me go ahead and try this.
1:16:40Instead of running Python of sayings.py, which
1:16:42is the module, which contains that conditional main,
1:16:45let me go ahead here, run Python of say.py,
1:16:49which is the program here before me that imports Hello from sayings.
1:16:54But because of that conditional, it's not
1:16:56going to say Hello to anyone else except me in this case.
1:17:00All right, we're here at the end of our week.
1:17:02It's only appropriate, I think, to import something other than Hello.
1:17:06Why don't I go ahead and import not Hello, but Goodbye from here.
1:17:09Let me go ahead and call Goodbye instead of Hello.
1:17:12And this time when I run Python of say.py,
1:17:15I'm not going to type my own name.
1:17:16Allow me if I may to type in the whole world
1:17:18so that our final sentiment today is Goodbye world.
1:17:22Indeed, that's it for this week.
1:17:23We will see you next time.