See all freeCodeCamp.org transcripts on Youtube

youtube thumbnail

Harvard CS50’s Introduction to Programming with Python – Full University Course

15 hours 57 minutes 47 seconds

🇬🇧 English

S1

Speaker 1

14:00:00

Whether or not your code is adhering to your own type hints. And that program here is called MyPy. And it's just 1 of several. But this one's particularly popular and can be easily installed in the usual way with pip install MyPy.

S1

Speaker 1

14:00:13

And its own documentation is at this URL here. But we'll use it quite simply to check whether or not our variables are indeed using the right types. So how can we go about doing this? All right, let me go back here to VS Code, clear my terminal window, and in fact, erase meows.py as it currently was.

S1

Speaker 1

14:00:30

And let's implement a different version of meows that quite simply has a function called meow that does the actual meowing on the screen. And then I'm just going to go ahead and call that function down toward the bottom. I'm not going to bother with the main function just for simplicity so that we can focus, as always, only on what's new. So here we are defining a function called meow.

S1

Speaker 1

14:00:47

It's going to take a number of times to meow, for instance, n for number. And inside of this function, I'm going to do my usual for underscore in the range of n, go ahead and print quote unquote meow. So based on our earlier code, I think this is correct. I've not bothered defining the variable as I.

S1

Speaker 1

14:01:06

I'm instead using the underscore because I'm not using it anywhere. But I think I now have a working function whose purpose in life is to meow 0 or 1 or 2 or 3 or more times. Well, let's use this function. Again, not bothering with main.

S1

Speaker 1

14:01:17

I'm just going to keep my function at the very top because there's only 1. And I'm going to write my code here on line 6. So I'm going to give myself, I'm going to ask the user for a number. And I'm going to go ahead and prompt them in the usual way for that number of times to meow.

S1

Speaker 1

14:01:32

And now I'm going to go ahead and call meow on that number. Now, some of you might see what I've already done wrong. But perhaps I myself don't. So let me go into my terminal window and run Python of meows.py, the goal being to prompt me.

S1

Speaker 1

14:01:47

This seems to be working. I'm going to type in 3. And I would expect now the meow function to print out meow 3 times. Enter.

S1

Speaker 1

14:01:55

But no, there's some kind of type error here. Stir object cannot be interpreted as an integer. Why might that be? Why might that be?

S2

Speaker 2

14:02:07

Because the input function returns a string instead of an integer.

S1

Speaker 1

14:02:12

Exactly. The input function returns a string or a str, not an int. So in the past, of course, our solution to this problem has just been to convert the string to an int by using the int function. But now let me start programming more defensively so that, honestly, I don't even find myself in this situation at all.

S1

Speaker 1

14:02:30

Let me go ahead and do this. Let me add what's called a type hint to my function that explicitly specifies for meow what type of variable should be passed in. I'm going to go ahead now and change the very first line of my code in my function to specify that n colon should be an int. And this is a type hint.

S1

Speaker 1

14:02:50

The fact that I've added a colon, a space, and the word int is not creating another int or anything like that. It's just a hint, an annotation, so to speak, to Python that this variable on the left called n should be an int. Now, unfortunately, Python itself doesn't care. Because again, these type hints are not enforced by the language.

S1

Speaker 1

14:03:12

And that's by design. The language itself in the community prefers that Python be dynamically typed, not so strongly typed, as to require these things to be true. But if I run meows.py type in 3 again, the same error is there. But let me go about trying this mypy program, an example of a program that understands type hints and, if I run it proactively myself, can find bugs like this in my code before I, or worse, a user, actually runs and encounters something cryptic like this type error here.

S1

Speaker 1

14:03:43

Let me clear my terminal window and this time run mypy space meows.py. So I'm going to run mypy on my program, but I'm not running Python itself. When I hit Enter, we'll see this. All right, we see now that mypy found apparently an error on line 7.

S1

Speaker 1

14:04:01

Error, argument 1 to meow has incompatible type str expected int. So it's still an error message. But MyPy is not a program that my users would use. This is a program that you and I, as programmers, would use.

S1

Speaker 1

14:04:15

And because we have run this code now before we, for instance, released this program to the world, I can now see even before the code is called or run, oh, I seem to be using my argument to meow wrong. I had better fix this somehow. Well, I can actually go about hint adding type hints even to my own variables here so as to catch this another way, too. If I know on line 6 that I'm creating already a variable called number, and I know already that I'm assigning it equal to the return value of input, I could give mypy and toolslikeit another hint and say, you know what?

S1

Speaker 1

14:04:51

This variable called number should also be an int. That is to say, if I now start getting into the habit of annotating all of my variables and arguments to functions, maybe mypy can actually help me find things quite quickly as well before I get to the point of running Python itself. Let's go ahead and try this again. Mypy of meows.py and hit Enter.

S1

Speaker 1

14:05:13

And this time, notice that mypy actually found the mistake a little more quickly. Notice this time it found on line 6 that error, incompatible types in assignment, expression has type str, variable has type int. So before I even got to the point of calling meow, line 6, via this type int, When used and analyzed by mypy, has helped me find, oh, wait a minute. I shouldn't be assigning the return value of input to my variable called number in the first place.

S1

Speaker 1

14:05:42

Why? Mypy has just pointed out to me that 1 returns a str. I'm expecting an int. Let me fix this now instead.

S1

Speaker 1

14:05:48

All right, so let me clear my terminal window. And now let me do what most of you were probably thinking I should have done in the first place after all of these weeks. But now let me go ahead and convert the return value of input to an integer. For today's purposes, I'm not going to try to catch any exceptions or the like.

S1

Speaker 1

14:06:03

We're just going to assume that the user types this in properly. And now let me go ahead and run mypy of meows.py, having not only added 2 type ints to my argument, to my function, to my variable down here on line 6. And I've also now fixed the problem itself. Let me go ahead and run mypy and success.

S1

Speaker 1

14:06:23

No issues found in 1 source file. Now it's more reasonable for me to go and run something like Python of Meows And just trust that when I type in 3, at least I'm not going to get a type error. That is, I didn't mess up as a programmer with respect to the types of my variables. Why?

S1

Speaker 1

14:06:40

Because when I wrote the code in the first place, I provided these annotations, these hints, that inform tools like MyPy that my intention had better line up with what the actual code does. Let me pause here and see if there's now any questions on type hints or MyPy.

S3

Speaker 3

14:06:57

Is it common, or how common is it for those to be used? Or is it just that it's more used in more complex code, where it's more difficult to ensure that you're actually using the correct type in the way that you're using variables? DAVID MALAN HANSON-COPERNUCCI-HILLS

S1

Speaker 1

14:07:13

It's a good question, and it's rather a matter of opinion. Python was designed to be a little more versatile and flexible when it comes to some of these details, partly for writeability, to make it easier and faster to write code, partly for performance, so that the program like Python doesn't have to bother checking these kinds of details. We can just get right into the code.

S1

Speaker 1

14:07:31

The reality, though, is that strong type checks do tend to be a good thing for the correctness of your code. Why? Because programs like MyPy can find before your code is even run if there's already known to be an error. And it tends to be good for defensive programming.

S1

Speaker 1

14:07:48

So the situation, essentially, is that within the Python ecosystem, you can annotate your types in this way. You can use tools to use those type hints. But to date, Python itself does not enforce or expect to enforce these conventions. In larger code bases, in professional code bases, commercial code bases, probably, depending on the project manager or depending on the engineering team, they may very well want themselves to be using type ints.

S1

Speaker 1

14:08:15

Why? If it just decreases the probability of bugs. In fact, let me propose now that I imagine a situation where, instead of expecting that meow prints meow, meow, meow some number of times, suppose that I accidentally assume that the meow function just returns meow some number of times. We saw, for instance, when focusing on unit tests, that it tends to be a good thing to have functions that return values, be it an int or a string, rather than just having some side effect, like printing things out themselves.

S1

Speaker 1

14:08:46

So perhaps I'm still in that mindset, and I've just assumed mistakenly for the moment that meow returns a value, like meow, or meow meow, or meow meow meow, a big string of some number of meows, rather than just printing it itself, as it clearly does at the moment on line 3. And therefore, suppose that I accidentally did something like this. Rather than just getting the number and passing it to meow, suppose I did this. Suppose I declared a new variable called meows, the type of which I think should be str.

S1

Speaker 1

14:09:18

And suppose, again, I assume accidentally that meow returns to me a string of those meows so that I myself can then print them later. This would be a little more conducive, arguably, to testing my meow function. Why? Because I could expect that it's returning meow, or meow meow, or meow meow meow, separated by new lines, returning a str that I could then assert equals what I expect it to be in something like a unit test.

S1

Speaker 1

14:09:43

I'm not going to bother writing any unit tests now, But let's just suppose that's the mindset I'm now in. And so on line 7, I'm assuming that I want to assign the return value of meow to a new variable called meows, which I've annotated with this type hint as being a str, just so we can see another variable. This one's not an int, but a str instead. Well, let me go ahead and run this code now.

S1

Speaker 1

14:10:07

Python of meows.py, Enter, typing in 3. And you'll see a curious bug. Meow, meow, meow, none. Well, why is that?

S1

Speaker 1

14:10:16

Well, it turns out at the moment, my meow function only has a side effect. It just prints out meow some number of times. It doesn't explicitly return a value, as it would if there were literally the return keyword there. By default, then, When a function in Python does not explicitly return a value, its implicit return value is, in effect, none.

S1

Speaker 1

14:10:36

And so what we're seeing here is this. On line 8, because I'm assigning the return value of meow, which is none, to my meow's variable, line 3 is what's still printing meow, meow, meow. And line 8 is what's now incorrectly printing none, because I accidentally thought that meow returns a value, but it doesn't. So its return value is effectively none.

S1

Speaker 1

14:11:02

So I'm printing, very weirdly, the word none at the bottom. So how could I go about catching this kind of mistake, too? Like, I might make this mistake, but maybe with less frequency if I'm in the habit of annotating my code with this new feature called type hints. What you can do here is this.

S1

Speaker 1

14:11:20

Let me clear my terminal window to get rid of that artifact. And up here, let me additionally specify with some funny looking syntax that my meow function actually, by design, returns none. So you literally use this arrow notation in Python. When hinting what the return value of a function is, you would do this.

S1

Speaker 1

14:11:41

After the parentheses, a space, a hyphen, a greater than symbol, like an arrow, and then another space, and then the type of the return value. For now, it's indeed going to return none. But now, at least, I can catch it like this. If I now run not Python, but MyPy on my code, which would be a habit I'm now getting into if using type hints.

S1

Speaker 1

14:12:03

Check that I'm using all of my types correctly before I even run my program. We'll see that now mypy has found on line 7 that meow, quote unquote, does not return a value. And mypy knows that because I have proactively annotated my meow function as having none as its return value. So now mypy can detect that.

S1

Speaker 1

14:12:23

I should now realize, oh, wait a minute. I'm being foolish here. Meow clearly does not return a value. I should not be treating it like it does on line 7.

S1

Speaker 1

14:12:33

Let me go about actually fixing this now. So how do I go about fixing this? Well, let's practice what we preached in our focus on unit tests, having a function like meow not have side effects, like printing itself, but let's have it return the actual string. And I can actually do this kind of cleanly.

S1

Speaker 1

14:12:48

Let me clear my error message in my terminal window here. Let me get rid of the loop here. Let me say this time that, OK, fine, meow is going to return a value, an actual str, or string. So I've changed none to str.

S1

Speaker 1

14:13:02

And now I can implement this in any number of ways, maybe even using a loop. But recall that we have this syntax in Python, which will, I think, solve this problem for us. If I want to return a string of n meows, What I can actually do, recall, is this. Return quote unquote meow backslash n times that number n.

S1

Speaker 1

14:13:23

So it's kind of a clever one-liner, avoids the need for a for loop or something more involved than that to just say, multiply meow backslash n against itself 3 times, or n times, in this case, in general, so that I get back a big string of 0 meows, 1, 2, 3, or many more meows instead. I think now my code on line 6 is actually Correct. Now I've changed meow to behave the way I was pretending to assume it always worked. So I'm storing in meows, plural, a variable that's of type str, because now meow does have a return value of type str itself per this type hint as well.

S1

Speaker 1

14:14:04

All right, let me go ahead now and print meows. But because each of my meows comes with a trailing new line, the backslash n, I'm going to proactively fix what would be a minor aesthetic bug. And I'm just going to avoid outputting an extra new line at the end of those 3. So if I run Python of meows.py now, type in 3, there's my meow, meow, meow.

S1

Speaker 1

14:14:25

And now, no mention of none. Questions now on type hints and these annotations in MyPy and using them to defensively write code that just decreases, hopefully, the probability of your own bugs.

S4

Speaker 4

14:14:45

In the return, There is a double quotes that have meow slash n. Why the program don't take it as a string?

S5

Speaker 5

14:14:53

DAVID MALAN

S1

Speaker 1

14:14:54

Why does the program not take it as a string? So recall that Early on in the class, we looked at plus as a concatenation operator that allows you to join a string on the left and the right. Multiplication is also an overloaded operator for strings, whereby if you have a string on the left and an int on the right, it will multiply the string, so to speak, by concatenating or joining that many meows all together.

S1

Speaker 1

14:15:22

So this is a feature of object-oriented programming, an operator overloading, as we saw it in the past. Other questions on type hints or MyPy? AUDIENCE 2 Can we not typecast this data type

S5

Speaker 5

14:15:37

of this variable number? DAVID MALAN

S1

Speaker 1

14:15:38

No, you still, and let me correct the terminology, it wouldn't be called typecasting in this context because it's not like C or C++ where there's an equivalence between these types, you're technically converting on line 5 a str to an int. You do still have to do this because mypy, for instance, would yell at you if you were trying to assign a str on the right to an int on the left. You must still use the int function.

S1

Speaker 1

14:16:02

Int itself is still a function. It's not a type hint. But the word int is being used in another way now in these type hints. So this int is still a function call, as it always has been.

S1

Speaker 1

14:16:14

This syntax on the left is another use of the keyword int, but in the form of these type hints. So you still have to do the conversion yourself. All right, let me propose that we transition to another feature of Python that's worth knowing, especially since it's 1 that you'll see in the wild when you see code or libraries that other folks have written, namely something known as a doc string or document strings. It turns out in the world of Python, there is a standardized way per another PEP, Python Enhancement Proposal, this 1 257, that essentially standardizes how you should document your functions, among other aspects of your code.

S1

Speaker 1

14:16:51

And so for instance, let me go back to my meows.py file here. And let me propose that we now start documenting this code, too, so that I know what the meow function does. And in fact, the standard way of doing this using docstring notation would be as follows. To comment this function, not above it, as you might be in the habit of doing with code in general, but actually inside of it.

S1

Speaker 1

14:17:15

But instead of commenting it like this with the usual hash comment sign, like meow n times, it turns out that when you're formally documenting a function, like meow in this case, you don't use regular inline comments, so to speak. You use this syntax instead. You use triple quotation marks, either double or single. Then you write out your comment, meow and times.

S1

Speaker 1

14:17:42

And then you write the same again at the end. So either 3 double quotes at the start and the end, or 3 single quotes at the start and the end. And Python has built into it certain tools and certain assumptions that if it detects that there is a comment using this docstring format, triple quotes on the left and the right, it will assume that that's indeed the documentation for that function. And it turns out in the Python ecosystem, there's a lot of tools that you can then use to analyze your code automatically, extract all of these document strings for you, and even generate web pages or PDFs of documentation for your own function.

S1

Speaker 1

14:18:20

So there's these conventions via which, if you adhere to them, you can start documenting your code as for other people by generating automatically the documentation from your own code without writing something up from scratch manually. Now, it turns out if your function does take arguments and perhaps does a bit more, there are multiple conventions for how you can document for the human programmers that might be using your function, whether it's you or a colleague or someone else on the internet to actually use these doc strings to standardize the information they're in. So you might see this instead. Using these same triple quotes above and below now, you might see your 1 sentence explanation of the function, meow n times.

S1

Speaker 1

14:19:05

Sometimes, depending on the style and use, it might actually still be on the first line, but with a blank line below it. But I'll keep everything uniformly indented. And this is a convention used by some popular Python documentation tools as well. You would say syntax like this, param n colon, and then a description of what n is, number of times to meow.

S1

Speaker 1

14:19:26

Then colon type n colon int, which just indicates that the type of n is an integer. Then if this function could actually raise an exception, you can document that too. And actually, it's not really, well, it's arguably my mistake here. If n comes in as an argument and is not, in fact, an int, Maybe it's a float or a string or something else.

S1

Speaker 1

14:19:48

The multiplication sign here is not going to work. It's not going to multiply the string. It's going to trigger what I know from experience to be a type error. So I'm going to go ahead and proactively say in my own documentation that this function, technically, if you use it wrong, could raise a type error.

S1

Speaker 1

14:20:04

Even though I'm hinting up here with this annotation that you should pass in an int, again, Python doesn't enforce that. So if you pass in a float, this might, in fact, raise this function a type error. And so that might happen if n is not an int. And then lastly, I might say, for clarity's sake, for other programmers, this function returns a string of n meows, 1 per line.

S1

Speaker 1

14:20:28

And the return type of that value, rtype, is going to be str. Now, all of this syntax here, as I've used it, is not Python per se. This is a convention known as restructured text, which is a form of Markdown-like language that's used for documentation, for websites, for blogs, and even more. But it's 1 of the popular conventions within the world of Python to document your own functions.

S1

Speaker 1

14:20:52

So this does not have anything to do fundamentally with type hints. Type hints are a feature of Python. What I'm doing here is just adhering to a third-party convention of putting, in between a Python doc string from the start to the end, a certain standard format so that these third-party tools can analyze my code for me, top to bottom, left to right, and ideally generate documentation for me. It can generate a PDF, a web page, or something else so that I or my colleagues don't need to not just only write code, but also manually create documentation for our code.

S1

Speaker 1

14:21:29

We can keep everything together and use tools to generate the same for us. Any questions now on these doc strings, which, again, are a convention of documenting your own code, often following some standard syntax?

S6

Speaker 6

14:21:45

Yeah, so when you say you would document it and put it in a PDF, is the purpose of doing this to publish it and share your function so other users can use it?

S1

Speaker 1

14:21:56

Absolutely. In the past, when we have installed some third-party libraries, for instance, Cowsay a few weeks back, recall that I showed you what functions it had. But if you read the documentation, you might actually see that it was documented for us by the author of that program. Now, I don't believe they were using this particular syntax.

S1

Speaker 1

14:22:13

But it was definitely useful for you and me to be able to read some web page or PDF telling us how to use the library, rather than wasting time reading through someone else's code and trying to infer what functions exist and how to use them. It just tends to be much more developer friendly to have proper documentation for our own code or libraries as well. Other questions?

S3

Speaker 3

14:22:34

Yeah. When with doc strings, when it's used to generate a PDF or whatever, does it include any of the code? So if you're referencing in your comment, if you're referencing the code and the comment itself might not make sense without seeing the code. Do these include it?

S3

Speaker 3

14:22:53

DAVID MALAN

S1

Speaker 1

14:22:53

LANGSTORM Short answer, you can do that. Not in the convention I'm using here. But there's actually a clever way to write in your doc strings, sample inputs to your functions, and sample outputs for your functions.

S1

Speaker 1

14:23:07

And if you use a different tool that we've not discussed, that tool will run your code using those sample inputs. It will check that your outputs match your sample outputs. And if not, the program will yell at you, saying you've got a bug somewhere. So this is just another way where you can use doc strings to not only document but even catch errors in your code.

S1

Speaker 1

14:23:27

This has been a lot, and there's a bit more to go. Why don't we go ahead here and take a five-minute break? And when we resume, we'll take a look at yet another feature of Python, yet another library to write code faster. All right, suppose we want to modify this Meow's program to actually take its input not from the input function in the blinking prompt, but from the command line.

S1

Speaker 1

14:23:46

Recall in our discussion of libraries that you could use something like sys.argv to get at command line arguments that a human has provided when you're running your program. So why don't we whip up a version of meow that uses command line arguments instead of, again, input. So I'm going to go ahead and delete what we've done here thus far. And let me propose that we import sys, as we've done in the past.

S1

Speaker 1

14:24:05

And let's do this. How about if the user does not type any command line arguments, then my program will just meow once, just so that it does something visually interesting. Otherwise, let's also give the user an option to specify how many times I want the cat to meow. So let's start simple.

S1

Speaker 1

14:24:24

Let's first of all go ahead and do this. If the length of sys.argv equals equals 1, That is, the user only typed the name of the program and nothing else in their command. Then let's go ahead and just print out 1 meow like this. Else, for now, let's go ahead and print out something like this.

S1

Speaker 1

14:24:46

Else, go ahead and print out, let's say, usage for the program, which will be usage of meows.py, just so that the user knows that the program itself is called meows.py. All right, now let me go down to my terminal window and start to type python of meows.py. And at this point, notice that the length of sys.argv should indeed be 1. Why?

S1

Speaker 1

14:25:05

Well, Python, the name, doesn't end up in sys.argv at all, ever. But meows.py, the name of the file, does. And it's going to go in sys.argv 0. But that's only 1 element.

S1

Speaker 1

14:25:16

So the length of this thing is 1. There's nothing more to the right. So when I hit Enter now, we should see, indeed, 1 meow. If I don't cooperate, suppose I do something like meows 3, Enter, then I'm going to see a reminder that this is how you use the program.

S1

Speaker 1

14:25:30

And this is a common convention to literally print out the word usage, a colon, then the name of the program, and maybe some explanation of how to use it. So I'm keeping it very simple. But let's be a little fancier. What if I really wanted the user to type in maybe not 3, but something more sophisticated?

S1

Speaker 1

14:25:46

And in fact, when controlling programs from the command line, it's very common to provide what are often called switches or flags, whereby you pass in something like dash n, which semantically means this number of times, then often a space, and then something like the number 3. This still allows me to do other things at the command line if I want. But the fact that I've standardized on how I'm providing command line arguments to this program with dash n3 is just a more reliable way now of my program knowing what does the 3 mean. It's a little less obvious.

S1

Speaker 1

14:26:21

If I just do meows.py space 3, well, what does the 3 mean? At least with syntax like dash n 3, especially if you've read the documentation for this program, Ultimately, oh, dash n means number of times. Got it. It's a way of passing in 2 additional arguments, but that have some relationship between them.

S1

Speaker 1

14:26:37

So how do I modify my program to understand dash n 3? Well, if I'm using sys like this, I could do this. L if the length of sys.argv equals this time 3. Because notice, there's 1, 2, 3 things at my prompt.

S1

Speaker 1

14:26:57

So sys.argv 0, 1, and 2, 3 things total separated by spaces. If it equals 3, and let's be safe, and sys.argv bracket 1 equals equals dash n, then let's go ahead and do this. Let's go ahead and convert sys.argv of 2 to an integer and assign it to a variable, for instance, called n. And then let's go ahead and do this.

S1

Speaker 1

14:27:26

For underscore in the range of n, Let's go ahead and print out some of these meows. Now, there's still an opportunity maybe to consolidate my print lines with meow, but for now, I'm going to keep these ideas separate. So I'm going to handle the default case with no arguments up here as before. And now, more interestingly, I'm going to do this, to be clear.

S1

Speaker 1

14:27:45

I'm going to check if the user gave me 3 command line arguments, the name of the program, dash n, and a number. If indeed the second thing they gave me in sys.argv of 1 equals equals dash n, then I'm going to assume that the next thing, sys.argv of 2, is going to be an integer. And I'll convert it to such and store it in this variable n. And now, just using a loop, I'm going to print out meow that many times.

S1

Speaker 1

14:28:12

So it's kind of a combination of our earlier focus on loops, our earlier focus on command line arguments. Just creating a program that allow me to claim is representative of how a lot of command line programs work, even though we've typically not used many like this. But it's very common to configure a program, 1, you're about to run it in the command line, with something like these command line arguments, like dash n or dash something else. Now I'm going to go ahead and hit Enter.

S1

Speaker 1

14:28:37

And I think I should see, indeed, 3 meows. By contrast, if I do 2 at the end, I should see 2 meows. If I do 1, I should see 1 meow. And frankly, if I just omit this altogether, I should see 1 meow as well, because that was my default case earlier.

S1

Speaker 1

14:28:56

And now let me allow us to assume that this program eventually gets more complicated, right? Let's imagine a world where I don't want to support just dash n. Maybe I want to support dash a and dash b and dash c and dash d and a whole lot of others. Or heck, at that point, I should maybe give them words.

S1

Speaker 1

14:29:14

So maybe it's dash dash number. It's indeed a convention in computing, typically, to use single dashes with a single letter, like n, but use double dashes if you're actually using a whole word, like number. So the command line argument might be dash n, or maybe it's dash, dash, number. But you can imagine just how complicated the code gets.

S1

Speaker 1

14:29:34

If now you want to support dash n, dash a, dash b, dash c, and so forth, you're going to have to be checking all over the place. And what if they come in a different order? You're going to have to check, is dash n first, or is it second, or is it third, or is it fourth? I mean, this just becomes very painful very quickly just to do something relatively simple like allow the user to pass command line arguments into your program.

S1

Speaker 1

14:29:55

Well, this is why, as always, there exist libraries. And Another library that comes with Python that's probably worth knowing something about is this 1 here called argpars. In fact, with a lot of the tools I, myself, or CS50's team writes in Python, we very frequently use argpars whenever they are more complicated than a lot of our class demos and a little more similar to this 1, where we want to allow the user to pass in configuration options at the command line. And by supporting things like dash n, or dash a, or dash b, or dash c, argpars is a library that, per its documentation, just handles all of this parsing, so to speak, this analysis of command line arguments for you automatically.

S1

Speaker 1

14:30:37

So you can focus on writing the interesting parts of your program, not the command line arguments part. So how might we use this? Well, let me go back to VS code here. Let me clear my terminal window.

S1

Speaker 1

14:30:47

And let me propose that I rewrite this using not sys, but actually using arg parse. And I'm going to start a little simple and then build back up. So let me throw all of this away for now and instead import arg parse. Arg parse stands for argument parser.

S1

Speaker 1

14:31:01

To parse something means to read it, kind of pick it apart to analyze it. So this is indeed going to do just that for me. Now let me go ahead and do this. And for this library, it's helpful to know a little object-oriented programming like we all now do.

S1

Speaker 1

14:31:14

I'm going to create a variable called parser. I could call it anything I want. I'm going to set it equal to the return value of argparse.argumentparser with a capital A and a capital P, a constructor for a class called argument parser that comes with Python itself within this library here. Now I'm going to configure this argument parser to know about the specific command line arguments that I myself want to support in my program.

S1

Speaker 1

14:31:41

So I'm going to do this. Parser.add underscore argument. So that's apparently a method in the parser object, I'm going to add an argument of dash n. Easy enough.

S1

Speaker 1

14:31:52

Now I'm going to go ahead and actually parse the command line arguments. I'm going to do args, or I could call the variable anything I want, parser.parseArgs. And by default, parseArgs is going to automatically look at sys.argv for me. I don't need to import sys myself.

S1

Speaker 1

14:32:09

I can leave the argument parser its code to import sys, look at sys.argv, and figure out where dash n or anything else actually is. And what's nice now, because this line of code here results in the parser having parsed all of the command line arguments, I now have this object in this variable called args, inside of which are all of the values of those command line arguments, no matter what order they appeared in. Not such a big deal when I've only got 1, because it's only going to go in 1 place at the end. But if I've got dash n, dash a, dash b, dash c, you could imagine them being in all different orders.

S1

Speaker 1

14:32:44

They definitely don't have to be alphabetical. The user should be able to type them in any order they want. That's better for usability. Arg parser is going to figure all of that out for me.

S1

Speaker 1

14:32:53

And all I have to do now is this. If I want to iterate over that many numbers of arguments, and that many mouse, rather, I can do this, for underscore in the range of the int conversion of args.n. So dot is the syntax we kept using to access things like properties inside of an object. And that's what args is.

S1

Speaker 1

14:33:15

It's an object returned by the parseArgs function for me. I'm going to go ahead now and print out quote unquote meow this many times. So it's not super simple. Like these are 3 new lines of code I need to write and rather understand.

S1

Speaker 1

14:33:29

But it's already a little simpler and more compact than my if and my elif and my ors and my ands and all of that Boolean logic. It's handling a lot of this for me. So if I didn't make any mistakes, let me run Python now of meows.py, Enter. And I did make a mistake here.

S1

Speaker 1

14:33:45

I did make a mistake. What's wrong here now? What's wrong? Well, I definitely didn't run it the way I intend.

S1

Speaker 1

14:33:52

So dash n 3, Enter. So it does work. But if I don't cooperate, this actually seems to be a worse version. If I don't pass in dash n in a number, it just errors with a type error.

S1

Speaker 1

14:34:04

Int must be a string. None is what came back. So there's clearly an error here. But the library is more flexible.

S1

Speaker 1

14:34:11

I can actually provide some documentation on how to use this thing. So how do I know how to use this? Well, typically, it's conventional in Python and in a lot of programming environments to run a program with a special argument, dash h or dash dash help. And almost always, I will claim, you'll then see some kind of usage information.

S1

Speaker 1

14:34:31

Indeed, that's what I'm looking at now. I just ran Python of meows.py space dash h. I'll do it again. Let me clear my screen and this time do dash dash help in English, Enter.

S1

Speaker 1

14:34:41

And I see the same thing. It's not very useful at the moment. It just shows me what the usage is up here. And this is kind of interesting.

S1

Speaker 1

14:34:49

This is a standard syntax in computing. And we've kind of seen it in Python's documentation before. This just means that the program's name is, of course, meows.py. Square brackets, as almost always in documentation, means it's optional.

S1

Speaker 1

14:35:03

So I don't have to type dash h, but I can. I don't have to type dash n and another value, but I can. And then down here is some explanation of these options. And more verbosely, It's showing me that I can also do dash dash help and not just dash h.

S1

Speaker 1

14:35:18

But this is so generic. This has nothing to do with my program. This is not going to help my users when I actually release this software for the world. So let me go ahead and improve it.

S1

Speaker 1

14:35:26

Let me add a description to my argument parser that the humans will see. Meow like a cat, quote unquote, is going to be the value of this named parameter called description. And let me also add a help parameter to my dash n argument that just explains what dash n means, number of times to meow, quote unquote. I'm not going to change anything else.

S1

Speaker 1

14:35:48

But I am going to go back to my terminal window and run Python of meow. I'm going to run Python of meows.py dash h, or equivalently, dash dash help. And now notice that this is a little more user friendly. If I scroll up, we still see the same usage, but there's a quick sentence in English of explanation that this program meows like a cat.

S1

Speaker 1

14:36:08

And if I look at the options now, oh, that's what n means. It's the number of times to meow. And this capital N, a middle variable, if you will, is just indicating to me that I need to type a number by convention after the lowercase dash n. So it would be nice, though, all that said, if my program still didn't just break when I run it without any command line arguments, right?

S1

Speaker 1

14:36:32

Ideally, my program would handle this just like my manual version did when I used sys.argv myself. So we just need to add a little more functionality to this library. And if I read the documentation, I'll see that add argument takes yet another named argument, if you want. You can specify a default value for dash n, for instance, 1.

S1

Speaker 1

14:36:52

And I'll do that there. And you can further specify that it's got to be an int. And what this will additionally allow me to do is, if I tell arg parser to make sure that the value of dash n is an int, I don't need to do the conversion manually. I can just trust down on line 7 that when I access the property called n inside of my args object, it's going to be automatically an int for me.

S1

Speaker 1

14:37:16

And again, this is the value of a library. It let it do all of the work for you so you can get back to focusing on the interesting project at hand, whatever problem it is you're trying to solve. Like in this case, granted, not that interesting, but meowing like a cat. Let me go ahead now and run Python of meows.py and hit Enter this time.

S1

Speaker 1

14:37:35

No arguments, and now it meows. Why? Because I specified that if I don't, as a user, specify dash n, it's going to have a default value of 1, apparently. And I don't have to convert that value from a str to an int, because I told arg parser, please just make this an int for me.

S1

Speaker 1

14:37:53

Any questions now on arg parse, or really this principle of just outsourcing the commodity stuff, the stuff that everyone's program eventually needs to do so that you can focus on the juicy part yourself.

S2

Speaker 2

14:38:06

AUDIENCE 2 What does args.n contain? DAVID MALAN

S1

Speaker 1

14:38:09

What does args.n contain? It contains the integer that the human typed after a space after dash n. Good question.

S1

Speaker 1

14:38:20

Other questions? Yeah,

S3

Speaker 3

14:38:24

when you specify the type for the argument, what happens? Does that basically handle the exception if the user inputs a string, in this case? DAVID MALAN ANDERSON

S1

Speaker 1

14:38:34

Oh, really good question. Suppose that the human does not type a number and therefore not an int. Well, let's see what happens.

S1

Speaker 1

14:38:39

So Python of meows.py dash n dog, where dog is obviously not a number. Enter. And voila, we see an automatically generated error message. A little cryptic, admittedly, but I'm seeing a reminder of what the usage is and a minor explanation of what is invalid about this.

S1

Speaker 1

14:38:57

And again, this is what allows you, this is what allows me to focus on writing the actual code we care about and just letting the library automate some of this stuff for us. All right. Well, allow me to propose now that we take a look at 1 other feature of Python that we've seen before, but it turns out we can use it even more powerfully as our programs become more sophisticated and the problems we're trying to solve themselves become more involved. Let me go ahead and return to VS Code, closing out meows.py and creating a new file, for instance, called unpack.py.

S1

Speaker 1

14:39:28

So code of unpack.py. And let me just remind us what we mean by unpacking, because this is actually a feature of Python that we've seen before. For instance, suppose that I write a program that prompts the user for their name, like David space Malin. Wouldn't it be nice if we could sort of split the user's name into 2 separate variables?

S1

Speaker 1

14:39:46

And when we've done this in the past, we've done it in a few different ways. But 1 of them involved unpacking a single value that comes back from that, like a list or some other data structure, and putting it immediately into 2 variables. So let's do this here. Let me go ahead and call the input function, asking someone, what's your name, question mark.

S1

Speaker 1

14:40:07

Then let me go ahead and just split a little naively on a single space. So I'm assuming that the only users at the moment are people like me, David, space, Malin. No middle names, no multiple names. It's just 1 and 2, which itself could be buggy for other users.

S1

Speaker 1

14:40:21

But for now, I'm keeping it simple just to remind us that I can now unpack that return value with something like first, underscore, last equals the return value of input. And now I can go ahead and do something like this, like printing out with an f string, hello, comma, and then in curly braces, first. If I just want to greet myself or any other user as, hello, David, without the last name. And frankly, if I'm not using the last name, recall that a Python convention is just to name it underscore to make clear that you know you're not using that value.

S1

Speaker 1

14:40:50

But it does need to be there because you're unpacking 2 values at once. So if I run this, it won't be all that unfamiliar. I'm just going to run now Python of unpack.py. I'll type in David Malan, which has a single space.

S1

Speaker 1

14:41:01

And there we have it, hello, David. Well, it turns out that there's other ways to unpack values. And there's other features that Python offers, especially when it comes to defining and using functions. And this is slightly more intermediate functionality, if you will, that's useful because you can start to write even more elegant and powerful code once you get comfortable with syntax like this.

S1

Speaker 1

14:41:24

So let me go ahead and propose that we not just play with hello names anymore, but instead do something maybe involving some coinage again. So maybe not dollars and cents, but maybe again, as in the past, some galleons and sickles and knuts, among which there's a mathematical relationship as to how many of those in the wizarding world equal each other. And Let me go ahead and do this. Let me define a simple function called total that just tells me the total value of someone's vault in Gringotts, the wizarding bank, based on how many galleons, sickles, and canuts that they have, which, again, are currencies from the wizarding world as opposed to our actual human world.

S1

Speaker 1

14:42:01

So this total function might take a variable like galleons and sickles and canuts like this. And then it's going to return the formula, which I admittedly had to look up myself. And it turns out that the formula for converting galleons and sickles to canuts would be this. Galleons times 17 plus sickles, then times all of that by 29, and then add in the individual canuts.

S1

Speaker 1

14:42:25

Not sure in what detail this came up in the books or movies, but here we have it, the official formula. All right, now let's go ahead and do this. Let me go ahead and call the total function with just some sample input. Suppose that someone like Harry has 100 galleons, 50 sickles, and 25 knuts.

S1

Speaker 1

14:42:42

Let me go ahead and print that out on the screen. All right, well, if total returns an integer, which I think this arithmetic expression will do, let me go ahead and store, or rather, pass the return value of total to print. And then just for clarity, let me write knuts at the end so I know that the unit of measure here is indeed knuts in total. All right, now let me go ahead in my terminal window and run Python of unpack.py and hit Enter.

S1

Speaker 1

14:43:06

And it turns out, mathematically, that if I got my math correct, 100 galleons plus 50 sickles plus 25 canuts equals in total 50,775 canuts, just avoiding having to use our own human currency here. But I'm not doing anything along the lines of unpacking, at least just yet. Let me propose now that I do this. Just For the sake of discussion, let me propose that I leave the total function as is.

S1

Speaker 1

14:43:34

But let me go ahead and just store all of my coins in a list. So coins in order from left to right, 100, 50, 25, just because for whatever purposes in this story, I have all of my coinage in a list in this order, kind of a purse or wallet of sorts. Well, how can I pass this in? Well, I'm not going to hard code the same values twice.

S1

Speaker 1

14:43:56

Just for the sake of discussion, how could I pass in the individual elements of a list to my total function? Well, of course, I could treat this list, as I always do, using numeric indices by doing coins bracket 0, coins bracket 1, coins bracket 2. So this is old school stuff with lists. If I've got a list called coins, and there's 3 elements, The indices, or indexes of those elements, are 0, 1, and 2, respectively, from left to right.

S1

Speaker 1

14:44:22

So all I'm doing here now is passing in the first element from that list as galleons, the second element of that list as sickles, and the third element of this list as my knuts. And that lines up with, of course, the signature of this function, which, as total, expects that I've passed in those 3 things in that order left to right. All right, let me go ahead and run, just to make sure I haven't broken anything. Unpack.py and hit Enter, and the math still checks out.

S1

Speaker 1

14:44:50

But this is getting a little verbose, a little verbose. And wouldn't it be nice if I could just pass the list of coins to this total function? Wouldn't it be nice if I could just say something like this, coins. But let me pause and ask the group, why would this not actually work as is?

S1

Speaker 1

14:45:12

It technically is passing in all 3, But why would I get some kind of error when I run this? Eric?

S2

Speaker 2

14:45:19

Because you are passing a list to galleons.

S1

Speaker 1

14:45:22

Yeah, I'm passing a list to galleons and nothing for sickles and canuts. And notice, those don't have default values. There's no equal signs on that first line of code, which means Python's not going to know what value should be assumed there.

S1

Speaker 1

14:45:35

So it just seems like it's not going to work. Plus, it's the wrong type, as Eric notes. It's a list, and it's not an integer as it was before. So let's actually run this incorrect version, Python of unpack.py, Enter, type error.

S1

Speaker 1

14:45:48

And that is probably what you might expect. Like, I'm messing up with the types here. And I'm required to pass in 2 positional arguments, sickles and canuts, that were not even passed. So I've definitely erred here.

S1

Speaker 1

14:45:59

But It certainly seems unfortunate if the only solution to this is to do what I previously did, which is index into the first element, index into the second element, index into the third. Like you can imagine, with bigger, fancier functions that take even more arguments, this is going to get very verbose and honestly very vulnerable, potentially, to just mistakes, typos on my part. But here, too, is where you can do what's known, again, as unpacking a value in Python. Right now, a list is kind of packed with multiple values.

S1

Speaker 1

14:46:28

My current list has these 3 values, 100, 50, and 25, respectively. But they're all packed up in this 1 list. Wouldn't it be nice if I could unpack that list, just like I previously unpacked the return value of the str classes split function into multiple things, too? And indeed, I can do just that.

S1

Speaker 1

14:46:48

Python actually allows me to pass in not coins, but star coins. So if you use a single asterisk at the beginning of your variable, that will unpack it. And it will take 1 sequence, in this case, coins of size 3, and explode it, if you will, unpack it into 3 individual arguments. No commas are needed.

S1

Speaker 1

14:47:10

Python just handles this for you. But the effect of passing in star coins is to pass in the individual members of that list, which in this case are going to be 100, 50, and 25 respectively, which is perfect because now it's going to line up with galleons, sickles, canuts, respectively. So now when I run Python of unpack.py, we're back in business. And the math checks out, but I've kind of cleaned up my code by just introducing this new symbol, which we've used, of course, in other contexts for multiplication and the like.

S1

Speaker 1

14:47:41

But now it's also used for unpacking in this way. Questions on what we've just done? It's a single operator, but it's already quite powerful because it allows us to take a data structure and unpack it and pass it in individually.

S3

Speaker 3

14:47:58

Does that work for Tuples, sets, dictionaries as well?

S1

Speaker 1

14:48:06

Tuples, yes. Sets, I don't know. Runction, I don't know if order is preserved.

S1

Speaker 1

14:48:15

No. Oh, is that no, it does not, or no, you're checking? Order's not preserved. Order's not preserved.

S1

Speaker 1

14:48:21

So it wouldn't work with set? Yes. Does not work with set. Does not work with set.

S1

Speaker 1

14:48:27

Sorry, I'm verbally Googling here just to save us some keystrokes. So it would work for enumerations where order is indeed preserved. And we'll see another example in a moment where it actually can be used in a different way for dictionaries, which nowadays do preserve order. Other questions on unpacking in this way?

S5

Speaker 5

14:48:44

AUDIENCE 2 Yes. Hi. DAVID MALANYIKA Hello.

S1

Speaker 1

14:48:46

AUDIENCE 2

S5

Speaker 5

14:48:47

Can you use unpacking to get the value, for example, 10 plus 50 plus 25, instead of a for loop, and then result plus?

S1

Speaker 1

14:48:57

Short answer, no. If you want the individual values, you should be just indexing, in this case, into those specific locations. This is returning multiple values, the equivalent of a comma-separated list.

S1

Speaker 1

14:49:09

So you would use the earlier approach if you cared about the individual locations. How about 1 other question on unpacking?

S2

Speaker 2

14:49:16

AUDIENCE 1

S7

Speaker 7

14:49:16

What if we declare some default values, and if you use this asterisk points, will it work right, or will it skip it?

S1

Speaker 1

14:49:28

Good question. If I heard you right, What if, for instance, the list has 4 values like this here, and you're still unpacking it when it's only 3 that's expected? Well, let's try it.

S1

Speaker 1

14:49:38

Python of unpack.py, Enter. Another type error. This time, it takes 3 positional arguments, but 4 were given. So the onus is on us as the programmer not to do that in this case.

S1

Speaker 1

14:49:50

So potentially fragile, but avoidable if I'm controlling the contents of this list. In fact, let me propose now that we take a look at another variant of this whereby we use not just positional arguments, whereby we trust that the first is galleons, the second is sickles, the third is knuts. Suppose that we actually passed in the names, as we're allowed to do in Python. And then technically, we could pass them in in any order.

S1

Speaker 1

14:50:12

And Python would figure it out using named parameters instead. Well, how might I do this? Well, it's going to be a bit of a regression at first. So let me get rid of this list here.

S1

Speaker 1

14:50:21

Let me change this now to just manually pass in the values I care about. Gallions, I want to still equal 100. Sickles, I want to equal 50. And knuts, I want to equal 25.

S1

Speaker 1

14:50:33

So this is old school parameter processing. It's no longer positional. I'm explicitly specifying the names of these arguments. But that's just going to work, because that's exactly what the names of these parameters are in my total function as before.

S1

Speaker 1

14:50:47

Let's make sure I nonetheless did not break anything. Let's run Python of unpack.py, Enter. And there we have it, still 50,775 knuts. Well, once you start giving things names and values, names and values, that probably should bring to mind 1 of our most versatile data structures in Python and even other languages, that of a dictionary.

S1

Speaker 1

14:51:13

Remember that a dictionary is just a collection of key value pairs, names and their respective values. So this kind of opens up an opportunity. What if I did this? What if I actually had, for some reason in my program, a variable as before called coins.

S1

Speaker 1

14:51:28

But instead of making it a list of 3 values like before, What if it's a proper dictionary? So what if it's galleons, quote unquote, colon 100 for 100 of those, sickles, quote unquote, and 50 of those, and canuts, quote unquote, 25 of those, each of those separated by colons. And let me fix my square brackets to this time be curly braces, which recall is the symbol we use for dictionaries or dict objects in Python. So now I have a dictionary called coins, not a list.

S1

Speaker 1

14:51:59

It's a collection of keys and values, 3 keys, galleons, sickles, canuts, and 3 values, 100, 50, 25, respectively, if I were to now pass these individual values into my total function, I could do it as always with my dictionary. So I'm doing it old school now. Coins is the name of my dictionary. I index into it not with numbers, like with lists, but with words.

S1

Speaker 1

14:52:23

So galleons, strings like this. Coins, quote unquote, sickles in square brackets there. And then lastly, coins, square brackets, quote unquote, knuts. So it's verbose again.

S1

Speaker 1

14:52:35

Like this is not maybe the best road to go down, but we'll backpedal in a moment. This is just how, if you happen to have all of your coins stored in a dictionary, you could pass the galleons, sickles, and knuts into your function, respectively. Let's make sure I didn't break anything. Let's rerun Python of unpack.py, and we're still good.

S1

Speaker 1

14:52:54

Now, how could we get to a situation like this? Well, as always, imagine this program is a little longer than this 1 here. And somehow, you're using a dictionary maybe just to keep track of someone's purse or wallet, like how many coins of each type that they have. And as such, it's perfectly reasonable to use a dictionary.

S1

Speaker 1

14:53:11

But then you want to print out the total. And darn it, if that total function does not expect a dictionary, So you cannot just do something nice and simple like pass in coins. For reasons we saw earlier, that would be a type error. Total expects 3 arguments, 3 integers.

S1

Speaker 1

14:53:26

You can't just pass in a dictionary. But if that's the data structure you're using to store the person's purse or wallet, well, it's kind of unfortunate that we have this clash between these data types. Well, here's what we can do. We can't pass in coins, because watch, if I try doing that and run Python of unpack.py, we're getting another type error.

S1

Speaker 1

14:53:46

Missing 2 required positional arguments, sickles and canuts. I have to pass in 3 things. But wonderfully, Python allows you to unpack dictionaries as well. For a dictionary, you don't use a single asterisk.

S1

Speaker 1

14:54:00

You use 2. And what this syntax has the effect of doing is passing in 3 values with names. It has the effect of passing in galleons equals 100, comma, Sickles equals 50, comma, canuts equals 25. And so it has the similar effect to the list unpacking, but that just passed in the values, 100, 50, 25, separated by commas, in effect.

S1

Speaker 1

14:54:28

When unpacking a dictionary, it passes in the keys and the values separated conceptually with equal signs, just like our function expects. So if I now run Python of unpack.py again, we're still good, but we've tightened our code up again. And now I'm giving myself yet another option. I can either store a wizard's purse or wallets in a list, as we did earlier, or I can store it with even more specificity using a dictionary instead.

S1

Speaker 1

14:55:00

And so to be clear, let me rewind. Star, star, coins is the same thing, if I rewind a little bit, to our first example of named arguments is equivalent to what I've highlighted here. When you unpack a dictionary, it passes in all of the keys and all of the values, much like this syntax here. But let me tighten it up and go to where we left off.

S1

Speaker 1

14:55:23

Questions now on unpacking.

S4

Speaker 4

14:55:25

AUDIENCE 1 In this dictionary, can we have, instead of having a constant name value pair, can we have a variable number of name value pairs? DAVID MALAN HANSON

S1

Speaker 1

14:55:36

Short answer, yes. You can have more than 3 key value pairs, as I have here. But it's not going to work unpacking it if the total function is expecting only 3.

S1

Speaker 1

14:55:47

So if I were to add something here, like let me introduce pennies to the wizarding world, and suppose I have 1 penny, for instance, and now I run the same code, Python of unpack.py, we're back to a type error again, whereby I got an unexpected keyword argument, pennies, because that is not expected by the total function. We will see in just a moment, wonderfully, a solution, though, to that. But for now, it does not work. Other questions on unpacking with dictionaries or lists?

S1

Speaker 1

14:56:17

AUDIENCE

S7

Speaker 7

14:56:17

1 In list values, we gave the same number of arguments, and we declared a default value in the function. Now, if you use this asterisk, will it override that value, or will it skip that default value?

S1

Speaker 1

14:56:30

A good question. If we did have default values up here, for instance, equals 0, equals 0, equals 0, the upside of that, recall from our discussion of arguments to functions a while back, is that now you don't have to pass in all of those values. They will default to those zeros.

S1

Speaker 1

14:56:49

Therefore, you could pass in fewer than 3 values, either using a list or a dictionary that's unpacked in this scenario. I deliberately did not do that because I wanted us to encounter this specific error in this case. But you could absolutely go back and add those defaults. So it turns out that this single asterisk or this double asterisk is not only used in the context of unpacking.

S1

Speaker 1

14:57:10

That same syntax is actually used as a visual indicator in Python when a function itself might very well take a variable number of arguments. That is to say, a function can be variadic, which means that it doesn't necessarily have to take, say, 3 arguments specifically. Even if they do or don't have default values, it can take maybe 0 or 1 or 2 or 3. And it turns out the syntax for implementing the same idea is quite similar in spirit.

S1

Speaker 1

14:57:38

In fact, let me go back to VS Code here. And let me propose that we start over with this code and get rid of our notion of galleons and sickles and canuts and do something just a little more generic, just so that we've seen the syntax for this. Suppose that I define a function as follows. Define a function.

S1

Speaker 1

14:57:54

Let's call it f. And that function is not going to take a specific number of arguments, but a variable 1. And so I'm going to go ahead and use this syntax here, star args, which indicates that this function is indeed variadic. It takes some variable number of positional arguments, positional in the sense that they go typically from left to right.

S1

Speaker 1

14:58:13

But I don't know how many just yet I want to support. Suppose that I additionally want to support some number of keyword arguments, that is, named parameters that can be called optionally and individually by their own name. Well, the convention syntactically here would be to use 2 stars and then kwargs. I could call args or kwargs anything else that I want, but a convention you'll frequently see in Python's own documentation is that when you have placeholders like this for some number of arguments and some number of keyword arguments, the world tends to use args and kwargs.

S1

Speaker 1

14:58:47

Well, inside of this function, let's do something super simple just for now. Let me go ahead and print out literally, quote unquote, positional, just to indicate to myself while wrapping my mind around what's going on here what the positional arguments are. And let me quite simply print out those args. This is not something you would typically do.

S1

Speaker 1

14:59:04

You don't typically just take in these arguments and print them, no matter how many there are. I'm just doing this diagnostically for now, to show you how the syntax works. Now, let me go ahead at the bottom of my file, and I won't bother with the main function this time, so we can focus only on this function f, let me go ahead and just call f with 3 arguments. I'll use the same arguments as before, but I didn't bother giving them names just yet, like galleons and sickles and canuts and the like.

S1

Speaker 1

14:59:28

So what do I have? A program that no matter what calls this function f, but it first defines f at the top of the file, is taking some number of positional arguments, some number of named arguments. And for the moment, I'm just printing out the positional ones. Let me go ahead and in my terminal window run Python of unpack.py and hit Enter, and you'll see that the positional arguments passed in are apparently this, a sequence, 100, 50, 25.

S1

Speaker 1

14:59:56

But notice this. If I clear my terminal window there and pass in some numbers, I get this.