0% found this document useful (0 votes)
3 views96 pages

Python

This document outlines a Harvard University course on programming with Python, taught by Dr. David Malan, aimed at beginners. The course covers fundamental programming concepts such as functions, conditionals, loops, exceptions, libraries, unit tests, file I/O, regular expressions, and object-oriented programming. By the end, students will have the skills to tackle real-world programming challenges and will be equipped to continue learning independently.

Uploaded by

huawei cui
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views96 pages

Python

This document outlines a Harvard University course on programming with Python, taught by Dr. David Malan, aimed at beginners. The course covers fundamental programming concepts such as functions, conditionals, loops, exceptions, libraries, unit tests, file I/O, regular expressions, and object-oriented programming. By the end, students will have the skills to tackle real-world programming challenges and will be equipped to continue learning independently.

Uploaded by

huawei cui
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

0:00 - This course from Harvard University is an introduction to programming using the Python

programming language. You will learn how to read and write code, as well as how to test and debug it. This
course is taught by Dr. David Malan and is designed for students with or without prior programming
experience who'd like to learn Python.

0:24 - [Music]

0:36 - [Music]

0:45 - "Hello, world! My name is David Malan, and this is CS50's Introduction to Programming with Python.
Whereas CS50 itself is an introduction to the intellectual enterprises of computer science and the art of
programming, this course is specifically focused on programming in Python itself. At the beginning of the
course, we'll be focused on a topic in programming known as functions and variables, mechanisms via
which you can write code that solves smaller problems, but you can compose those smaller solutions into
solutions to larger problems."

1:02 - "We'll then transition to a look at conditionals, a way in code of expressing yourself logically to
maybe do something if some question has an answer of true or not do something if the answer is false.
We'll transition thereafter to introducing you to loops, the ability and code to do something again and
again and again some number of times."

1:26 - "We'll then transition to something a little more technical, known as exceptions. Unfortunately, a lot
can go wrong when you're writing code—some of it your fault, some of it perhaps someone else's fault—
but you can write code defensively, so to speak, and actually catch those kinds of exceptions, those errors,
and handle them properly so that the users you're writing code for don't actually see them."

1:45 - "We'll then take a look at libraries, third-party code written by other people, often or perhaps yourself
in the past, that you can use and reuse in your own project, so as to avoid reinventing the wheel again and
again."

1:57 - "We'll look thereafter at something called unit tests. It turns out you'll actually write code to test your
own code, but you won't have to write tests for your tests. Indeed, this is a best practice in industry—writing
tests for your code—so that one, you can be sure that your code today is, hopefully, if your tests are
correct, correct itself. But moreover, if you or someone else modifies your code tomorrow or down the line,
you can rerun those same tests to ensure that those new changes have not broken anything about your
own code."

2:23 - "We'll then take a look at something called file I/O, I/O for input and output—the ability to not just
store information inside of a computer's memory but rather save it persistently to disk, so to speak, to files
and folders."

1 / 96
2:40 - "We'll then take a look at another technique known as regular expressions, whereby in Python, you
can define patterns and you can validate data to make sure the human types something in as you expect.
You can use regular expressions to extract data, perhaps from some data set you're trying to analyze."

2:59 - "We'll then take a look ultimately at object-oriented programming, a paradigm, a way of writing code
whereby you can represent in code real-world entities. This is in addition to other paradigms of
programming that we'll also explore, among them procedural programming where you write lots of those
functions, procedures, really, top to bottom to solve problems step by step, and even something known as
functional programming as well."

3:23 - "And then at the very end of the course, when we equip you with all the more tools for your toolkit,
additional building blocks, additional vocabulary, via which, after this same course, you can go off on your
own and either take other courses or solve projects of your own using all of these mechanisms."

3:42 - "Now, this course itself assumes no prior programming background, so you don't have to have
written a single line of code in Python or in any language yet. But this is also a course that you can take
before, during, or even after CS50 itself, if you'd like to get all the more versed with Python."

3:54 - "Each week via the course's lectures, we'll introduce you to any number of concepts that we'll then
drill down more deeply into in the form of problem sets each week. That is programming projects that will
enable you to apply some of those lessons learned to problems of your very own. And by the end of the
course, you'll have solved so many problems that ideally are representative of problems you'll eventually
encounter in the real world, whether you aspire to solve code in the technical world or perhaps in the arts,
the humanities, the social sciences, the natural sciences, or beyond. You'll have ultimately the vocabulary
and the technical skills via which to approach the same."

4:31 - "This then is CS50, and this is CS50's Introduction to Programming with Python."

4:43 - [Music]

5:01 - "Alright, this is CS50's Introduction to Programming with Python. My name is David Malan, and this is
our week on functions and variables. But odds are, many of you, most of you, have never actually
programmed before. So let's start by doing just that."

5:12 - "Let me go ahead here and open up my computer and on it a program called Visual Studio Code, or
VS Code, which is just a very popular program nowadays for actually writing code. Now, you don't have to
write code using this particular tool. In fact, all we need, at the end of the day, is a so-called text editor, a
program for writing text. And heck, if you really want, you could even use something like Google Docs or
Microsoft Word. You'd have to save it in the right format, but really, at the end of the day, all you need is a
program for writing text because that's what code is—text."

2 / 96
6:05 - "Now, within this particular program, I'm going to have the ability to create one or more files via this
top portion of the screen. And I'm going to do so by diving right in and doing this at the bottom of my
screen. At the bottom of my screen is a so-called terminal window, and this is a command-line interface, or
CLI interface, to the underlying computer—be it your Mac or your PC or even some server in the cloud. And
what I'm going to do here is literally write code and then the name of the file that I want to code. For
instance, [Link], as we'll soon see, any program that you write in Python generally has a filename that
ends in .py to indicate to the computer that it's indeed a program written in Python."

6:24 - At the top of my screen, I have a blinking cursor on line one, which is where the very first line of my
code will go. Just below that, I see a tab that reminds me of the name of this file, [Link]. Without even
knowing much Python, I'm going to write my very first program as follows:

python
print("Hello, World!")

6:45 - When I run this program, you'll see that some of my thoughts are finished for me. I only had to type
one parenthesis, and the other one automatically appeared. This is a feature of text editors like the one I'm
using. Even if you've never programmed before, you can probably guess what this simple program is going
to do. It's only one line: print("Hello, World!"). When I run this program, it will just say "Hello, World!" on
the screen. In fact, this is a very famous, perhaps the most canonical, program you can write as your very
first program in Python or any other language.

7:30 - Normally, on my computer or phone, I run programs by double-clicking an icon or tapping on the
screen. However, in this case, I don't have such icons here because my interface is a command-line interface
(CLI), which allows me to interact with the computer using commands.

8:05 - To run this program, I need to use a command. In my terminal window, I already ran the command
code [Link] to open the file in VS Code. Now, I'm going to run the Python interpreter to execute the
code in the file [Link]. The command is python [Link]. The Python interpreter is a program that reads
and executes Python code, translating it into the zeros and ones that the computer can understand.

9:50 - Let me go back to VS Code, and now I'm going to hit Enter to run the command python [Link]. If I
didn't mess anything up, I should see my very first program's output on the screen. Voilà! "Hello, World!"

10:03 - Congratulations! If you've typed exactly the same code and executed the same command, you have
now written your very first program in Python.

11:04 - In most programming languages, you have access to functions, which are like actions or verbs that
allow you to do something in the program. Functions are predetermined actions that the computer already
knows how to do, and you, as a programmer, can use them to get the computer to perform those actions.

3 / 96
11:23 - In the program [Link], we are using one function, and that function is print(). The print() function
prints whatever you want it to print. It takes a string of text as input and displays it on the screen. In this
case, it's displaying "Hello, World!"

11:48 - The string of text we passed to the print() function is what we want the function to print. Functions
can have arguments, which are inputs that influence their behavior. The print() function is designed to take
a string of text as an argument.

12:00 - The program's action of displaying "Hello, World!" on the screen is known as a side effect. It's
something that appears visually as a result of executing the program. Functions can have side effects, like
displaying text on the screen.

12:06 - When learning to program, and even after becoming experienced, you will likely make mistakes, and
these mistakes are referred to as bugs.

12:17 - A bug is a mistake in a program, and they can take many forms. You should take comfort in
knowing that over the coming weeks, you're going to make many mistakes and encounter many bugs in
your code, just like I did and still do. Bugs are just problems for you to solve, and we'll provide you with the
tools, both mental and technical, to solve those problems. Don't get discouraged if your program doesn't
work the first time you write it; with time, practice, and experience, you'll improve.

13:07 - Now, let me deliberately make a mistake to demonstrate what happens. Suppose I forgot to include
the closing parenthesis at the end of the print statement. It's almost correct, but now that I've pointed it
out, you can see that it's missing the closing parenthesis.

13:42 - I'll run the program again after making this change by typing python [Link]. This time, I should
see an error on the screen called a syntax error. It refers to the mistake I made at the keyboard. In this case,
it says that the open parenthesis was never closed.

14:13 - Unfortunately, sometimes the error messages we'll see in the coming weeks are not going to be
nearly that user-friendly. But there too, again with experience and practice, you will get better at debugging
such programs. Let me now make sure that I indeed fixed it correctly. Let me go ahead and run [Link]
and hit enter, and voila, we're back in business. Well, let me pause here and see if we have any questions
now about Python itself, writing, or running even the simplest of these programs.

14:37 - Uh, could I write code inside a word or, for example, Microsoft Excel, and what's the barrier to doing
that? A really good question, and allow me to very explicitly say to the entire internet that you should not
write code with Microsoft Word. I mentioned that only because it's a tool via which you can write text, and
code is, at the end of the day, just text. But it's not the right tool for the job. We don't need bold facing,
underlining, paragraphs, and the like. We generally want something much simpler than Microsoft Word or
Google Docs. So, VS Code is an example of just a more general-purpose text editor. Its purpose in life is to

4 / 96
allow you, the human, to edit text. Nowadays, these text editors come with many more features. In fact,
you'll notice that even in my code here, even though it's just one line, there's a bit of color to it. The word
"print" for me is appearing in blue, the parentheses are black, and we'll see as we might write more lines of
code, more and more of the lines will come to life in various colors. Now, that's just one feature of a text
editor. We'll see, too, that it has features like this built-in terminal window. It's going to have a built-in tool
for debugging or finding problems with code. And it's just a very popular tool nowadays, but there are
many, many others out there. You're welcome to use them for this course and beyond. We just happen to
use this one in large part two because you can also use VS Code nowadays for free in the cloud.

16:01 - How about one other question here on programming with Python, or hello world, or syntax, more
generally. If it's not possible to run the computer using the terminal window, I think I heard, is it not
possible to run the program without the terminal window?

16:15 - Yes, sir. Okay, you froze for me again, but let me infer what the question is. So, in this environment
as I've configured my computer, I can only run these Python programs via the terminal window. Now, that's
good for me, the programmer or the person who's trying to learn how to program, but it's not very good if
you want to ship this software and have other people use your actual code. You can absolutely write
programs and then allow other people to use not a command-line interface but a graphical user interface
or GUI. GUI, this is just one mechanism and perhaps, I think, the best one with which to start writing code.

"16:48 - Because eventually, it's going to give us a lot more control. Allow me to forge ahead here, but
please feel free to continue asking questions along the way if only via the chat. Let's consider now how we
might go about improving this program. Let's go about improving this program to make it a little more
interactive and not just assume that everyone is going to want to be greeted more generically as 'hello
world.' Let's see if I can't get this program to say something like 'hello David' or 'hello Jeremiah' or 'hello
Horatio,' or whatever the actual user's name is.

Well, to do this, I'm going to go back up to [Link] and I'm going to add another line of code at the very
top that simply says, 'For instance, what's your name?' with an extra space at the end. So I'm printing to the
user, asking them a question for some input, but now I need another function to actually get input from the
user, and perfectly enough, Python comes with a function named 'input.' So here, I'm going to go ahead
and call the function 'input()' and that's going to prompt the user with just a blinking cursor waiting for
them to type something in.

Now, it turns out if I read the documentation for the 'input()' function, it actually takes an argument itself. I
don't need to use 'print' separately and then prompt the user for input. So I can actually simplify this code
before we even use it. I'm going to go ahead and take that same string from 'print,' put it as an argument to
the 'input()' function, and get rid of the print altogether. And in fact, that print would have added a new line
anyway, so now I've just got a prompt where the user's cursor is going to end up blinking at the end of the
line, asking them, 'What's your name?'

5 / 96
In my terminal window, I'm going to run 'python [Link]' and hit enter. Okay, we're making progress. It
seems that this new function 'input()' is indeed prompting me, the human, for input. So I'm going to type in
my name, 'David,' and hit enter. Unfortunately, it doesn't really do anything with my name; it just outputs it
immediately. Alright, well, I could fix this, right? I could go up to line two and change 'world' to 'David.' Back
in my terminal window here, I can do 'python [Link]' and hit enter. 'What's your name?' 'David.' Enter, and
there we go. Alright, now I'm up and running.

Now my program is working as intended. Of course, this isn't really working as intended. Let me go ahead
and try pretending to be my colleague, Carter, here. Well, Carter's name is this. I'm going to go ahead and
hit enter and see, of course, 'Hello, Carter.' Obviously not because I've hard-coded, so to speak, I've written
literally my name inside of the string. So we need some way now of actually getting back what the user's
input is and doing something with it ultimately. And for this, we're going to leverage another feature of
programming, specifically a feature of some functions, which is that they can have return values as well.

If you think of 'input()' as being, again, this action, this verb, you can actually personify it as maybe a person,
like a friend of yours that you've asked a question of and you've asked your friend to go get input from
someone else, go ask that person their name. And if your friend comes back knowing that person's name,
well, wouldn't it be nice if they handed that name back to you? That's kind of what we need metaphorically
the function to do: get the user's input and then hand it back to me so that I, the programmer, can do
something with it. But if it's going to be handed back to me, I kind of want to put it somewhere so that I
can then print it back on the screen. I need to do the equivalent of take out, like a piece of paper or Post-It
note, write down on this piece of paper what it is the human has said so that I can then feed it into, as
input, that 'print' function. And to do that, we're going to need one more feature of programming, namely
variables. Odds are most everyone's familiar with variables from math class way back when, X and Y and Z
and the like.

"20:28 - Well, programming has that same capability - this ability to create a variable in this case in the
computer's memory, not just on a piece of paper. And that variable can store a value - a number, some text,
even an image or video, or more. A variable is just a container for some value inside of a computer or inside
of your own program. So how do I go about expressing myself in this way? Well, I think what I'm going to
do is introduce a variable that's a little more interestingly named than X or Y. I could just say, 'x = input,' but
I'm going to use a better name than a typical mathematical variable here, and I'm going to literally call my
variable 'name.' Why? Well, in programming, because I have a whole keyboard in front of me, I can use
more descriptive terms to describe what it is I'm writing. And now, there's an opportunity to consider a
specific piece of syntax. We've seen parentheses; we've seen quotes, all of which are necessary when
passing inputs to a function. But this equal sign here that's in between 'input' on the right and 'name' on
the left is actually important, and it's technically not an equal sign per se. It doesn't mean equality as much
as it means assignment.

6 / 96
20:34 - So in Python, in many programming languages, a single equal sign is the assignment operator. And
what that means specifically is that you want to assign from right to left whatever the user's input is. So the
equal sign copies from the right to the left whatever the return value of the function on the right is. So
again, the 'input()' function clearly gets input from the user; that's why I was able to type my name or
Carter's. But it also, sort of behind the scenes, hands that value, that return value, back to me, the
programmer. And if I use an equal sign and a variable, no matter what I call it, I can store that input in that
variable so as to reuse it later. So now, sitting in the computer's memory somewhere is a container
containing 'David,' 'Carter,' or whatever the human has typed in.

20:47 - But here, it's easy to make a mistake. Suppose I decide to try to print that name, and so I, kind of on
a hunch, type in this 'hello, name' just kind of plugging in the name of the variable. Well, let me go ahead
here and run 'python [Link]' and hit enter. That's going to prompt me for my name, and let me type in my
name, 'David,' but I haven't hit enter yet. And perhaps via the chat, what's going to happen here when I now
hit enter? I'm hoping it says 'hello, David.' I'd be okay if it says 'hello, world,' but I don't want it to say what
it's actually going to say. And yep, what we're seeing in the chat is, well, it's probably going to say literally
'hello, name.' So that's not quite right. So we need another way of printing out the value inside of that
variable, rather than just this word 'name.'

21:05 - Well, let me try this in a couple of different ways. Let me go ahead and maybe undo this because
I've gotten pretty good already at saying hello. Let's draw that line in the sand to just say, 'Alright, let's get
at least get hello, comma, out the door.' Let's now print 'name,' and just on a hunch, I'm going to try this.
I'm going to use 'print' again because you can use these functions as many times as you need, and I'm
going to pass the name to the 'print' function - the variable called 'name.' But notice, I'm being a little
clever now. I'm not putting it in double quotes because we've seen already that double quotes mean
literally print out 'n-a-m-e.' I'm getting rid of the quotes this time in hopes that now, by passing the variable
called 'name' to the function called 'print,' it will, in fact, go about printing the contents of that variable -
that is, its so-called value.

22:00 - Alright, let's go ahead and do this here. 'python [Link]' enter. What's your name? David. And now,
crossing my fingers still, I see 'hello, David.'

"24:15 - Alright, so it's not the best program. I'm kind of cutting some corners here, so to speak. I'm saying
'hello, David' on two separate lines, so it's not as elegant, it's not as pretty, it's not as grammatically
appropriate in English as just saying it all in one breath on one line. But at least I've solved the problem, just
not very well yet.

24:22 - But let me take a step back now and perhaps introduce a couple of other concepts with which we
should be familiar, which is as our programs get longer and they're no longer just one line or two or even

7 / 96
three, eventually our programs are going to become dozens of lines, maybe even hundreds of lines long.
Let's set the stage for success moving forward.

It turns out that Python and a lot of programming languages also support something called comments.
Comments are notes to yourself in your code, and you include comments by way of a special symbol. In
Python, it's going to be the hash symbol typically, and that allows you to write the equivalent of a note to
yourself, but in a way that's not going to break your code. The computer actually ignores your comments;
it's just there for you, it's just there for your teacher, it's just there for your colleague with whom you're
sharing, ultimately, that code. So if I go back to VS Code here and I just want to add some comments to this
program to explain to my teacher, to myself, to my colleagues what this program is doing, well, let's go
ahead and do that.

25:04 - I'm going to go at the very top of my program, and on line one, now I'm going to move that original
line of code down a bit. I'm going to add a hash, and I'm going to say something like this: 'Ask user for their
name.' Now, I don't have to use that language; I don't have to use that text. I could use any human
language whatsoever; it doesn't have to be English. But I'm going to now below that just say something like
this: 'Say hello to user.' And you'll notice that VS Code, by default, is kind of graying out my comments.
They're no longer blue; there's no red; there's no color in them, and that's just because they're notes to
myself, and the computer ultimately is going to ignore them. But what we have now is two comments: 'Ask
user for their name' and then a second comment: 'Say hello to user.' And I've just kind of commented each
chunk of code, like each line or lines (plural) of code that are doing something noteworthy.

25:54 - Why? Well, tomorrow morning, when I wake up, having, you know, uh, slept for quite some time,
forgotten what it is I did the previous day, it's convenient with comments to just see in English or your own
human language what it is this program is doing, so that you don't have to read the code itself. And better
yet, if there's maybe a mistake down the road, you can read what your intention was, and then you can look
at the code and figure out if your code's now doing what you intended.

26:17 - So this isn't really necessary for a program this small. It's pretty obvious with just one or two or three
lines what the program's doing. It's just as fast to read the code than the comments. But getting into this
habit is generally a good thing: to comment your code every one or few lines, so as to remind yourself and
others what it is your intent and your code is doing.

26:29 - What's nice about comments too is this: comments can also serve to be sort of a to-do list for
yourself. There's this notion in programming of pseudocode. Pseudocode isn't a formal thing; it's not one
specific language. It's just using English or your own human language to express your thoughts succinctly,
methodically, algorithmically, so to speak. But pseudocode, therefore, because it's not Python and it's not
necessarily English, it just kind of allows you to outline your program even in advance.

27:00 - So for instance, if I wasn't sure today how I wanted to go about writing this program, but I didn't
know what I wanted to do, I could have started today by just writing this in '[Link]': no code. I could have

8 / 96
written just a couple of comments to myself. Step one: ask user for their name. Step two: say hello to user.
Then, once I've outlined my program in pseudocode, then I can go in there and say, 'Alright, how do I ask
the user for their name?' Well, I can do 'input()' - 'What's your name?' - and then on the left here, I can
maybe put a variable and assign it to that.

28:03
Okay, how do I say hello to the user? Well, I know I can use print to say things on the screen. Let me say,
"Hello," comma.
28:10
And let me... Okay, let me now print the person's name. So, again, pseudocode is a nice way of structuring
your to-do list.
28:16
Especially if you have no idea how to write the code, because it breaks a bigger program down into small,
bite-sized tasks. All right, let me call us here to see if there are now any questions on comments,
pseudocode, return values, or variables. Any questions we can clear up here?
28:37
Yeah, my question is, does the function input work for any type of information or only for words?
28:42
Yeah, really good question! So according to its documentation (and we'll look more at formal
documentation soon), input is going to expect what's called a string, that is, a sequence of text, be it in
English or any other human language. But it's indeed going to be expecting text with which to prompt the
user. A good question! How about another question from the group, if we could? I wanted to ask how I
make a server line comment.
29:09
Oh, how do you do many lines of comments if I'm hearing it correctly? Sure, you would just keep doing
them like this. You just prefix each of the lines with a hash symbol like I'm doing here. There is another
technique for doing multi-line comments in Python that actually tends to have special meaning. You can
do three double quotes like this, and then anything in between here is a comment.

29:34
That's another technique, or you can use single quotes as well, but more on those, I think, another time. All
right, well, if you don't mind, let me forge ahead here and see how we might improve this program further
and also introduce a few other features that we might want to take into account over time.

29:51
So, it turns out that we can certainly improve on this program because it's a little disappointing that I'm
cutting this corner and saying, "Hello," comma, and then on a new line, printing out the name. Like, we can
do better, and most programs you use on your phone or your laptop certainly keep text together when
people want. So, how can we go about doing that? Well, there are a few different ways, and in fact, the
goal here is not so much to solve this one problem but to demonstrate and emphasize that in
9 / 96
programming, Python, and other languages, there are so many ways sometimes to solve the same
problem. Here's one way to solve this problem: let me go in here and let me go ahead now and say,
"Hello," comma.

30:25
And let me just add to the end of that the user's name, so I'm using plus in kind of an interesting way. This
is not addition per se; I'm not adding numbers, obviously, but I do kind of want to add the person's name
to the string of text. "Hello," comma. Well, let me go now down to my terminal window and run `python
[Link]` again. Enter, "What's your name?" I'm going to type in "David," enter. Okay, it's better, it's better,
but there's a minor bug, albeit aesthetic here; there's a missing space. But let's just use some intuition here.
Well, if I'm missing the space after the comma, why don't I go ahead and just add it manually here? Let me
now rerun the program: `python [Link]`, enter "David," enter. And there we go. Now we have something
that looks a little prettier in terms of English grammar: "Hello, David." ( hello comma space David )

31:20
And now if we rewind, you might have noticed before or wondered why I had this seemingly extra space
after my question mark, namely here. There's a space after the question mark before the double quote,
and that was just for aesthetics too. I wanted to move the user's cursor one space to the right so that when
I type their name or they type their name, it's not immediately next to that same question mark. There, but
there are other ways we can do this.

31:43
It turns out that some functions, print among them, actually take multiple arguments. And it turns out that
if you separate the inputs to a function, the so-called arguments to a function, with a comma, you can pass
in not just one but two, three, four, five onward.

32:02
So let me go ahead and pass in not just “hello comma space” but that followed by ‘name’. And th
10 / 96
is is a little confusing potentially at first glance because now I've got two commas, but it's importa
nt to note that the first comma is inside of my quotation marks, which is, uh simply an English gr
ammatical thing. The second comma here is outside of the quotes but between what are now two
separate arguments to print. The first argument is “hello comma space” and the second argument i
s the ‘name’ variable itself. So let's see how this looks: ‘python of [Link]’ enter. What's your name?
“David,” enter. Okay, I've kind of over corrected. Now I've got two spaces for some reason. Well, it
turns out, and this is subtle, when you pass multiple arguments to print, it automatically inserts a
space for you. This was not relevant earlier because I was passing in one big argument to print all
at once by using that plus operator. This time I'm passing in two because of the comma. So if I
don't want that extra space, I don't need to pass in one myself. I can just do this and now notice
if I run this program again: ‘[Link]’, type in my name “David”, now it looks grammatically lik
e I might want.

33:13 - Now, which of these approaches is better? This approach uses a function print with two arguments:
"hello, " and the name variable. The previous version, recall, technically used one argument, even though it
looked a little curious. It's one argument in the sense that the computer, just like mathematicians, are going
to do what's inside of parentheses first. So, if inside of parentheses, you have this string of text "hello, " and
a space (which I need to add back), then you have a plus sign, which means not addition per se, but
concatenation, to join the thing on the left and the thing on the right. This ultimately becomes the English
phrase "hello, space David." And then, what's being passed ultimately to the function is technically
something like this, but it's doing it all dynamically. It's not me typing in "David" as I discreetly did earlier.
It's figuring out dynamically what that value is after concatenating "hello" with the value of name and then
passing that ultimately to print as the sole argument. Let me pause here to see if there are any questions
on the number of arguments now to functions.

Can we use a function many times to solve a certain problem, which we can encounter many times in our
code? Yes, you can use a function many different times to solve some problem. What we'll soon see,
though, is if you find yourself as the programmer solving a problem the same way again and again and
again, it turns out you'll be able to make your own function so that you don't have to keep reusing the
basic ones that come with the language.

I was curious about the comma and the plus sign. So, after the plus sign, can we give just one variable? And
after the comma, can we give multiple variables? Like, what is the difference? A good question. So, in the
context of strings (and I keep using that term – "string" – which is a technical term in a programming
language, and again, it means a sequence of text, a character, a word, a whole paragraph, even), the plus
operator is not just used for addition of numbers in Python, like we do on paper with a pencil. It's also used
for concatenation of strings on the left and the right. If you did want to combine not just two strings, left
and right, but a third and a fourth, you can absolutely keep using plus, plus, plus, plus, and chain them

11 / 96
together just like in math. Eventually, that's going to start to look a little ugly, I dare say, especially if your
line of code gets long. So, there are better ways that we'll actually soon see. And a good question as well.

Well, let me come back to the code here in question and see if we can't show you just a couple of other
ways to solve the same problem along the way, emphasizing that what we're technically talking about here,
yes, are strings. But there's even a technical term for these strings in Python. It's just "str," so to speak, "Str"
for short for "string," as you may know if you programmed in other languages. People who invent
programming languages like to be very succinct to the point, so we tend to use fairly short phrases to
describe things, not necessarily full words. So, while you might say "string" technically in Python, what we're
really talking about, these sequences of text, are technically "strs." This is an actual type of data in a
program, but we'll soon see that there are other types of data in programs as well.

In fact, let's see if we can't improve this in one other way. I like the progress we've made by keeping
everything on the same line: "hello, David" all on the same line. But what more, though, could we do in
terms of solving this problem? Well, it turns out that we didn't have to give up entirely with using print
twice. Let me rewind a little bit and go back to that earlier version where I wasn't really sure how to solve
this problem. So, I was using print once to print out just the "hello" and the space and the comma, and
then I use print again to call to print name. That strictly speaking wasn't bad, but there was this visual side
effect that I just didn't like. It just looked ugly to have these two lines of text separate from one another. But
there's another way to fix this. Clearly, it seems to be the case that the print function is automatically
outputting a blank line. It's moving the cursor automatically for me to the next line because that's why I'm
seeing "hello" on one line and "David" on the next, and then my prompt, the dollar sign, on the line below
that. So, print seems to be presuming automatically that you want it to move the cursor to the next line
after you pass it some argument. But you can override that behavior. Again, functions take arguments which
influence their behavior. You just have to know what those arguments are. And it turns out that if we look at
the documentation for Python's print function, we can actually look it up at this URL here,
"[Link]." This is where all of Python's official documentation lies.

38:07 - And if I go a little more precisely, I can even find specific documentation for the print function itself.
And rather than pull that up in a browser, I'm going to go ahead and highlight just one line from that same
URL, which is this. And this is easily the most cryptic thing we've seen yet, but this is the official
documentation for the print function. And one of the best things you can do when learning a programming
language is honestly learn to read the documentation because truly all of the answers to your questions
will, in some way, be there, even though admittedly it's not always obvious. And I will say too, Python's
documentation isn't necessarily the easiest thing, especially for a first-timer or a novice programmer. It too
just takes practice. So try not to get overwhelmed if you're not sure what you're looking at. But let me walk
you through this example. This, again, is a line of text from Python's official documentation for the print
function. What this indicates is as follows: The name of this function is, of course, print. Then there's a
parenthesis over here and another close parenthesis way over there. Everything inside of those parentheses
12 / 96
are the arguments, the potential arguments to the function. However, when we're looking at these
arguments in the documentation like this, there's technically a different term that we would use. These are
technically the parameters to the function. So when you're talking about what you can pass to a function
and what those inputs are called, those are parameters. When you actually use the function and pass in
values inside of those parentheses, those inputs, those values are arguments. So, we're talking about the
exact same thing. Parameters and arguments are effectively the same thing, but the terms you use from
looking at the problem from different directions. When we're looking at what the function can take versus
what you're actually passing into the function.

What does this imply? Well, this syntax is pretty cryptic, but at the moment, just know that an asterisk, a
star, and then the word objects means that the print function can take any number of objects. You can
pass in zero strings of text, one string like I did, two strings like I did, or technically, infinitely many if you
really want, though that code's not going to look very good after that. After that, we see a comma, then we
see another parameter here called sep, short for separator in English, and notice the equal sign and the
single quote (space) . So, quote unquote, space. I don't know what that is yet, but I think we've seen a hint
about it. Let's focus though for a moment on this: the print function takes another parameter called end,
and the default value of that parameter is apparently based on this equal sign and these quotes: \n. And
what is \n? If you'd like to chime in the chat, anyone who's programmed before has probably seen this.
Though, if you've never programmed before, this might look quite cryptic. \n means new line, and it's a way
textually of indicating if and when you want the computer effectively to move the cursor to the next line,
create a new line of text. And so technically, if we read into the documentation, we'll see more detail on this.
The fact that there's a parameter called end in the documentation for the print function just means that by
default, this print function is going to end every line with \n. You don't literally see \n; you see a new line;
you see the cursor moving to the next line. Now, by that logic, let's move backward. sep for separator. The
default value of separator is apparently a single blank space. Well, where have we seen that? Well, recall in
an earlier example when I passed in not just one but two arguments to the print function, recall that they
magically had a space between them. In fact, they had that space plus my own space, and that's why I
deleted my space because at that point, it was extra. So, this just means that when you pass multiple
arguments to print, by default, they're going to be separated by a single space. By default, when you pass
arguments to print, the whole thing is going to be ended with a new line. Now, just by knowing this, and
let me literally wave my hand at the rest of the documentation for another day. There's more things that
print can do, but we're going to focus just on sep and on end. Let's see if we can't leverage this now to
solve that original problem.

42:08 - The original problem was this: I don't like how "hello, David" is on two different lines. Well, that's
happening again because print is automatically printing out a new line. So let's tell it not to do that. Let's
tell it by passing a second argument to the first use of print to say end='', not \n, which is the default
automatically. Let's make it empty, literally nothing else. Let's override the default value so there is no new
line, there's literally nothing there, and let's see what happens. Let me now go down to my terminal window

13 / 96
and clear it, and I'm going to run python [Link]. Enter. I'm going to type in my name, David, and I think
now everything's going to stay on the same line because... and it did. This line here 5 is going to print out
"hello, " but then nothing at the end of it because I changed it to be empty. The second line is going to
print the name "David" or whatever the human's name is, and it will move the cursor to the next line
because I didn't override the value of end there. Just to see this more explicitly, if you do something cryptic
like, "Well, I have no idea what's going on, let me just put in temporarily three question marks here," we'll
see the results of this too. Let me go back down to my terminal window, run python [Link], "What's your
name?" David. And now you see literally really ugly output, but it demonstrates just how much control we
have here too. And let me rewind further. Recall that in our other version of this, when I passed in "hello, "
and the name, they were separated by a single space. So, python [Link], "D-A-V-I-D," enter. That just
worked. Well, what if we override the value of sep for separator? Instead of being one space, we could say
something like "???," just to wrap our minds around what's going on there. Let me now do python
[Link], "David," enter, and you see these two inputs, "hello, " and the name, are now separated in an ugly
way by three question marks because I've overridden the default behavior of sep. Even though the
documentation uses single quotes, I've been in the habit of using double quotes in Python. You can use
either; strictly speaking, it doesn't matter, but you should be consistent, and I generally always use double
quotes. Python's documentation, though, always uses single quotes. Questions now on these types of
parameters, and allow me to propose that we give these an official name. Up until now, when we've been
passing values to print, those are called positional parameters - positional in the sense that the first thing
you pass to print gets printed first, the second thing you pass to print after a comma gets printed second,
and so forth. But there's also these things we've now seen called named parameters - named sep,
separator, or end. end for the line ending. Those are named parameters because one, they're optional, and
you can pass them in at the end of your print statement, but you can also use them by name.

43:47 - This may be a weird question, but I was wondering, what if someone wants to like add, actually,
quote quotation marks within the quotation marks?

44:00 - Yeah, I like how you think. This is what we would call a corner case, right? Just when we've made...
right, this is all sounding great, at least as programming goes, but wait a minute, what if you want to print a
quote? That's a really good question. Well, let's see if we can't figure this out. Suppose that I want to print
out not just the user's name. Let me simplify this further. Let me go ahead and get rid of all of this, and let
me just say something like, "Hello, friend," you know, in that kind of tone. Well, this is not gonna work,
actually, because you are trying to use quotes to be like "friend" and finger quotes, but you're also trying to
end the sentence, and if I try running this, let's do this: python [Link], you'll see that this is just invalid
syntax. Perhaps you forgot a comma, and this is actually a bit annoying. Sometimes the error messages you
see are misleading. Like, the computer, the language, doesn't really know what's going on, so it gives its
best guess, but it's not necessarily correct. But I can solve this problem in a couple of ways.

14 / 96
46:41 - I can do this. I can change my outermost quotes to single quotes because, recall a moment ago, I
said you could use double quotes or single quotes so long as you're consistent. So that's fine if you use
single quotes on the outside, you can then use double quotes on the inside, and you'll see them literally. So,
for instance, if I run python [Link], there we go, "Hello, friend." But there's another way. If you insist on
using double quotes as you might want to just because consistent, you can also use that backslash
character again. We saw the backslash n a moment ago, and that meant we don't want a literal n to be in
the output, we wanted a new line. So, the backslash actually represents what's called an escape character,
an escape character is one that you can't just type necessarily once on your keyboard, you need to express
it with multiple characters. So, I can actually put backslashes in front of these inner double quotes so that
the computer realizes, "Oh, wait a minute, those aren't literal, those aren't quotes that finish or start the
thought, they're literal quotes." So now, let me go back to my terminal window, run python [Link], enter,
David, enter. Okay, obviously not what I want, but I need to tell Python that this is a special string. This is
what we're going to call a format string or an F-string, a relatively new feature of Python in the past few
years that tells Python to actually format stuff in the string in a special way. The symbol via which you do
this is a little weird, but this is what the world shows. If you put an f at the beginning of the string, right
before the first quote mark, that's a clue to Python that, "Oh, this is a special string, let me format this in a
special way for you." So, let me now rerun the program, python [Link], enter, David, enter. And now we
see the goal this whole time, "Hello, David." We don't start with this way because I think if we did this the
first way, you'd be like, "Why are we doing this? What are all these magical symbols?" But this is just yet
another way to solve the same problem.

49:38 - If I may, let me rewind now on these examples and go back to where we left off with my code. I'm
just undoing all of that because I want to get back to the point ultimately of specifying now a final way of
solving this problem. Well, it turns out that we have yet another way we can solve this problem, which is
perhaps the most frequently done now or at least the most elegant when it comes to setting us up for
longer and longer uses of strings. You can use a relatively new feature of Python that allows you to do this.
You can literally put not the name of the variable like that in your string because we already saw this is
wrong, right? If you do this, you will literally see "hello, name." But what if I do this? What if I put curly
braces or curly brackets around the variable's name? Notice VS Code is actually very subtly changing the
color of it, so VS Code knows something interesting is going on here. Let me run this program, but I'm not
done yet, python [Link], enter, DAVID, enter. Okay, obviously not what I want, but I need to tell Python
that this is a special string. This is what we're going to call a format string or an F-string, a relatively new
feature of Python in the past few years that tells Python to actually format stuff in the string in a special
way. And the symbol via which you do this is a little weird, but this is what the world shows. If you put an f
at the beginning of the string, right before the first quote mark, that's a clue to Python that, "Oh, this is a
special string, let me format this in a special way for you." So, let me now rerun the program, python
[Link], enter, David, enter. And now we see the goal this whole time, "hello, David." We don't start with
this way because I think if we did this the first way, you'd be like, "Why are we doing this? What are all these
magical symbols?" But this is just yet another way to solve the same problem.

15 / 96
51:08 - And if I may, let me demonstrate what might happen if a user doesn't cooperate. If I go ahead here
and run python [Link], enter, let me just sloppily hit the space bar a few too many times. I just wasn't
paying attention, and I'm going to type in my name, David, and I don't know, I hit the space bar a couple
more times like it's kind of a mess. It's all lowercase. That's not going to necessarily look grammatically
right. It's got spaces here and here. The program is going to print exactly that, and that looks really bad, at
least if we're prioritizing aesthetics and grammar. Like, why are there so many spaces after the comma? This
is not a very nice way to greet your users. But we can clean this up. It turns out that built into strings, which
again is this data type, so to speak, this type of data in Python, is the ability to actually do things to that
string. So, let me do this. I can actually go ahead and do something like this, name = [Link](). What
does this do? Remove whitespace from string. And what do I mean by this? Well, on the right-hand side,
notice I've written the variable name called name. I've then used a period or a DOT, and then I seem to be
doing what's a function, right? Anytime we've seen a function thus far, we see it's the function's name, print
or input, then we see a parenthesis, then another parenthesis, and that's exactly what I see here. But I'm
using this function a little differently. Technically, this function is in this context called a method.

52:37 - And what do I mean by that? Well, if name is a string (AKA str), it turns out, according to the
documentation, there are a lot of functions that come with strings in Python, and you can access that
functionality by using the name of a string, like literally name here, then a period, then the name of the
function, and then an open parenthesis and a closed parenthesis, maybe some arguments inside of those
parentheses. But in this case, it doesn't need any arguments. I just want to strip the space from the left and
the space from the right of the user's input. But that's not enough. I want to remember that I've stripped off
that whitespace on the left and the right, so I'm going to use the equal sign again here, and notice that just
as before, this doesn't mean equality, this means assignment from right to left. So when this line of code
here, [Link](), returns to me (AKA a return value), it will return the same thing that the user typed in
but with no more whitespace to the left or to the right. So then the equal sign assignment is going to copy
that value from the right to the left, thereby updating the value inside of my name variable. So, you can not
only assign values to variables, you can absolutely change the value of variables by just using the
assignment operator, the equal sign, again and again and again, and it will just keep copying from right to
left whatever the new value should be. Now, if I rerun this program, python [Link], enter, I have David,
let's do it again, space, space, space, space, DaviD, in all lowercase, space, space, enter. It's better. It hasn't
fixed my capitalization, so I'm still being a little sloppy with the first D, but it has stripped off all of that extra
space. Super minor detail, right? Like this isn't all that exciting, but it just speaks to the power of what you
can do with just a single line of code.

54:50 - Now, what else can I do here? Well, I could capitalize the user's input. Let me go ahead and try this.
It turns out that I could also do this, [Link](). Let me go ahead and capitalize user's name. And
again, I'm making comments, and there's no one right way to write the comments. I'm just using some
short English phrases here to remind myself of what I'm doing. What's now going on here? Well, let me go
ahead and run python [Link], enter, space, space, space, D-a-v-i-d, space, enter. Okay, now it's looking

16 / 96
prettier, right? No matter how the user typed in their name, even a little sloppily, I'm now fixing that. But
let's try something. I'm getting a little curious here. How about this? Space, space, space, David space Malin.
I'll use my last name now, enter. Okay, so ironically, capitalize() is not really capitalizing everything we
want. It's clearly capitalizing what just the very first letter. So, it turns out that, again, there are other
functions in Python that come with strings, and if we poke around the documentation, scrolling through a
URL like that, I bet we'll find another solution, one of which is actually this. Let's actually change this to
title(). There's yet another function that comes with strings called title() that does title-based capitalization,
just like a book or a person's name, capitalizing the first letter of each word, and this is just going to do a
little more work for us. So, let's go ahead and run this.

56:05 - And as an aside, I'm kind of tired now at this point of typing python, python, python all the time. It
turns out that when using a command-line interface like this, you can actually go back through all of your
old commands. What I just did a moment ago is I hit the up arrow. That immediately goes back through my
history of all of the commands I've ever typed. So, this is just a faster way now for me to repeat myself than
typing everything manually. Let me go ahead and hit enter, space, space, space, David Malin, space, space,
all lowercase, enter. Now it's looking better. Now I've capitalized things and cleaned things up. But what
about my code? I've got like eight lines of code now, four of which are comments, four of which are actual
code. Do I really need this much? Well, not necessarily. Watch what I can also do in Python. Let me not
bother capitalizing the user's name separately. Let me say this: [Link]().title(). I can chain these
functions together. I can add title() to the end of this, and now what's happening? Well, again, with a line
of code like this, you first focus on what's to the right of the equal sign, then we'll get to the left of the
equal sign. What's on the right of the equal sign, this line here? Well, what does this mean? Get the value of
the name variable, like David Malin, then strip off the whitespace on the left and the right. That is going to
return a value.

57:24 - It's going to return "David" space "Malan" without any whitespace to the left or right. What do you
want to do with that return value? You want Python to title case it. That is, go through every word in that
resulting string and fix the first letter of the first word, the first letter of the second word, and so forth. And
then now we can finish our thought, copy the whole thing from right to left into that same name variable.
And you know what? I can take this even one step further. Why don't we go ahead and do this? Let me get
rid of all that and let me just do strip and title all on that first line, and now we've gone from like eight lines
of code to four. It's a lot tighter, it's a lot neater, and even though reasonable people might disagree, it's
arguably better because it's just easier to read. Fewer lines of code, fewer opportunities for mistakes, it just
allows me to move on with my next problem to solve.

59:06 - All right, let me pause here and see if there are any questions on these methods. A method is a
function that's built into a type of value like these functions are or on F-strings which we saw a moment
ago.

17 / 96
1:00:22 - Yes, hi, thanks, David. So, is there a way to remove the spaces between the spaces that I might
have added?

1:00:34 - A short answer, no. If you read the documentation at that same URL earlier, you'll see that strip
removes from the left and the right, but not in between. In fact, there are two other functions that come
with strings: one's called lstrip, the other is called rstrip, that allows you to do one or the other. If we want
to start getting rid of space in the middle, we're going to have to do a different trick altogether. How many
functions can be combined like [Link]().title()? You have combined so how many we can combine?

1:01:06 - Yeah, a really good question. Technically, as many as you want, but at some point, your code is
going to start to look really, really bad, right? Because the line of code is going to get really, really long. It's
certainly fitting nicely onto the screen, so I think that's a good argument.

1:01:23 - How about a counterpoint, though? Someone who voted no, if we could call on someone who
thinks this is worse because it's not very long?

1:01:29 - Yeah, it's a very long line, so I think it's better to separate.

1:01:33 - I think that's persuasive, too. Right? It's getting a little longer, and even though my sentence here,
"What's your name?" is relatively short, you could imagine that this could get even uglier quickly if I were
asking a longer question of the user. That's going to make this line of code even longer and, therefore, less
readable. It might be less obvious to me or my colleagues that I am calling strip or that I am calling title. It
might be kind of an unexpected surprise, so I think that's reasonable, too. In short, there is no right answer
here, and, in fact, part of the process of getting better at programming is getting your own sense of style or
working for a company where they might prescribe which way is better than the other because they just
want everyone doing the same thing, even though reasonable people might disagree. Ultimately, though,
so long as you have what's a pretty good argument in favor of one way or the other, like ultimately, that's
what's important. If you're just doing things because you don't really know which one's better, that's not
great. But if, if and when you start to acquire require opinions, and if your boss, if your teacher, if your
colleague, your friend can challenge you and say, "Wait, why did you do it like this?" They might not agree
with you, but at least have an answer, and that should be sufficiently persuasive in general.

1:02:25 - Now, strings come with a whole bunch of other methods as well, among which is one called split,
which can, as the name suggests, split a string into multiple smaller substrings, so to speak. For instance, if
the human here is in the habit of typing in their first name, then a space, and then their last name, and you
want to go ahead and greet them only by first name, what we could actually leverage is that single space
between the first name and last name and split that string into two smaller substrings. How can we do this?
Well, let me go ahead and in between these lines proactively comment that we're about to split the user's
name into first name and last name. And then, let's go ahead and take that name variable, which currently
contains something like, presumably, "David Malin." And let me go ahead and call split and pass in, as the
argument to split, a single whitespace, thereby indicating that I indeed want to split on that character. Now,

18 / 96
it turns out, split is going to return a sequence of values, ideally a first name and then a last name, and we
can actually, in Python, assign both of those values from that sequence at once to some variables. For
instance, first, last = [Link](), and that's going to have the effect, from right to left, of putting the first
such value in the first variable, the second such value in the second variable. So now, on my last line of
code, I can go in and say, "Hello, not to the full name, something like David Malin, I can just say, "Hello,
first."

1:04:00 - Let's go ahead and clear my terminal window, run python [Link], and hit enter. I won't bother
with any leading whitespace this time, but let me go ahead and type in David Malin and crossing my
fingers, as usual, hello, David is what we now see.

1:04:21 - All right, so we've seen so much, so many examples thus far involving strings, but certainly,
programs and programming languages can manipulate other types of data as well. Let's go ahead and
transition them to another very common type of data in Python and programming more generally, namely
integers. Otherwise known in Python as int. So just as str is short for string, so is int in Python short for
integer. What's an integer? Well, just like in math, it's a number like negative two, negative one, zero, one,
and two onward. That's an int. Of course, in the world of mathematics, there are lots of symbols that we
use, and we've seen + before, although we used it for a different purpose, but Python supports these
symbols and more, and Python allows you to add numbers together, plus; subtract numbers, minus;
multiply numbers, asterisk; divide numbers, slash.

1:05:02 - The only one here that might look a little strange to people or unfamiliar is this percent sign, but it
doesn't mean percent in this context. If you use a single percent sign in a Python program, that's actually
the so-called modulo operator, the operator that allows you to take the remainder after dividing one
number by another. We'll see examples of that before long. But the first four of these are perhaps quite,
quite familiar. Well, it turns out that in Python, you cannot necessarily...

1:05:24 - Interactive mode. You don't necessarily have to keep writing code in a file like [Link] and then
running it in a terminal window. One of the features that many people like about Python is that it supports
this so-called interactive mode. You can start writing Python code and immediately execute each of those
lines interactively. If you don't care about saving all of your lines of code and just want to execute code and
get back some answers, you can use Python as a fancy calculator. But generally, when teaching the
language, we tend to want to do things incrementally and want you to be able to see where it is we came
from and try things again and again, especially if we make mistakes. But know that this is indeed a feature
of Python, this so-called interactive mode.

1:07:30 - Let's focus for a moment now not just on that interactivity but really on the fact that Python
apparently supports integers and mathematics and some of those basic operations, and let's see if we can't
make maybe our own little calculator. Let me go ahead and open up VS Code again and create a new file
called [Link]. So now I'm not creating any .py file; I'm just going to run python by itself at my
19 / 96
prompt, and I get three triple brackets >>>, like this. This is the interactive mode for Python. Anytime I type
a line of code in The Interpreter, it's going to execute it immediately. I don't have to keep running Python
again and again. It's as though, in the human world, if you were standing next to a human who speaks some
other language and you're just having a conversation with them back and forth, it's all happening—the
translation—immediately.

1:08:07 - Let's make a simple calculator that does some addition for me. I'm going to declare a couple of
variables, X and Y, and then I'm going to give myself a third variable, Z, which equals X + Y. And then I'm
going to print out Z. This program, admittedly, not very exciting or interesting, but we'll build on this and
see what other features exist in Python that we can leverage. Let me go ahead and first declare a couple of
variables. I'm going to do the mathematical thing of calling my first variable X, my second variable Y, and
then I'm going to give myself a third variable Z equals X + Y, and then I'm going to go ahead and print out
Z. This program, admittedly, not very exciting or interesting, but we'll build on this and see what other
features exist in Python that we can leverage.

1:09:19 - Let's at least make this program a little more interactive. We already know from previous examples
how we can get input from the user. Let's bring back that input function and do this. At the top of my code,
let's change X to not be the number one always; let's change it to be whatever the return value you is of
asking the user for X. I can use any English or human language I want here. I'm going to say, "What's X,"
just like I asked before, "What's your name?" And I'm going to do the same thing for Y. I'm going to use
input again, but this time change the question to be, "What's Y?" At this point, I think I'm going to leave
the rest of the code the same: Z = X + Y and then print Z. But what's nice now is that I think I have a nice
interactive calculator. Now, it's not going to do 1 + 2 all the time; it's going to do whatever the user types
plus whatever the user types. So let's try this. Let me go ahead and run the program.

1:09:55 - Alright, let's do it. One is going to be X, two is going to be Y, and, of course, everyone in
agreement: 1 + 2 equals 3.

1:10:09 - Huh, what's going on there? Either your math class misled you, or I have misled you. Why don't we
call on someone here to see if you can't help us reason through what the bug is? What's the mistake? Uh,
Anjali, if I'm saying it right, I think the issue is that it's concatenating strings because you use the plus
operator instead of adding perfectly. So perfect intuition! We've seen that plus is used a little differently in
the context of strings because it concatenates, that is, it joins the two strings, and that seems to indeed be
what's happening here, even though the user typed a number. But the interesting thing here is that when
you get user input because they're using a keyboard on their Mac or PC or their phone, it is always going to
be text. It might look like a number, but by default, it's coming from the keyboard as a string, that is, as text.
And so how do we go about resolving this, if ultimately we don't want to treat those inputs as strings? We
want to treat them as actual numbers. Well, we need another function, and it turns out in Python that you
can convert sometimes from one type of data to another type of data, for instance, from string to int, by
doing something like this. Let me go back into my code and let me change X before adding it to Y to be

20 / 96
whatever the int(X) is plus whatever the int(Y) is. So it turns out that "int" is not only a type of data in
Python; it's also a function, and it's a function that if you pass in an input like a string, so long as that string
looks like a number, like one or like two, it will convert it to an actual number that you can perform
mathematics on instead. So if I now go back to my terminal window and run Python, and let me show you
another trick - calculator is kind of a long word; it's a little tedious to type - notice what I can do in my
terminal window in a command-line interface in general if I start typing "C-A-L" for calculator...

1:12:15 - I can actually hit tab to finish my thought, so autocomplete is possible in a terminal window like
this. Type the first letter or a few letters and then boom, with tab, it'll finish your thought for you. Or you
can go back in your history like I did with the up and down arrows. Let me go ahead and execute this.
What's X1? What's X2? And there we go, now we have a general-purpose calculator that's going to support
not just addition of one and two, but now any two integers that the user types. And let me now improve
this - right, we've seen how we can make improvements to code, and I don't know if it's going to necessarily
be better, but let's try this: do I really need the Z variable? It's worth noting that I'm creating a variable
called "cz" and then I'm immediately using it on the next line of code. Now, that's not that compelling
because if you're creating a variable and then immediately using it but never again using it, did you really
need to take the time to introduce another symbol and another variable just to use it once and only once?
Well, maybe not. Maybe we don't really need Z in this way. Maybe I should go and do something like this:
maybe I should get rid of Z here, maybe I should change this to be "int" up here, change this to be "int" up
here. Doing something that's pretty interesting now, even though it's a bit of new syntax - notice that you
can nest functions, so to speak, you can put one function call that is the use of a function inside of the use
of another function so that the return value of the inner function becomes the argument to or the input to
the outer function. So just like in math, if you have parentheses, parentheses, parentheses,

1:13:58 - Your teacher probably taught you to focus on what's inside the innermost parentheses first and
then work your way out, same thing with programming. That's what Python's going to do; it's going to look
at what's inside of the parentheses first, it's going to get the answer, and then it's going to pass the return
value to the outermost function. So what happens on line one now is that the input function gets called
first, then the result of that, "one," becomes the input to the int function. The same on line two - the output
of "what's y" becomes the input to this int function. And now there is no Z. I could just do print X plus Y.
And because I've taken the time to convert each of those strings to an integer, I think we're okay. So let me
try this: python [Link], enter one and two, and we're still getting 3, not 12 or not twelve one two.
We're indeed getting three, and we've additionally gotten rid of the variable because we didn't necessarily
need it, it seems, especially if only using it once. Well, here too, let me put everyone's hands down for just a
moment, and let me ask as before: this version now, which uses "int" around the invocations of input and
does not use Z, is this better than the previous version? If you want to vote yes, go ahead, or if you prefer
the old way, vote no - the old way.

1:15:13 - "I'll undo all of this as we vote instead looked like this." "Alright, and let me go back to now the
newest version. Let's take a hand of the yeses, someone who thinks this latest version is better. I think this
way is better because it allows us to immediately see what the X and Y variables are with integers, and so
we know what to expect from them. Also, the print argument is more inclusive; we avoid too much clutter in
the code. The lines of code are not very long, I don't need to know what Z is because it doesn't exist, it just
says 'print X plus Y.' I like that."

1:15:53 - "But someone who prefers the older way where we did have Z and we more explicitly passed
individual variables to the 'int' function, yeah, hi. I think the earlier version is better because when, I mean if
21 / 96
a user can put something else other than 'int,' let's say, I mean, let's say they type 'one' right and 'two' like
so. It will be easier to debug this version or the old version."

1:16:28 - "Okay, that's fair. And in fact, I'm being very careful today as best I can not to mess up. I have thus
far only inputted integers when I'm expecting integers, and Rose actually pointed to something we'll come
back to in the coming weeks - how do we actually handle errors? What if the user doesn't type in the
number 'one' or the number 'two,' or a number at all? What if they type in a word like 'cat' - c-a-t? That's
not a number.

1:16:47 - "And I bet I can't convert it to an integer. But for today, I'm not going to focus on that. I'm just
going to hope that the user cooperates, but that's not going to be the case. And so perhaps one way would
set us up for more success when it comes to handling those errors. Now, for today's purposes, which is
better? I mean, I like both, and I think both of you made very valid arguments in there too, so long as you
have a justification that feels pretty reasonable. I mean, that's what ultimately matters, but acquiring again a
sense of the trade-offs here, well, is this way better? If so, why or why not? Just understanding what those
trade-offs are? But generally speaking, prioritizing readability is a very good thing - making your code
readable for someone else is a very good thing and very good for you too. So that when you wake up the
next morning, or you come back the next week, or the next year, you too can read your own code without
having to waste time trying to remember what you did. And simplicity tends to be a good thing too -
keeping your code simple so is as you get more comfortable with programming."

1:17:48 - "You might be tempted to try to combine an entire program into one long line, for instance, let
me do right just that. Technically speaking, we don't really need X in a variable, we don't really need Y in a
variable, we could also do this. I could just get rid of X and Y altogether. I could then now eliminate that and
make it just one line of code. Okay, so on some sense you might be inclined to think, wow, that's really nice,
you made it one simple line of code. I would argue this actually isn't that simple. Now I think I'm starting to
nest too many things. I have to think about print and int and input. I then have to notice that okay, I've
opened two parentheses; I've closed two of them, there's a plus - you're making me think too much. And
anytime you make me think, you're wasting time, and anytime you complicate the look of the code like this,
you're just going to increase the probability of mistakes and tactical mistakes or logical errors in your code.
So of all the things we've done, this is the only one that I would argue - yes, it's one line and it's nice and
compact, it's just not readable enough. I would shy away from doing this, especially since two of those
function calls are getting input from the user. But there too, reasonable people might disagree, but that's
the kind of visceral reaction you should have sometimes when code starts getting a little too complicated, a
little too clever perhaps for its own good." 1:19:07 - "Alright, well, it's not just integers we have access to.
Let me propose that we transition from integers to one more data type here, namely a float. So again, a
string is a sequence of text, an INT is an integer like negative one, zero, and one. A float is a number with a
decimal point - properly called a floating-point value. And you can think of the floating point as being the
decimal that might be over here or over here with some number of digits to the left or the right,
mathematically..."

1:19:32 - "And you can think of the floating point as being the decimal that might be over here or over here
with some number of digits to the left or the right - mathematically, it's a real number, a number that has a
decimal point in it. So that's a third type of data that Python supports. Right now, our calculator is
somewhat naively assuming that the user is only going to type in integers. But if I want to support floating-
point values too, I think I can just make a couple of tweaks. So I'm going to go back to VS Code here, and
instead of just converting the user's input X and Y to integers on line one and two, let's just make a simple
22 / 96
change. Let's actually convert it to a float on the first line and a float on the second line here. Now, I think if
I go down to my terminal window and run python [Link], let's type in a number like 1.2 with a
decimal point and 3.4 with the decimal point, and there we go, we have 4.6 as the final answer. That
wouldn't have worked before if I was only expecting integers from the user, but now that I'm expecting
floating-point values and accommodating it, I can actually now do floating-point arithmetic as well.

1:20:38 - "But suppose that I don't really want the final answer to be a floating-point value like 4.6. I would
be happy if we just round to the nearest integer. So, I want to support the user typing in floating-point
values with decimal points, but at the end of the day, I just want to round the result to the nearest possible
integer. For instance, well, it turns out that here too, Python comes with some functionality built in. And in
fact, if we return to this URL from earlier wherein all of the Python built-in functions are listed, there's one
called round which does exactly as we would expect. It takes as input a number and then rounds it for us -
for instance, to the nearest digit, to the nearest integer. But if we look a little closer to that documentation
as we can here, I'll provide an excerpt, this is what the function looks like in the documentation. And recall
that earlier we looked at the documentation for print, and this is similar in spirit that this shows us not just
the name of the function but its available parameters, that is, inputs that we can provide when using this
function. But this is a little cryptic too, just like print was, and it adds some syntax. So let's see, the name of
this function here is, of course, round, and its first argument is a number. Notice this time, there's no star
like there was for print. The round function takes just one number as its first argument, period, that's its
positional parameter. But notice this syntax, and this is a convention in programming or technology more
generally - generally speaking, when you see square brackets and documentation like this, this means that
you're about to see something optional.

1:23:04 - "I don't have to, and reasonable people here might disagree, but I'd like to revert to a scenario
where I'm printing Z so that I can just a little more clearly to myself, to others say 'Z equals the rounded
result of X plus Y.' It's not necessarily the better way to do it, but I'm a little more comfortable with breaking
out my thoughts one at a time, especially if I want to start commenting each of these chunks of code.
Alright, let me go down to my terminal window now and run python [Link]. What's X? Let's do 1.2
again, then let's do 3.4, and now it was previously 4.6, but now it's been rounded up to the nearest integer,
which of course is going to be 5. Alright, what if I wanted to change this a little further? What if I wanted to
support maybe really big numbers - big numbers, irrespective of rounding, let's just do something like this.
Let me go ahead and run python [Link] again, and let me just add 999 plus 1, and notice I don't
have to type decimal points even though I'm converting to float, my program will just allow me to type
decimal points, but I don't need to oblige. The answer, of course, here should be, and is, in fact, one
thousand, whether or not we round. So that's just arithmetic with integers here, but in the US, we tend to
format long numbers by putting commas after or before every triple of digits. Other countries flip it, and
they use periods and commas instead. That's a system setting you can change that on your own Mac or PC
or device for Python or any language.

1:24:37 - "But for me, I'm using the US approach here, which is periods for decimal points and commas for
separators. What if I wanted this to be outputted as 1,000, just to make it a little more clear that it's 1,000
and not something like 100? That's even more useful when it's like 1 million - 1,000,000. Wouldn't it be nice
if we could automatically output those numbers as well? Well, it turns out that we can. There is a way, using
Python, to actually specify that we want to include commas like this. And here we have an opportunity to
bring back our old friend, the F-string. First, let me do something that's not that productive. First, let me do

23 / 96
this, let me print out the value of Z. But wait a minute, I can't just say 'Z' because that's literally going to
print 'Z' on the screen. So let me wrap it with those curly braces like I did before, but that too was not
enough. I literally needed to add an 'F' at the beginning of my string to tell Python that this is an F-string, a
format string that now is going to print out not very interestingly just the value of Z itself. So that I'm going
to great lengths just to print Z when really I could have just passed Z as the sole argument, but just to
ensure that I haven't broken it, let's do this again, 999 + 1, enter. Okay, it's still a thousand, so I didn't make
anything worse.

1:25:58 - "But notice this, and this syntax is unfortunately a bit cryptic. Notice that I can actually do this. I
can put a colon after the Z, and I can put a comma thereafter. This looks very cryptic, admittedly, and even I
have to constantly look things like this up in the documentation to remember the syntax. But here, let me
run it again, python [Link] 999 1, and now notice that the number has been automatically
formatted for me. If I were in a different country or locale, I could absolutely override this to use periods
instead of commas, or vice versa. But in this case here, it's just happening for me automatically. So there
too, we see a hint of what it means to really format a string. There's even more power, more powerful
capabilities built into that. Alright, let me pause here to see if there are any questions now on floats, on
rounding, or on this use of f-strings."

1:26:48 - "Yes, so I have a question. So when using floats, is there a cap on how many decimal points it can
have?"

1:27:02 - "A really good question. So floats, yes, and this is a problem we'll revisit before long, floats cannot
represent numbers infinitely precisely. In a nutshell, because computers only have so much memory, they
only have a finite amount of memory. You and I only have a finite amount of hardware inside of the
computer, so at some point, they're going to have to round. Right now, I'm rounding automatically
effectively, computers will eventually have to do that for us, but we'll see that as a fundamental problem
before long. Allow me to turn back just for a few final examples on floats. Before we introduce a few final
examples that allow us not just to use functions but to make our own, let me propose that we also try our
hand at a bit of division. Here, let me propose that we modify this calculator now to still take a couple of
floats, but let's now just do something a little simpler than a little different from this, just doing X divided by
Y. And let me go ahead and get rid of my format string and just keep it simple for now, printing out Z
instead. And what are we going to see here?

1:27:57 - "Well, just some simple division. So python [Link], let's do something like 2 divided by 3,
and of course, I get 0.6666... And to Ethan's question a moment ago, it does seem to be finite. It's not
rounding in a weird way here, but I only seem to see so many digits. That's an inevitability of using a float in
this way. By contrast, just so you know, integers nowadays in Python can be as big as you want them to be.
Unlike other languages, there is no upper bound on how big an INT can be in Python, but there is a bound
on just how precise a floating point value can be. Alright, now that I've got some simple division working
here, let's go ahead and round this. It would be nice to round this really long number, 0.6666666 and so
forth, to maybe just two decimal places. We've seen how to do this with round, though at least in its
documentation. Let's just round this not to the nearest int by passing in just x / y, which is one argument.
Once the math is done inside of the parentheses, I don't want to pass in just one argument, I want to pass in

24 / 96
two so that I can specify 'n' digits, number of digits, which recall was the second parameter for round. Let
me go ahead and run python [Link]. I'll do the same thing, 2 and then 3.67. So here too, we see a
way of rounding now not just to the nearest integer but to the nearest number of digits. But there's another
way to do this here, and in fact, this evokes our F-string example again. Let me go ahead and change this.
Suppose that you didn't remember the round function or for some reason, you didn't want to use it. You
instead want to just use a format string. Well, let's go there. Let me do 'Z', but let me surround it with those
curly braces, let me add the F at the beginning. And again, this is not interesting yet, this is just going to
print out Z, but I'm adding a lot more complexity to turn it into an F-string. But notice, I can do something
else after my variable name, after the colon. If this were going to be a big integer, I might want to use a
comma like before to separate each triple of numbers with commas, but I don't.

1:29:55

"I'm going to use a different sequence of characters. I'm going to say 0.2 F, and this 2 is one of these very
cryptic things I have to constantly look up because I forget if I don't use it that often. So, don't be 1:30:06
intimidated if this looks especially weird, but this is according to the documentation the way you specify
using an F-string, how many digits you want to print. Let me run this version of the calculator, type in 2, and
then three, we get the exact same thing.

1:30:26

But again, this is just consistent with my claim that in programming we can so very often solve the same
problem in multiple ways. This is just now the F-string approach to that very same problem, all right? Which
one is better? It depends. In this case, they're pretty equivalent.

1:30:38

You could imagine though it being useful to use a function sometimes so that you can pass in an argument
like n digits as that second argument, or you can imagine just deciding in advance that you want point two
and then writing it like this.

1:30:50

Let's transition now from focusing on strings and on integers and on floats to focusing now on functions
themselves. We began today by focusing on how you can use functions that come with Python, but
wouldn't it be nice if you could invent your own functions, especially if to our point earlier you find yourself
solving the same kind of problem again and again? It's nice that Python comes with the print function
because it's really useful to be able to print things on the screen, but wouldn't it be nice if you could print
specific things on the screen by just calling your own function?

1:31:19

Well, let me propose that we do this. Let me go back to VS Code here, and let me propose that we go back
to [Link]. I'm going to reopen [Link] where we left it before, and I'm going to go ahead now and
propose that we consider how we can start improving this further by making our own function. I have

25 / 96
written so many programs today that just say hello, and each time I'm using print, but wouldn't it have been
nice if from the beginning of today, we could just call a function called hello that just says hello for us?

1:31:52

"Now, the authors of Python years ago didn't think that we need a special function just to say hello, but I
would like that to exist. I'm saying hello so many times; I just want to be able to call a function 'hello'. So,
I'm going to start from scratch here. I'm going to delete all of my code from earlier, and I'm going to
pretend for the moment that a function called 'hello' exists. And I'm going to do just as I did before; I'm
going to get the user's name with the input function, asking, 'What's your name?' Now, I'm going to call a
function 'hello', and then I'm going to print out the user's name.

Now, I will admit, 'hello' doesn't exist, so bad things are about to happen. But let's see what... Let me go
down to my terminal window; let me run python of [Link]. I think the first line is going to be okay because
that worked before, and indeed, it's prompting me for my name. So, let me type in 'David'. The second line
of code is apparently calling a function that looks like it's called 'hello' because why is it a function? It has a
parenthesis and a closed parenthesis immediately after it, and that's what every function we've used has
looked like. But Python's not going to recognize this one. When I hit enter, now I get a 'NameError: name
'hello' is not defined'. Did you mean help? I didn't, although it's opportune that's what I need at this point is
some help, but I am encountering this error because why? The function just doesn't exist.

So, how do I make this function exist? Well, I need to create it myself using this keyword 'def' for 'Define'.
So here too, just as 'str' is short for 'string' and 'int' is short for 'integer', 'def' is short for 'define'. If and
when you want to define, create, invent your own functions, you can do so using this keyword in Python.

So, let me go back to my code here, and let me propose that we define this, perhaps in this way. At the very
top of my file, I'm going to first take a moment to define a function called 'hello' using 'def hello():' colon.
What this means now is that Python is going to treat every line of code that I indent underneath this one as
the meaning of this new function 'hello'. So, 'def' is important, as is the space.

1:34:05

"I get to choose the name of the function, and I'm choosing to call it 'hello'. The parentheses with nothing
inside mean that this function at the moment is not going to take any inputs, no arguments. There, too, the
colon means stay tuned for some indentation. Everything that's indented beneath this line of code is going
to be part of this function. It's going to be a super short function, one line of code. It's just going to print
out 'hello'.

1:34:26

But now, on lines one and two, I have invented my own function 'hello'. Notice these dots that have now
magically appeared here. This is just a setting of my text editor, VS Code, in this case, that's just making
super explicit to me that I've hit the space bar four times or equivalently, the Tab Key once, which is

26 / 96
converted 1:34:43 automatically to four space cases. Generally speaking, I'm going to need to make sure
that all of my indented code lines up now so that Python knows that it's all part of the same thing, but it's
easy in this case because it's just a single line. But now, thanks to lines one and two, the function 'hello' will
absolutely exist when I'm ready to use it on line six.

So, let me go down to my terminal window and run 'python [Link]'. Enter. Here comes my name again,
and now when I hit enter, I now see 'hello, David'. All right, we've kind of regressed though, right? This is
not nearly as pretty as it once was.

1:35:11

I think we can probably do better than this by improving things further. Why don't we consider though how
we might say parameterize this same function? That is to say, can we customize 'hello' to maybe take the
user's name as input, so that we can say not only 'hello' but the person's name all on one line, all in one
breath? Well, I think we can do this. Let me propose that we do this as follows: let me go ahead in my code,
let me inside of these parentheses. Let me come up with my own parameter name. I have complete choice
here, and I'm going to 1:35:46 say that the name of my parameter will be the word 'to'. Why? Because I
want my function to sound like the verb it 1:36:00 represents: 'hello', but who do you want to say hello to?

1:36:06

"Well, I'm going to call my parameter for this function 'to' just because in English it kind of sounds nice to
me: 'hello to who do you want to say hello to?'. That's why I'm calling this parameter 'to' instead of
something simpler like 'X' or 'Y' or 'Z'. All right, well, what do I want to do with the word 'to'? Well, I can do
a couple of different things. We've seen so many different ways to implement 'hello'. Let me just add a
comma there for grammar's sake, and then let me put the word 'to' after that as the second argument to
the function 'hello'.

There are other ways we can do this, and we've seen so many, but this one looks a little clear to me. I'll say
what's going to happen next. Well, I don't think I need this extra print line here. I think what I'm going to do
is this: I'm going to go ahead here and print out not the person's name manually, I'm going to sense
instead say 'hello(name)'. So, what am I now doing on lines one and two? I'm defining my very own function
called 'hello', but this time, that function has been designed to take a parameter, a single parameter, as
input, and I'm using the value of that parameter, which I called 'to', to plug into print so that I see not only
'hello', but also that person's name.

What am I doing on line five? Same as always, I'm just getting the user's name. Line six, I'm not only calling
'hello', I'm passing as input the name variable as an argument so that that's what gets passed into 'hello'.
And what's happening here is essentially this: even though the variable is called 'name' here, when the
function itself is called, the computer assumes that the same value is now called 'to', so 'name' is essentially
copied to another variable called 'to', so that in the context of 'hello', I can say 'hello to' that variable
instead. And we'll see in a moment what happens if we don't keep those straight.

27 / 96
Let me go ahead and run 'python [Link]', enter. 'What's your name?' And now, I'm crossing my fingers,
enter. There we go, we're back in business. But now I have my own custom function called 'hello' that's
allowing me to say hello to a specific person. And here's where now things can get really fancy.

1:38:12

"What if you wanted your 'hello' function to say hello to someone specific, but you know what? What if you
don't know who you want to say hello to? You want to say hello to the whole world? You can give
parameters default values. We've seen that, recall that with print, there was a default value for 'sep', for the
separator, there was a default value for 'end', the line ending. We can do that too, and here's the syntax: if
you want the value of this parameter by default, if not provided by the programmer, to be equal to 'world',
you literally do that in the same line you're defining the function. And I'll admit, it's starting to look more
cryptic, but I'm 1:38:39 still just defining a function called 'hello', it takes a parameter called 'to', but I'm
assigning it with the equal sign a default value of 'world', just in case the programmer doesn't call 'hello'
with an argument. And we can see this here. Let me change my code to use 'hello' in two ways.

1:39:06

On line five, I'm going to very simply call 'hello' with no arguments. Then on line six, I'm going to get the
name. Line seven, I'm going to call 'hello' with an argument. So, you'll see 'hello' now being used in two
ways.

Let me go ahead and run 'python [Link]'. I'll type in my name. Oh, interesting, notice I already see 'hello,
world', but that's expected because line five happens before line six. But once I type my name, now the
program is going to be a little more polite and say 'hello' to me personally. So there, too, we see with
relatively simple but new syntax how you can implement functionality very similar in spirit to what the print
function gave us automatically. Now you have control over doing that yourself.

1:39:55

But let me now make this point, too: one of the whole points of defining your own functions is one, just to
avoid having to repeat yourself again and again. You don't have to actually keep reinventing the wheel and
keep using the print function again and again and again if you just want to say 'hello'. Wouldn't it be nice
now if I could kind of move this code that I 1:40:08 wrote for defining the 'hello' function and just, to be
dramatic, I'm going to hit enter a whole lot of times, 50 lines down, and put my definition of 'hello' way
further down in this file? Why?

1:40:22

"Just from the spirit of 'out of sight, out of mind,' because if I now rewind to the start of my program, now
you can sort of take for granted that 'hello' is a function 'y' because it's there on line one and it has an open
parenthesis and a closed parenthesis, which up until now has meant 'call this function.' And then on line
two, we're getting a variable from the user by typing in their name, and then we're calling 'hello,' passing in
that value.

28 / 96
1:40:44

Well, at this point, I can just take for granted that 'hello' exists, even if it's way down further in the file, or as
we'll see in future weeks, even if it's in a different file altogether.

But there's a problem here, and let me go ahead and run this version of '[Link]'. Notice that as soon as I
run the interpreter 'python [Link]', I see a 'NameError: name 'hello' is not defined', again, 'Did you mean
help?'

1:41:02

Well, again fitting, I do need some help here, but I didn't mean to call the function 'help'. The problem here,
though, is that Python is just taking me literally. I have defined my function 'hello' all the way down here,
but I'm trying to use it way up here, and that's not allowed. Python's interpreter is going to take you
literally, and if you use a function, it must already exist by the time you are calling it. So, how do I fix this?
Well, apparently, I can't do that.

1:41:25

I have to define any functions I want at the very top of my file. But that, too, could get me 1:41:31 into a bit
of trouble eventually because if I constantly have to define a function above where I want to use it, you're
kind of writing code in reverse; you're constantly writing functions up here appear, up here, as opposed to
like writing your code logically, top to bottom.

1:41:49

So, let me fix this in a more standard way, which is to do this: generally speaking, you do want to put the
main part of your code at the top of your file. And in fact, I'm going to go so far as to define my function
called 'main'. It's not a requirement, but it's indeed a convention, and this just connotes to the reader that
this is the main part of my program. I'm going to get rid of my empty 'hello' call now and only pass in one
version with 'hello(name)'. And then down here, a couple of lines further down, I'll actually define my 'hello'
function.

1:42:24

"Unfortunately, now that I've reordered the functions in this way, by putting the main part of my code at the
top and 'hello' at the bottom, so that my logic kind of flows top to bottom, if I go ahead and run 'python
[Link]', enter, nothing whatsoever happens.

1:42:39

29 / 96
If I do it again, nothing whatsoever happens. Well, why in the world is this? Well, just because I've defined a
function called 'main' and I've defined a function called 'hello', doesn't mean that I've actually called or used
either of them.

1:42:51 - Yes, I'm using 'hello' inside of 'main', but no one is telling Python to actually use or call 'main'. So,
in order to tidy this up, the last thing I need to do in this file, it seems, is actually call my 'main' function.

1:43:02

And in fact, by calling my 'main' function in this way, it gets me out of trouble because now I'm defining
'main' first, but I'm not calling 'hello' yet. I'm defining 'hello' next, but I'm not calling 'hello' next. I only, at
the very end of this file, call 'main', which has the effect of running this code up here, which has the effect of
running this code down here, and it allows me, therefore, to organize my file and order my functions in any
way I want, including 'main' at the very top and solving ultimately that problem of Python not knowing
what's going on.

1:43:44

Now, it's important to note that I defined my function 'hello' as taking an argument 'to', and then I passed
into that function the value of the variable that I wanted to say hello to, that is the variable called 'name'.

1:43:50 - Because suppose I had done something a little bit differently, suppose that I hadn't defined 'hello'
as taking an argument. So, I just remove mention of 'to' and its default value 'hello, world', and I go back up
to my 'main' function, and I just call'hello' itself without passing in any arguments.

And now, let me go ahead and make one more change, one more mistake, technically. Let me go ahead
and just try to naively print out the value of 'name' in the 'hello' function. So now, to be clear, in my 'main'
function on line two, I'm defining my variable called 'name' and assigning it the return value of the 'input'
function from the user.

1:44:28

"I'm then just calling 'hello' in my 'hello' function, which now no longer takes any arguments. I am calling
'print', passing in 'hello,' comma, and then immediately passing a name, the variable into which I got the
user's input. But the catch is that 'name' exists now only in 'main,' and so watch what happens when I try to
run this version of the program with 'python [Link]'. I hit enter, I'm prompted for my name, 'David,' enter,
and ah, a 'NameError: name 'name' is not defined.'

1:45:00

So, it turns out that this is actually an issue of what's called scope. Scope refers to a variable only existing in
the context in which you defined it. So, insofar as I define this variable 'name' in my 'main' function, I can
only use that variable in my 'main' function. I can't use it as I've tried to here in my 'hello' function; it doesn't
exist in that so-called scope. And so this is why now, if I rewind and undo all of those changes, you'll see
that I'm deliberately passing 'main' from my 'main' function into my 'hello' function.

30 / 96
1:45:26

And now, in the 'hello' function, it technically has a different name, it's called '2' in that context, but that's
fine. It's completely up to each individual function to name its own variables or name its own arguments.
But this is a way now that I'm handing to the 'hello' function the value of that variable so it can be printed
by 'hello' as well.

1:45:50

And there's one final flourish we can add here: now that we've implemented 'hello', you'll notice that 'hello'
only has a so-called side effect it only prints out something to the screen. Well, what if I also want my
function to not have a side effect per se, but actually hand me back a value?

1:46:00

Recall that the 'input' function returns a value, the string that the user typed in. Recall that the 'int' function
returns a value, the 'float' function returns a value that was passed into it. Well, you can use one final
keyword here, literally 'return,' to return a value explicitly yourself.

1:46:19 - In fact, let me go back to VS Code here, and I think we'll return our attention to '[Link]' and
see if we can't implement one other version of '[Link]' that actually has our own function that even
returns a value.

1:46:38

So, I'm going to go ahead and open up [Link], and I think this time I'm going to throw everything
away, as before, and I'm just going to start practicing what we're preaching here.

1:46:45 - Define a function called main, which is now going to be the main part of my function. Let's go
ahead and now declare a variable called X and assign it to the converted version of the user input after
asking them, "What's X?" So again, a line of code quite like we've done before.

1:47:02

And suppose now that what I want to do is square this value. I want to take the number that the user typed
in and raise it to the power of 2. So 2 squared would be 4, 3 squared would be 9, 4 squared would be 16,
and so forth. Well, how do I go about implementing a function literally called square, which actually doesn't
come with Python built-in? Well, let me assume for the moment that it does exist, and let me say something
like this:

1:47:26 - Let me go ahead and say that printing, "How about X squared is," comma, square of X. So what
have I done? I've defined a function called main, and I've implemented two lines. The first of these lines
prompts the user for a value X and converts it to an integer and stores it in a variable called X. On line
three, I then say, "X squared is," and then I pass a second argument to the print function, whatever the
return value is of a square function.

31 / 96
1:47:59

But square doesn't exist, and I'll show you this here. If I now call main at the bottom, and I run python
[Link], I'll see that X is 2, and then I see a whole bunch of errors: "NameError: name 'square' is not
defined." So this isn't a typo here; it's just the function doesn't exist. But I think I can make it exist. Here, let
me go ahead and define another function called square.

1:48:24 - This one's going to take in a number, and I'm going to call it generically n, as many programmers
would just to represent any old number. And then, what do I want to do in order to square n? Well, a
number squared is really just itself times itself. So, I'm going to do this: n * n. But it's not enough just to do
the math yourself, n * n.

1:48:48

You're going to have to return the actual value n times n, and that's our new keyword here. When I now do
this, watch what happens: python of [Link] enter X, say shall be 2. x squared is 4. Let me go ahead
now and say x is now 3. x squared is now 9. So, I've implemented my very own function that returns the
square of a value, and because I'm using the return keyword, that ensures that I can pass the return value
of this just like the return value of input or int or float to another function like print. Instead, and here too
there's going to be so many ways to solve the same problem. I can actually raise n to the power of two;
we've not seen the syntax before, but if you use two two asterisks like this two stars, that raises the thing on
the left to the power on the right. Or it turns out there is in Python a function called pow for raising
something to the power that takes two arguments, the first of which is the number, the second of which is
the exponent. So there too there's just so many ways to actually solve that same problem as well.

1:49:49

So ultimately what we have done here, we first introduced functions. These actions are verbs, many of which
come built into Python that you can just use in your own code. We then introduced variables via which you
could store those return values and then maybe do something more with it. At the end of the day too, you
now have the ability to create to invent your own functions to solve simple problems like hello or in the
weeks to come, much more sophisticated, more challenging, more fun problems as well.

1:50:40

This is CS50's Introduction to Programming with Python. My name is David Malan, and this week we focus
on conditionals. Conditionals or conditional statements in Python and in other languages are this ability to
ask questions and answer those questions in order to decide, do you want to execute this line of code or
this line of code?

1:50:53

32 / 96
Conditionals or conditional statements in Python and in other languages are this ability to ask questions
and answer those questions in order to decide, "Do you want to execute this line of code or this line of
code?"

1:50:59

Or this other line of code. Instead, they allow you to take the proverbial forks in the road within your own
code.

1:51:05

Logically, so how might we go about making some of these decisions? Well, it turns out that Python comes
with a lot of built-in syntax. For instance, here are just some of the symbols you can use in Python to ask
questions, admittedly mathematical questions, but we'll start there if only to keep the examples simply
simple early on. This first symbol, as you might know for math, represents greater than. The second symbol
might not look too familiar because we usually write it all as one thing on a piece of paper, but on a
keyboard, if you want to say greater than or equal to, you'd use this symbol instead. This, of course, means
less than. This means less than or equal to, and this one's a bit of a curiosity we've seen in our look at
functions and variables how we were able to assign values to variables using a single equal sign. But that
equal sign didn't represent equality; it represented assignment from right to left. That's great because it
solved that problem, but it kind of left us in a bit of a bind because how do we now compare two things left
and right? Well, in Python and in many languages, you actually use two equal signs. So, two equal signs
represent equality, comparing the thing on the left and the right. One equal sign, as always, represents
assignment of copying the thing from the right to the left. Lastly, this last symbol represents not equal to.
So the exclamation point or bang followed by an equal sign means not equal to some value next to it.

1:52:28

Well, to ask the questions using these symbols or any others, we're going to need another keyword in
Python, and that keyword, quite simply as in English, is "if". You can ask questions in Python code along the
line of "if the answer to this question is true, then go ahead and execute this code for me." So, let's go
ahead and write some of these examples. Here, I'm going to go over to VS Code, and let's go ahead and
create a program first called "[Link]."

1:52:54

Here, I'm going to go over to VS Code, and let's go ahead and create a program first called "[Link]."
The goal of which is simply to write code that compares values and makes decisions based on those values.
Let's go ahead and type the code of "[Link]" in order to create a brand new file called "compare" in
which we'll start to express some of this logic. All right, well, what do we want to compare? So, we'd like
those integers to come from the user so that we can make decisions based on numbers we don't know the
values of in advance. Well, let's go ahead and do this as we've done in the past. Let's declare a variable like
X, let's assign it equal to the return value of the int function and pass to the int function the return value of
the input function asking the user a question like "What's X?" As we've done in the past, let's do this one
more time with Y, asking the user for the value of Y and again converting that ultimately to an INT as well.

33 / 96
So with this amount of the story, we have two variables, X and Y, each of which has values, and ideally, we
should be able to now compare these values.

1:53:53

So, suppose I want to make a decision based on the values of these variables. I'm going to use the keyword
if, and I'm going to use some of those mathematical symbols to actually ask the question itself. So how
about this? If X is less than Y, then let's go ahead and just print as much out: "X is less than Y." So, this is not
a very interesting program yet. I'm literally just stating the obvious based on the math. But it's allowing me
to now introduce some new syntax. And exactly what is this syntax? Well, it's this, not just the keyword if,
which I've added here at the start of line four, but then I ask my question here: X less than Y. X is one
variable on the left, Y is one variable on the right, and of course, the less than sign is expressing the
mathematical question I have. What I've highlighted here is technically called a Boolean expression. A
Boolean expression, named after a mathematician named Boole, is simply a question that has a yes or no
answer or technically a true or false answer.

1:54:52

And that's nice because if there are only two possible answers, it's very easy for me and, in turn, the
computer to make a decision: do this or don't do this thing. Now notice, if you come from other languages,
you might notice that I have not typed any parentheses. They are not, in fact, necessary, at least in this case
in Python, but I have typed a colon at the end of the line. And even more importantly, at the next line, I
have begun my line with some indentation, hitting the space bar four times or just hitting tab once, which
will automatically be converted to the same. That indentation is what tells Python that line five should only
be executed if the answer to line four's question is, in fact, true. So if X is less than Y, that phrase will be
printed thereafter.

Well, let's add a few more lines of code. How about another question? If X is greater than Y, then let's go
ahead and print that "X is greater than Y." And let's do one final question: if X equals Y, then wait a minute,
what have I done wrong here, right? A good eye here. I don't want to assign Y to X. If X equals equals Y is
how I express equality. Let's go ahead and print out "X is equal to Y." So I now have three conditions, if you
will: one question asking X less than Y, one asking X greater than Y, and one X equaling Y.

Let's run the code. Well, down here in my terminal window, I'm going to run python [Link] and hit
enter. "What's X?" Let's go with one. "What's Y?" Let's go with two. This should, of course, execute that first
line of code and tell me indeed that "X is less than Y," exactly as I would expect there.

Well, what just happened though in code? Let's take a look, perhaps at this same code visually, particularly
if you're a more visual learner. This, I dare say, is what just happened. So what we're looking at here is a flow
chart. It's a diagram of this program's logic, and more technically, it shows the program's control flow, that
is, the ability of you and code to control the flow of a program generally from top to bottom. In fact, let me
go ahead and zoom in on the top of this flowchart, and you'll see an oval at the very top that says, quite
literally, "Start."

1:57:09

34 / 96
That is irrespective of what shape or layout the diagram is, is where your own thinking and logic should
start when trying to wrap your mind around this program. Notice that there's an arrow from "Start" to this
diamond shape, and inside of that diamond is a question, a Boolean expression X less than Y. And this
shape just means, based on the answer to that question, go left or go right, specifically go left if the answer
is true or go right if the answer is false.

Well, the inputs I typed were one and two, respectively, for X and Y. So, of course, 1 is less than two, so
that's why my program printed out "X is less than Y." But recall, the code then proceeded to ask two more
questions: is X greater than Y, is X equal equal to Y? Well, the flowchart depicts those questions too. Notice
that no matter whether the question had an answer of true or false, the arrows both converge back down to
this second diamond shape here. And that second diamond shape asks the second question: is X greater
than Y? That too has a true or false answer, so we go one way or the other. But if X is one and Y is two, then
no, the answer is false. One is not greater than Y, so logically in the flowchart, you follow the false arrow this
time. And notice, along that false arrow, you don't print anything this time. That's why we only saw one
printout on the screen.

Now there was still a third question, and this flowchart captures that as well. The third diamond asks: is X
equal equal to Y? Now that too has a false answer in this case because 1, of course, does not equal equal Y.
And so we again follow the third false branch here, and that leads us, of course, to "Stop," and "Stop" just
indicates that's it for the program.

I think that's correct, and that particular flowchart does happen to represent the actual code that I wrote, so
it's correct. It does what it's supposed to do. It answered the question correctly by printing on the screen "X
is less than Y." But what is perhaps poorly designed about it? Let's make this first distinction. It's not enough
necessarily for the code that you write to be correct; it's got to be clear as well. In fact, that's really the first
thing to focus on when you start writing programs, especially programs that solve problems of any
reasonable size or complexity.

1:59:12

It's not enough necessarily for the code that you write to be correct and do what you intend longer term,
especially as our programs get longer and more sophisticated, more complicated. We're going to want
them to be well-designed too. Thoughts on in what way this program is arguably not well-designed, even
though it's correct?

Let's see here, Khalid (if I'm saying that right), your thoughts too many "ifs," I think, is getting repetitive. We
can make our code more concise, maybe. Yeah, it seems a little repetitive. I'm asking if this, if this, if this,
and yet logically, I should know the answer to some of those later questions once I figure one out. And in
short, if you look at this diagram here, notice that no matter whether I go left or I go right, I'm always
asking three questions no matter what. All of those arrows lead to the first, the second, and the third
diamond. So, I'm asking three questions no matter whether any of those answers are true or false.

Well, how might I go about improving this? Well, let me propose that we introduce another keyword to our
Python vocabulary, namely elif. And this too is kind of a succinct one. It's a conjunction of "else" and "if" in
English, which allows us to ask a question that takes into account whether or not a previous question had a

35 / 96
true or false answer. What do I mean by that? Let me go back to my code here, and let me propose that we
now improve upon this by asking ourselves ultimately, "How can we ask fewer questions?"

Let me go ahead here and propose that instead of asking if, if, if, let's make these conditions potentially
mutually exclusive. That is to say, don't keep answering questions once we get back a true answer. So, I'm
going to change my code up here as follows. Instead of asking if, if, I'm going to say if x less than y, elif x
greater than y, elif x equals equals y. So, I'm going to implicitly, just like in English, take into account that
I'm only going to keep asking myself these questions if I haven't yet gotten a true response.

2:01:16

Think about the logic here. The English: "If x is less than y, on line four print out 'X is less than y'." Well, if
that's the case, you're done logically. Because if the English is saying, "if x less than y," else if x greater than
y, those are going to be mutually exclusive. If the answer to the first question is true, you don't have to keep
asking questions to which you already logically know the answer.

So let me go ahead now and run this program. I think the behavior is going to be the same. Python, open
"[Link]". What's X? Let's do one. What's y? Let's do two. X is less than y.

Now, honestly, I didn't really notice a difference when I ran the program, and honestly, my Mac, my PC, my
phone nowadays are so darn fast, these kinds of improvements aren't going to necessarily feel any faster
until we're writing bigger, faster programs. But it's laying the foundation for writing better code longer-
term.

Now, what is the improvement I've just made? Well, if previously my diagram looked like this, which was
problematic insofar as I was asking three questions no matter what, even if I already figured out what I want
to print on the screen, this new version of the program that says "if L, if L, if" might look a little something
like this instead. Now, it got a little wider, that's just because we drew the arrow rows to be a bit wider here,
but let's focus on just how many questions are getting asked. Let me zoom in at the top.

As before, and let me propose that we note that the start oval is at the very top, and it's asking us to ask
one question first: "X less than y?" Is one less than two. But notice here, let me zoom out, if one is indeed
less than two, we follow this longer arrow down, marked true, we print out "X is less than y", but then we
immediately follow this next arrow down to the icon that says "stop." So that's what's implied by doing "if L,
if L, if." If we get back a true answer right away to that first if, we're going to print out "X is less than y" and
then stop. We're logically at the end of the program.

2:03:22

So this picture is just representing graphically what the code is actually doing. But suppose I typed in
something else. Suppose that my code actually ran, and I typed in 2 for x and 1 for y. That is to say, the
answer to the first question is now false, but the answer to the second question is now true because, of
course, 2 is greater than 1.

Well, let's go back to the diagram, same as before. We start at the very top where it says "start." The very
first question up here: "X less than y?" is an answer of false because no, 2 is not less than 1. So we follow

36 / 96
this arrow to the next question. This diamond is "X greater than y." Well, yes, 2 is greater than 1, so now we
follow this left arrow, which is true. We print out "X is greater than y" and then stop.

So what's the improvement? Well, in the first case, we got lucky, and we only had to ask one question, and
boom, we're done. This time we had to ask two questions, but then boom, we're done. Only if x happens to
equal y do we actually find ourselves logically getting all the way down to this final "L if" in my code and
pictorially. Only if x is equal to y, we find ourselves going all the way down to the third diamond, the third
question, asking is it equal to y or not. Now hopefully, the answer at that point is not false. We've included a
false arrow just so that the program itself is well defined, but logically, we shouldn't actually be getting
there anyway because it's got to be less than, greater than, or equal to in this case.

Well, let me pause here to see if there's any questions now, either on the code version thereof here or on
this diagramming of that very same logic. Questions here on this control flow, "Aren't we supposed to put
an 'else' at the end?" Ah, a good question, and yes, so that's going to be my third and final approach. And if
you don't mind, let's pivot there right away, identifying a third keyword that indeed exists in Python that
allows us to be even better at expressing this logic, to design this program even better, and that's going to
solve a particular problem.

2:05:32

So if I take us back to our code here, notice that what I've highlighted earlier: "elif x == y," it's not wrong to
ask that question. In fact, if you're trying to be especially thorough, it makes perfect sense to check if x is
less than y, greater than y, or equal to y. But why don't I need to ask this third and final question? We don't
need to ask if x is equal to y anymore because logically, if the two conditionals evaluate to false, there is
only one conditional that will evaluate to true, and that is "x is equal to y." Exactly! If we're all pretty
comfortable with math and comparisons here, of course, x is either going to be less than y, greater than y,
or equal to y. But once you rule out the first two scenarios logically, it's got to be the case that x must equal
y if it wasn't the case that it's less than or greater than.

So, I propose that we use this other keyword, "else." And how do we use this? Well, exactly as we might in
English. Let me go back to my code here, and instead of bothering to ask the third and final question, let's
not ask a question at all. Let's just have this catch-all, so to speak, a final line of code that says "else," just
assume that x is equal to y, therefore printing it as well.

What's the upside of that? My code is still going to work exactly the same, and again, my computer's so
darn fast, I don't even notice that it's working even faster than it was before. But we would notice these
kinds of things if we were doing a lot more work, a lot bigger programs here. But let me run "python
[Link]." Let's do, for instance, one and two. It still works for that. Let's do two and one. Still works for
that. Let's do one and one, and it indeed now works for that.

But in these cases now, let's consider the path we just went down. Previously, our diagram when we had "if
L, if L, if" in place looked a little something like this. And notice that again, we might have asked one
question or two, or worst case, three whole questions.

2:07:30

37 / 96
But we can do better than that using 'else,' as Hope proposed. We can whittle this diagram now down to
this, and even though it looks like the diagram is getting bigger, notice that it's having fewer building
blocks inside of it. There are fewer arrows and there are fewer nodes in this picture. Let's start at the top
now. 'Start' leads us to the first question still: 'Is X less than y?' If the answer is true, great, we can say as
much, 'X is less than y,' and we can stop. If it's not true, if it's false, we can ask the next question, 'Is X
greater than y?' True or false? If it is, great, we can print 'X is greater than y' and stop. 'Else,' if it's not the
case that X is greater than y, the answer is false, we can just immediately logically say X is equal to Y. We
don't have to add the third question at all. We can just immediately conclude there."

So, what's the implication here? You can see with these pictures a relative decrease in the complexity of a
program. The first one was very long and stringy with lots and lots of questions unnecessarily. Ultimately,
the next one got a little shorter, and this one's even shorter still. And again, the fewer lines of code you
have, the less likely you are, arguably, to make any mistakes. The easier it is for other people to read, and so
generally, this readability, this simplification is indeed a good thing.

Well, let's go ahead and add another piece of capability in Python, and that's this one here. Just like in
English, where you can ask this question or this other question, you can say the same thing in Python using
literally this word "or." So let me go back to my Python code here, and let's propose how we might ask a
couple of questions at once this time. Perhaps this time, considering how we might ask not whether it's
greater than or equal to, in caring about the precise answer, let's take a coarser approach here, and let's just
try to determine: Is X greater, is X equal to Y, or not?

Well, let me go ahead and delete some of this code and change the question we're asking. Let me do this:
"Well, if I care about whether it's equal or not, let's check the possible scenarios: If X is less than Y or X is
greater than Y,

2:09:36

Let's go ahead and print out "X is not equal to Y." Now why is that? No pun intended. If X is less than Y,
well, it's obviously not equal. If X is greater than Y, it's obviously not equal. So we can include "X is not equal
to Y." So if we instead want to make sure that it is equal to, we can just use Hope's "else." Using print "X is
equal to Y," and again, Y is this: if X is less than Y or X is greater than Y, they're obviously not equal.
Otherwise, logically, they must be equal. In fact, so let's run this. Let's go ahead and run "python
[Link]." What's X? 1. What's Y? 2. Okay, "X is not equal to Y." Let's do it again, but 2 for X, 1 for Y. "X is
not equal to Y." And one third time, how about X is 1 and Y is 1? "X is now equal to Y."

Now, if we want to compare that visually to... let me propose that the picture looks a little something like
this. And again, this is the exact same thing logically, but it's a pictorial representation thereof. What's the
first question? Well, if X is less than Y, then we follow the true arrow and we say "X is not equal to Y," and
then we stop. But what if X is not less than Y? What if it's greater than Y? What if it's 2 and 1 respectively?
Then the answer to "X less than Y's" first question is false, so we go here, we ask the second question
because of the "or," and that asks, "Is X greater than Y?" If so, notice this, we can kind of reuse some of the
same parts of this picture and just say "X is not equal to Y." We don't need to add arrows and add boxes
unnecessarily. We can reuse lines of code, uh, picture parts of the picture, just as we have lines of code, and
then we stop.

38 / 96
Lastly, we have the following "if": if we know that X is not less than Y, we know that X is not greater than Y,
it must be the case that X equals Y. We don't need to ask a third question, another diamond. We can just
immediately print as much and then say "stop" as well. Well, what could I do here? I bet I could improve this
code slightly, and if we really want to be nitpicky, I would argue that this is now really just a minor
refinement, but it's a good habit to get into, thinking about: Could my code be better? Could my code be
simpler? Could I improve this code further?

2:11:59

It's subtle, but could I improve the design? Could I ask fewer questions? Could I tighten it up, so to speak?
What do folks think? You can ask if X is just equal to Y. Then, if we print "X is equal to Y," else "X is not equal
to Y." Perfect! Recall one of the other symbols we saw in the available list earlier. We can check not just less
than or greater than or equal to, we can literally ask the question, "Is it not equal to Y?" Are we wasting time
asking if it's less than or if it's greater than? Well, if all you care about is, "Is it not equal?" I think we can do
exactly that. Let's just ask the one simple question we do care about.

So let me go back up here, and let me just say not both of these questions. Let's get rid of the "or," let's just
say, "If X is not equal to Y," then go ahead and print "X is not equal to Y." And that too, I think, is going to
work exactly the same. But the picture now looks a little bit different. Notice that this was our flowchart
earlier that represented that same logic, and there's a bit of complexity. You've got to go left, you've got to
go right based on the answer to these couple of questions. If we now take into account what this version of
the program looks like, it's even simpler, perhaps the simplest one we've seen yet.

When we start off the program, we ask just one and only one question: "Is X not equal to Y?" And if so, true,
we go ahead and print out "X is not equal to Y." If the answer is false, then of course, it must be equal to Y,
so we say that instead. And if we really want, we could invert this. If I go back here to my code, and if, for
whatever reason, you just prefer to think in terms of equal or not equal, as opposed to not equal or equal,
it's really up to you. We could change this to be "equals equals," but I'm going to have to change my print
statements to be in the opposite order. So now, when I execute this code, I'm asking still just one question,
so it's still just as good, just as succinct, but now the diagram, instead of looking like this, is going to change
to "not equal to equal equal,"

2:14:06

And we just need to make sure that we print out the right thing accordingly. And again, here too, just as the
code is getting a little more compact, a little more compact with fewer and fewer characters, so are these
diagrams, these flow charts capturing the relative simplification of each of those programs too. All right, let
me go ahead and pause here to see if there are any questions now on any of these versions of code.

2:14:24

Yeah, I have a couple of questions. What if indentation is not used? 2:14:37 If indentation is not used, your
program will not work. So Python is a little different from a lot of languages in that it enforces the
indentation requirement. Some of you who have been programming for years might not necessarily be in
the best habit of indenting your code properly, and one of the features, arguably, of Python is that it makes
you indent your code, or it will not just work.

39 / 96
2:14:54

Did you have one other question? 2:14:37 Yeah, is the colon necessary? 2:15:09 Yes, the colon is necessary.
So with Python, what you see is what you get here, and indeed, it needs to be indented, and the colon is
necessary. Python does not use, in the same way, by convention, as C and C++ and Java, curly braces to
connote blocks. Instead, it relies indeed on this indentation.

Well, let me propose that we introduce one other keyword here in Python to see exactly how we might
combine additional thoughts, and that's going to be literally the word "and," a conjunction of one or two or
more questions that we might want to ask at once. And let me propose here that we explore this kind of
logic by way of another program altogether in VS Code, whereby I'll go ahead now and create a new
program, say called "[Link]." Let's consider exactly what grade a student should get based on their score
on an exam or a test or a quiz or some other assignment.

2:16:03

I'm going to go ahead and run "code [Link]" to give myself a new file, and I'm going to go ahead and
start by just getting the user's score again on some assignment or test or the like, and I'm going to store it
in a variable called "score" equal to the return value of the "int" function, which is going to convert
whatever the user's input is when prompted for this score. So again, the user should just oblige by giving
me a number like zero or one or two, or hopefully much higher than that, like 97, 98, 99, 100, assuming the
test or assessment is out of 100 percentage points.

Now, how could I go about assigning a grade to the student's score? Well, in the U.S., it's very commonly
the case that if you get between a 90 and 100, that's an A, and if it's between an 80 and 89, it's a B, if it's 70
and 79, it's a C, and so forth all the way down to F, which should be E, but we'll see that there's a bit of a
jump. So how might I express this? Well, I can use conditionals, and I can ask a few questions and then print
out the student's grade accordingly.

So let me express it like this: if the student's score is greater than or equal to 90 and the student's score is
less than or equal to 100, so it's in that range, let's go ahead and print out that their grade shall be an A
because they're in the 90s above grades range. Else, if the score is greater than or equal to 80 and the score
is less than 90, but here, I have some options. Logically, I can actually express myself in any number of ways,
and maybe just to be a little cleaner, I'm going to say "and score is less than 90." So I'm using "less than"
instead of "less than or equal to," so I'm making sure that their boundaries between these grades are
correct. Then, I'm going to go ahead and give the student a B if it's in the 80s.

Elif, the score is greater than or equal to 70 and the score is less than 80, I'm going to go ahead and give
them a C. Elif, the score is greater than or equal to 60 and the score is less than 70, I'm going to go ahead
and give them a D. And here's where it's a little anomalous, at least in some schools here: else, I'm going to
go ahead and give them an F. So we're skipping E altogether, and we're going to give an F instead for the
grade.

2:18:12

40 / 96
So that's the catch-all, and I think logically I've gotten this correct, at least based on where I went to school
growing up, such that it's going to give an A or a B or C or a D; else, it's going to assume that you got an F.
Well, let's try just a few of these here. Let's run "python [Link]." My score is, let's start strong, 100. Alright,
I got an A. Didn't do as well the next time, maybe it's a 95, still an A. Starting to slip further, so I got an 89,
that's now a B. And let's say I really had a bad week, and it's now like a 71, that's now a C. Or I didn't even
submit it at all, that's an F altogether. Alright, it seems to work. That's not really an exhaustive test, but at
least based on some sampling there, my code seems to work as I expect.

But let's see if we can't tighten this up. It's not wrong; it's correct, and indeed, according to my own
specifications, I dare say this code is correct. But can we tighten it up? Can we reduce the probability of
bugs down the line? Can we increase the readability of it, and can we increase the efficiency of it? Can we
get the computer to have to answer fewer questions and still get the same result?

Well, let's see what we might do. Let me just kind of switch things up if only to demonstrate that we can use
these symbols in different ways. I could say, as I've done, if score is greater than or equal to 90, but I can
actually do this. I can flip it around instead of saying "greater than or equal to," let's say 90 is less than or
equal to score, and here, let's say if 80 is less than or equal to score, and here, 70 is less than or equal to
score, and then lastly, 60 is less than or equal to score. So it's the same thing logically; I'm just kind of
switching things around, just like you could do on paper-pencil if you really wanted.

But now notice this trick, and this is not possible for those of you who have programmed in C or C++ or
Java or other languages. Notice what I can do here is actually combine these ranges. Notice that I'm asking
two questions, two Boolean expressions: "Is 90 less than or equal to score?" and "Is score less than or equal
to 100?"

2:20:16

Well, Python allows you to nest these things like this and chain them together, and just like you would on
paper pencil in the real world, you can encode in Python to do this.

2:20:23

This is just a little cleaner, right? It's tightening up the code a little bit. It's fewer keystrokes, it's faster to
type, and it's easier to read moving forward. So that's arguably better as well. So that's one improvement;
it's largely aesthetic in this case. It's still asking the same number of questions, but it's doing it a little more
succinctly.

2:20:40

Still, well, what more could I do here next? Well, you know, each time I'm deciding these grades, I don't
think I have to ask two questions. I don't have to ask, "Is it greater than 90 and less than 100? Is it greater
than 80 and less than 90?" If I kind of rethink my logic, I can maybe do this better. Still, let me propose that
we simplify this further and just do this:

2:21:04

41 / 96
If we know the input, for the moment, is going to be within 0 and 100, we can make some assumptions. We
could say something like if the score is greater than or equal to 90, well, the student gets an A. If the score
is greater than or equal to 80, the student gets a B. If the score is greater than or equal to 70, they get a C. If
the score is greater than or equal to 60, they get a D. Else, they get an F.

2:21:34

What have I done here? Well, instead of asking two questions every time, checking the lower bound and the
upper bound of that range, I'm kind of being a little more clever here by asking if the score is greater than
90, well, they've obviously gotten an A or better. If your score is greater than 80, well, you either deserve an
A if it's really strong, or a B if it's just above 80. But because of the if-else logic, we've already checked if the
student's score is greater than 90. If it's not, then we're asking the question, "Is it greater than 80?" So you
implicitly know it's somewhere in the 80 to 89 range. Else, you know it's in the 70 to 79 range. Else, it's in
the next range down. So it's a minor optimization that allows us to ask fewer questions, but again, it's
making the code arguably a little more readable, certainly more...

2:22:17

So it's a minor optimization that allows us to ask fewer questions, but again, it's making the code arguably a
little more readable, certainly more succinct, and then hopefully more maintainable longer term. Any
questions then on these types of changes and this type of logic with our code? What if we don't use elif at
all? What if we write the code in F? Yeah, that's a good question because it's actually going to have an
unintended effect. Let me get rid of the F temporarily and just focus on A through D.

If we revert to where we began today's story with conditionals, saying "if if if," now our cleverness here of
using broader strokes and not using upper and lower bound ranges is going to come back to be a
downside. Let me go ahead and run python [Link], and suppose my score is 95. I am so darn excited. I
want my A, but nope, I just got an A, a B, a C, and a D. So logically, that's broken things because if you don't
make these conditions mutually exclusive, every one of those questions is going to get asked and therefore
answered. Even if your grade is above 90, it's also logically above an 80, above a 70, above a 60, and if I'd
kept it in there, I would have failed as well with an F. Really good question. Any other questions here on this
form of logic? Like, would there be any, I guess, better way to kind of clean up even just this simple
statement like we had before, the previous one that you had with the elif? Oh, I like your enthusiasm for
simplifying things further. I'm gonna go out on a limb here and say this is about as good as it gets, at least
using only conditional statements. I can, if my mind wanders, think of a slightly more clever way to do this,
maybe with something called a loop or another programming construct we don't have that yet in our
vocabulary. But yes, there's absolutely other ways to do it, but I think not yet if we want to restrict ourselves
to just words like if and or and else, and elif, and the like.

2:24:22

Well, let me propose that we pivot now to use another approach here that uses one other symbol that up
until now we've not really had occasion to use. Let me propose that we implement a program that we'll call
"parity" in mathematics. Parity can refer to whether a number is even or odd, and that's kind of an
interesting question. And it turns out it can be useful in other applications too, to just ask the question, "Is a

42 / 96
given number even or odd?" Maybe that the user typed in. Let me go ahead and write a new program
called "[Link]" via code [Link] in my terminal. And let me propose that we use this as an opportunity
to introduce the last of those arithmetic symbols, at least most of which we're familiar with: addition,
subtraction, multiplication, division. But there's been one on this list before this last one here: a percent
sign. And it doesn't mean percentage in this case when used as an operator in programming in Python.
Rather, it represents the so-called modulo operator for modular arithmetic, or at least in our case, we're
going to use it to calculate the remainder when dividing one number by another.

Well, what do I mean by that? If you take a number like 1 divided by 3, 3 does not go into 1 cleanly, so you
have a remainder of one. Two divided by three has a remainder of two. Three divided by three has a
remainder of zero because it divides cleanly. Four divided by three has a remainder of one because you can
divide it in once, but then that leaves one, so it has a remainder of one. And then, lastly, something like 5
divided by 3 has a remainder, of course, of two. So that's all we mean by remainder - how much is left over
after dividing one number by another.

Well, if I go back now to my code and consider how I might implement the question, "Is this number even
or odd?" Let's consider how we might implement that since it's perhaps not necessarily obvious how we can
use this additional building block, but it turns out it's going to be very useful longer-term.

2:26:13

Let's first just get a number from the user in a variable called X, and I'm going to set that equal to the
conversion to int of whatever the user inputs after asking them, "What's X?" We've done that before many
times. How do I now determine if X is even or odd? Well, it turns out if I have access to a programmatic
operator that tells me the remainder, I think I can do this. In fact, let me just ask the group, and this is just
from grade school math perhaps: What does it mean for a number to be even? To be clear, a number like
zero, two, four, six, eight, ten, twelve, fourteen, sixteen, those are all even numbers. But what does that really
mean, Elena, if I'm saying that right? Even numbers that can divide it exactly by two, for example, two, four,
six, eight, and ten.

Perfect! And we could go on all day long, literally, since there's an infinite number of those even numbers.
But it's nice that you formulated it in terms of a question that we can ask very clearly: Is this number cleanly
divided by two? That is, can we divide it by two with no remainder, a remainder of zero? Well, that's perfect
because if we have this operator, this percentage sign, that allows us to answer just that - what is the
remainder, we can presumably check is the remainder is zero, or is it one? Do we have nothing left over, or
do we have one left over?

Well, let's ask that. If X divided by two has a remainder of zero, as Elena proposes, let's go ahead and print
out something like "even" and just say as much to the user. Else, I think we can assume that if a number is
not even, it's going to be odd if it's indeed an integer. So I'm going to go ahead and print out "odd"
instead. Let's go ahead and now run python [Link] in my prompt.

"What's X?" Let's start with two. Two is, in fact, even. Let's start with four. Four is, in fact, even. Let's get
interesting with three. Three is now odd. And I think we could do that all day long and hopefully get back,
indeed, exactly that answer.

43 / 96
But what more could we do here? How could we improve upon this?

2:28:19

Well, recall that we have the ability to invent our own functions, and let me just propose, for the sake of
discussion, that we're eventually going to find that it's useful to be able to determine if a number is even or
odd, and so we'd like to have that functionality built-in. And I don't think Python has a function for telling
me just that, but I can invent it using code, like just this.

So, let me go into my earlier version here and let me propose that we do this. Let me go ahead and write a
main function. I'm going to get back into that habit of defining a main function to represent the main part
of my program, and I'm going to do what I did before: I'm going to get an integer from the user's input,
asking them, "What's X?" And then I'm going to ask this question. For the moment, I'm going to naively
assume that the function already exists, but that's a useful problem-solving technique, even if I have no idea
yet where I'm going with this, how I'm going to invent a function that determines if a number is even. I'm
just going to assume that there's a function called is_even, and I'm going to call it blindly like this: if
is_even(x) and then go ahead and print "even". So if this magical function called is_even returns True as
its return value, I am going to print out that it's even. Otherwise, I'm going to assume that it's, of course,
odd.

Now, the one problem with this program, even if I call main over here, is that is_even does not exist, and
this program would break if I ran it right now. But that's okay, I have the ability to recall to invent my own
function. So let me define, with def, a function called is_even. I want this function to take an argument, and
I'm going to call it n, just a number generically. I could call it x, but again, I don't want to confuse myself as
to which x is which, so I'm going to give it a different name, and that's fine. I'm just going to call it more
generically n for number. And then I'm going to do this: I'm going to say if n % 2 == 0, just like before.

2:30:22

Then, and here's the magic you, the programmer, can actually return what are called Boolean values. We've
seen in Python that Python has strings, integers, floats, all of which are different types of data in Python.
Python also has a fourth data type called bool for a Boolean value, and even though this is just adding to
our list, the nice thing about Booleans is that they can only be True or False. An int can be any number of
an infinite possible values, but a Boolean can only be True or False, and it must be capital T and capital F if
you're writing it yourself.

So, if I go back now to my code and consider exactly what I want to return here: well, if n % 2 == 0, that is,
if n divided by 2 has a remainder of 0, well, I think it's even, according to Elena's definition, so let's return
True (capital T). Else, if it doesn't have a remainder of zero, I'm pretty sure mathematically it's got to have a
remainder of one, but it doesn't matter, I know it's not even, so I'm going to return False (capital F).

And now that we've defined both main and is_even, and I'm calling main at the bottom, I think I've got this
right. python [Link], enter. "What's X?" Let's try something simple like two, and it's even. Let's do it
again. "What's X?" How about four? Even once more. "What's X?" How about three? And it's odd.

44 / 96
Now, what have I done here? I've just made the point that if I want to create my own function called
is_even that answers this question for me, that I can now use in this program and heck, maybe future
programs that I write. I now have a function that no one gave me, I gave myself that I can use and reuse,
and I can even perhaps share it with others. I'm using that function now on line three just to make a
decision. I'm using a conditional up there, and my Boolean expression, something that's true or false, is
going to be not something explicit like x < y or y > x or the like. It's going to be a function call.

2:32:32

I'm using a function as my Boolean expression, but that's okay because I know, because I wrote it, that the
function is_even returns True or it returns False, and that's all I need in a conditional to make a decision to
print "even" or print "odd." So let me pause here to see if there are any questions now on how I've
implemented is_even using this Boolean value.

Hello, hi David, first of all, thank you for this wonderful class. I have just one query. Based on the
background of Java, when we used to pass the arguments, we can also pass the address of the variables. So
is there any sort of this concept in Python?

Short answer: No. Those who are unfamiliar with Java or other languages like C or C++, there are generally
ways to pass values in different mechanisms that allow you or disallow you to change them. In Python, no.
Everything we're going to see is actually, in fact, an object, but more on that down the line. How about time
for one more question here on these Booleans and these is_even?

So I actually had a question about defining a function. If that's okay, sure. So if you define one, are you
allowed to use the dot operator like we did [Link]() and use it like that?

Good question. If you've created your own function, can you use other functions like [Link]() or
[Link]() or [Link]() that we've seen in the past? You can use those on strings. Those
functions come with strings. You can't necessarily use them on your own functions unless your function
returns a string. For the examples you gave, I'm returning a Boolean. Booleans have no notion of white
space to the left or the right. You can't call strip(), you can't call capitalize(). But if you were writing a
different function that returns a string, absolutely you could use those functions as well.

Well, let me turn our attention, if I may, back to this example here and consider, as we now frequently do,
can we improve on the design of this code? Can I make this particular program better? And I can.

2:34:34

There are a couple of ways here, and I'll show you something that's now generally known as something
"Pythonic." There's actually this term of art in the Python world where something is "Pythonic" if it's just the
way you do things in Python, which is to say we've seen already there are so many different ways to solve
certain problems, and in the Python community of programmers, there tend to be some ways that are
smiled upon more than others, and they tend to relate to features that maybe only Python has but not
other languages.

45 / 96
Here's some syntax that you might not have seen in languages like Java or C or C++. If you've programmed
before, and if you've never programmed before, this too is going to be new. Instead of asking a question
like this if...else using four lines, in Pyt
Python,
hon, you can actually collapse this into just one more elegant line, if
you will.

Instead of asking if n divided by 2 has a remainder of 0, return True, else, return False
False. Let me delete all of
that and just say this:

Now, those of you who do have prior programming experience might actually think this is kind of cool. You
can condense from four lines into one line with that very same thought. And one of the reasons why Python
is popular is that it does tend to read rath
rather like English. It's not quite as user-friendly
friendly as most English or
most human languages, but notice now, the line does rather say what you mean: "Return True if n divided
by 2 has a remainder of 0, else False."
." I mean, that's pretty darn close to somethin
something you might say logically
in English, be it about even and odd or really anything else.

So that program is going to work exactly the same. python [Link].. Let me type in two. It's still even. Let
me type in three. It's still odd.

But I can refine this even


en further, and again, consistent with this idea of not just writing correct code but
writing better and better code while still keeping it readable. I can do one even better than this.

2:36:37

Notice this value here is my Boolean expression, and it is going to evaluate to True or False. Is n divided by
2 having a remainder of 0 or not? Like that, is by definition a Boolean expression. It has a "yes" or "no"
answer, a True or False answer. Well, if your Boolean expression itself has a True or False answer, why are
you asking a question in the first place? Why ask if? Why say else?? Just return the value of your own
Boolean expression.

And perhaps the tightest version, the most succinct and still rereadable
adable version of this code would be to
delete this whole line, pythonic though it is, and just return n % 2 == 0.. If it helps, let me add parentheses
temporarily because what's going to happen in parentheses will happen first. n divided by 2 either does o or
does not have a remainder of zero. If it does, the answer is True;; if it doesn't, the answer is False. So just
return the question, if you will. You don't need to wrap it explicitly with an if and an else, and in fact,
because of the order of operations, you don't even need the parentheses.

Now, this is perhaps the most elegant way to implement the same idea. Now, which is better? This is pretty
darn good, and it's hard to take fault with this because it's so very succinct. But it's perfectly okay and jus
just
as correct to have an if and then an else
else,, even though it might be four total lines. If that helps you think
about your code more clearly, and it helps other people reason about it as well.

46 / 96
So, it turns out there's another syntax that you can use to implement the same idea of a conditional,
whereby you do something optionally based on the answer to some Boolean expression, and the keyword
that you can now use in recent versions of Python is called match. match is a mechanism that, if you've
programmed before, is similar in spirit to something called switch in other languages. For instance, let me
go ahead here and close out [Link], and let me go ahead and create a new file called [Link].

2:38:49

In [Link], I think what we're going to do is try to implement a program that prompts the user for their
name, and it just outputs what house they're known to be in in the world of Harry Potter. So, for instance,
let me go ahead and do this: Let me give myself a variable called name, set it equal to the return value of
the input function, and I'll say something like, "What's your name?" And then after that, I'm just going to
use a traditional if-elif-else construct to decide what house this person is in.

Let me go ahead now and run this as python [Link], and I'll go ahead and type in something like
"Harry," and voila, we see that Harry is indeed in Gryffindor. Let's run it one more time: python [Link].
Let's type in "Draco" this time, "Slytherin." And now let's type in an unrecognized name. Let's go ahead and
rerun python [Link] and let's go ahead and type in "Padma." It says "Who?" because we haven't actually
hard-coded with an elif condition in this case what house Padma is meant to be in.

Alright, well, it turns out there are other ways to implement this. Indeed, there's some redundancy here in
that we're checking if Harry or Hermione or Ron are all in Gryffindor.

2:40:44

Alright, well, it turns out there are other ways to implement this. Indeed, there's some redundancy here in
that we're checking if Harry or Hermione or Ron are all in Gryffindor. I feel like we can at least tighten this
code up a little bit using techniques we've seen already.

Let's get rid of these two blocks of elif statements, leaving just Harry's for a moment, and let's use that or
keyword again and say name == "Harry" or name == "Hermione" or name == "Ron", thereby
consolidating all three cases into just one if statement. Then we still have a separate elif for Draco because
he's not, in fact, in Gryffindor, and finally, the else to catch anyone else.

47 / 96
It turns out there's another approach altogether that can perhaps make your code a little less verbose. You
could imagine how complicated this code might get if we had not just Harry, Hermione, and Ron but a
whole bunch of other names as well for Gryffindor, Slytherin, and for all of the other Hogwarts houses. You
can imagine that code just getting pretty unwieldy pretty fast.

Well, it turns out another technique you can use is indeed this keyword called match, which is very similar
in spirit, but the syntax is different and allows you to express the same ideas a little more compactly. So, let
me go back to [Link] and let me propose that I get rid of my current if-elif-else approach and instead
do this: literally use the keyword match and type the name of the variable or value that we want to match
on. Then I'm going to go ahead and include a colon, and underneath that, I'm going to include literally a
keyword called case, and the first case I want to consider is going to be "Harry". I'm going to put "Harry" in
quotes because it's a string, and I'm going to have another colon at the end of this line.

2:42:23

And indent it under that one. I'm going to go ahead and for now print out Gryffindor, which, of course, is
Harry's house. Otherwise, I'm going to have another case for "Hermione," and similarly, I'm going to have
under that indented print "Gryffindor."

2:42:28

Now I'm going to have another case for Ron, also in quotes with a colon. Now print "Gryffindor."

2:42:34

And now I'm going to have another case for, let's say, Draco. This one gets a little more interesting because
Draco, of course, is in Slytherin. And then I'm gonna go ahead and leave it at that for now. So let me go
ahead and save this file and go back down to my terminal window running Python of [Link], enter.

2:42:58

Let's go ahead and try Harry, and he seems still to be in Gryffindor. Let's run it again for Hermione, enter,
Gryffindor. Let's skip ahead to Draco and type in Draco's name. He's indeed in Slytherin.

2:43:12

Now let's try another name that we haven't handled a case for, like Padma. Again, enter, and we're just
ignored. There's no output whatsoever because there wasn't a case for Padma. Now we could, of course, go
back in and explicitly add one for Padma, but what if we, similarly to the else construct, just want kind of a
catch-all that handles anyone whose name is not explicitly specified?

2:43:31

Well, turns out the syntax for that, using this new match statement, is to still have another case, but then to
use this single underscore character, which is used in other contexts in Python, but for here, it's meant to

48 / 96
say whatever case has not yet been handled, go ahead and print out, as we did before, for instance, "who?"
with a question mark at the end.

2:43:49

Now let's go ahead and rerun this Python of [Link]. I'll type Padma's name again, and this time, I think
we're at least going to get an explicit response indicating "who," whereas previously we did not have the
equivalent of that. Now I think we've regressed a little bit. We went from tightening things up by putting
Harry and Hermione and Ron all on the same line in the same if statement, but here we have now three
case statements again for all three of those.

2:44:20

Well, we can tighten this code up as well, but the syntax is going to be a little bit different. I'm going to go
ahead and delete these two middle cases for Hermione and Ron, and then up here next to Harry's name,
before the colon, I'm going to go ahead and use a single vertical bar and then a "quote-unquote
Hermione," then another single bar and "quote-unquote Ron."

2:44:38

And this is how, using this relatively new match statement, you can say the equivalent of Harry or Hermione
or Ron, but more concisely than you could using an if statement alone as we implemented it previously. So
now one final run of the program with Python of [Link]. Let's make sure that Harry is still in Gryffindor.
Let's make sure that Hermione is still in Gryffindor. Let's make sure that Ron is still in Gryffindor, and indeed,
all three of them are.

2:45:05

Now, as always with Python and programming more generally, there's going to be different ways you can
solve these problems. This is just another tool in your toolkit, arguably it has tightened things up. Arguably,
it's perhaps a little more readable because there's a little less syntax going on, a little less duplication of
equal signs and "elephant elephant eleph" all over the place, but ultimately, this would be an equally correct
approach to that same problem.

2:45:23

But it turns out with the match statement, you can do even more powerful forms of matching as well. Here
we've used it simply to implement the same idea as that if-elif-else construct, and it's worth noting if you've
programmed in some other language, the syntax here is indeed correct. You do not need, for instance, a
break statement as has been peppered throughout, and you don't need something like "default" or
something explicit; you indeed just use this underscore as your catch-all at the end of the match.

2:45:51

So just by adding in some of these new keywords here like "if" and "elif" and "else," we have now the ability
to ask questions about values, we have the ability to analyze input from users, and ultimately make

49 / 96
decisions about it. These then were our conditionals. Lying ahead is going to be the ability for us to not
only use functions and variables and also these conditionals but also next loops, the ability to do something
now, again and again.

2:46:47

Alright, this is CS50's Introduction to Programming with Python. My name is David Malan, and this week, we
focus on Loops, the ability in Python and a lot of other programming languages to do something again and
again, a cycle of sorts. Let's see if we can't begin by motivating exactly why we have this ability to do things
cyclically using these loops.

2:47:04

I'm going to go ahead here and open up VS Code, and in my terminal window, let's go ahead and create a
Python program that meows like a cat. I'm going to go ahead here in this code tab very simply, perhaps I'm
going to start by implementing this cat just by using print. We're going to have this cat not make audible
sounds but just print "meow, meow, meow" on the screen three times.

2:47:25

Well, I think the simplest way I can do this is just to print "meow" once and to print "meow" again and to
print "meow" one last time on the screen. Now let me go down to my terminal window, let me run Python
of [Link], enter, and "meow, meow, meow."

2:47:48

Alright, so this program works. This program indeed works if my goal is to get the cat to meow three times.
And let me propose, just to help us wrap our minds around what's going on inside the computer, let me
propose that we consider this flowchart. So, as before, we have this flowchart that starts with a this oval,
which just means "start reading here," and then notice it goes via arrows to "meow, meow, meow," and then
it stops. It's perfectly correct and honestly, it's wonderfully simple. But I dare say we can find fault with my
code nonetheless.

2:48:18

Why is my code arguably poorly designed? Now the answer is going to be Loops in some way, but let's see
if we can identify in what way the code is actually poorly designed, in some sense. Let's see, any thoughts,
Alex?

2:48:32

Okay, so I mean repeating the same action like three times, so even more. Um, it's not a good habit. Yeah,
I'm just repeating myself, and honestly, it's not that big a deal. If we go back to my code here, am I really
doing such a bad thing by just printing "meow, meow, meow" three times? Not really, but let's consider the
logical extension of this. Suppose I wanted "meow" four times or five times or 50 times or 500 times. Do
you really think, even if you've never programmed before, is the solution to this problem really going to be

50 / 96
to hit copy-paste 50 times? Like, probably not. We can probably do better than that. And beyond it just
being ugly at that point, having so many lines of identical code, just imagine if you wanted to change the
code. Maybe I changed my mind, and I don't want to make a cat. I want to make a dog, so now it has to say
"woof, woof, woof" multiple times. Now I have to change that in like 50 different places, and yes, sure, I
could do find and replace, but come on, like, we're programmers now. There's got to be a better way than
just repeating ourselves. So, I bet that we can do better than that if we think about it a little harder, how we
go about structuring this program, and we can do that if we augment our vocabulary just a little bit.

2:49:51

It turns out in Python, and in other languages too, there's a keyword called "while," and "while" is one way
that we can express what's called a loop, a block of code that's going to do something again and again and
again. Zero times, one time, two times, fifty times, as many times as we want. But "while" rather leaves to us
the particulars of how we express ourselves to do something again and again. So, let me go back over to VS
Code here, and let me propose that I do this: "while" is a construct that allows me to ask a question again
and again. And anytime we've seen a question, it's been in the form of a Boolean expression, a question to
which the answer is true or false.

2:50:29

Well, how could I do this? How could I print out "meow" three times and ask three times a question to
which the answer is true or false? Well, what if I did some counting, right? Like literally on my fingers, and if
I'm trying to count maybe down from three, I want to meow three times. I can put three fingers up, and I
can meow, and then I can put like one of the fingers down and then meow, and I can put one of the fingers
down and I can meow, put one of the fingers down, and maybe the question I can ask every time I meow is,
"Do I have any fingers up still? Do I have any fingers up still? Do I have any fingers up still?" If the answer is
true, keep going. If the answer is false, stop.

2:51:11

So, how can I translate that to code? Well, once we've added this "while" keyword, I think we have all the
building blocks already. Let me propose that I do this. Let me propose that I give myself a variable, and I'll
call it "I" for integer, but I could call it anything I want, and I'm going to initialize it to 3. Then, I'm going to
use this new feature of Python, "while," and I'm going to ask a question the answer to which must be true
or false, and I'm going to say, "while I does not equal zero," so I'm going to ask the question, "while I does
not equal 0, do the following." Notice the colon at the end of the line, notice my indentation, and just like
with functions, just like with conditionals, you indent the lines that you only want to execute as part of this
other thing.

2:51:52

What do I want to do while I does not equal zero? Well, I think I just want to meow. But it's not enough just
to write this code. If I were to very dangerously run Python of [Link] and hit enter right now, what might
happen on the screen, whether you've programmed before or not? Why is this a very bad thing potentially?
It's not going to break things, but it might lose control of my computer somehow. Any thoughts? Uh, yeah,
Teemo, hi, uh, I think it's going to continue to print out "meow" since I is always equal to 3, and the "while"

51 / 96
is always true. Yeah, exactly. If I'm initializing I to three, that is setting it equal to three on line one, then I'm
asking the question, "while I does not equal zero," and that's going to be true; it does not equal zero, it
obviously equals three.

2:52:57

Print "meow," and the way a while loop works is that the Python interpreter just keeps going back and forth.
It goes from line one to line two, then to line three, and then it goes back to line two to ask the question
again. If the answer is still true, it goes to line three. It then goes back to line two if the answer is still true, it
goes back to line three, and to Teemo's point, if you're never actually changing the value of I, it's always
three, you're just going to be looping literally forever, and this is an accidental infinite loop. So we've got to
be smarter than that. I'm not going to hit enter because I don't want to lose control over my computer here,
such that it's printing out "meow" forever. Fortunately, if you ever do that, and you find yourself in an
accidental infinite loop, Control+C for cancel or interrupt is going to be your friend. If you ever seem to lose
control, you don't need to reboot or turn off the computer; you can just hit Ctrl+C in your terminal window,
and that will likely fix it.

2:53:56

Well, what do I want to do then after meowing each time? I think what I'd like to do here is maybe
something like this. Let me update I to equal whatever the current value is, minus one. Here, whoops, sorry,
minus one. So if I, on each iteration, am updating I to be one less, one less, one less, it should eventually hit
zero, at which point the answer to the question will now be false. So let's see if this works. I'm going to go
down to my terminal window and run python of [Link], and I indeed get three meows. Why? Why? Because
I've kind of wired this up, kind of like a machine in software, if you will. I've set I equal to three, then I keep
asking this question, but I keep turning the gears, I keep changing the value of the variable to make sure
that ultimately, it is actually being decremented, that is decreased by one, until we eventually hit zero.

2:54:53

Now, for those of you who think a little more graphically, let me pull up one of our usual flowcharts. This is
just a representation graphically of the exact same thing. Notice what's happening: I first start the program,
and then I initialize I to three, and then I ask the first of my questions. Again, the diamonds...

2:55:10

Again, the diamonds always represent questions, and the answer is going to be true or false. Does I not
equal zero? Well, it doesn't equal three. So if I follow the true line, I meow, and then I follow this arrow, and
I update I to equal I minus 1. At this point in the story, I presumably equals two mathematically. I follow the
arrow, and there's the loop. This is why it's nice to see this graphically, perhaps because you can literally see
the loop back and forth. Now I ask the question again: Does two not equal zero? Well, it does not equal
zero; it's two. So we meow again, we change I from two to one. Well, does one not equal zero? Well,
obviously, if one is not zero, so we meow again, we decrement I again. I is now zero. Does zero not equal
zero? No, it equals zero, so the answer is false, and we stop.

2:56:19

52 / 96
So there, perhaps more so than any of our flowcharts before, do you really see the structure of what's
happening inside of the program. You don't have to get into the habit of making these charts or creating
these charts, but just as a first pass at what's going on inside of the computer, that's indeed one way to
visualize it. Instead, well, let me propose that, like always, there's many different ways to solve this problem,
and suppose you just like to think a little differently. Maybe you don't like starting at three and then
counting down to zero. Maybe your just brain doesn't work that way, and you prefer to count up instead of
down. Totally fine. Let me go ahead and change my code here to set I equal to one instead of three, and
here, let me just change my logic. Rather than checking for "not equal to zero," maybe you don't like
thinking in terms of "not" because it's a little confusing, and it might be. Let's just check that I is less than or
equal to three, so we'll be a little more explicit. We'll count from one up through three each time, printing
"meow." But I'm going to need to change this line here. Let me see if we can't call on someone to change
line four for me.

2:57:08

How do I want to change line four to be consistent with counting from one up to and through three? I
would add one every time you meow.

2:57:20

Yeah, exactly. In this case, we want to add one, not subtract one. And in fact, if you think about this, this two
could end very poorly, right? If you start counting at one and you keep subtracting one, subtracting one,
subtracting one, I think we're going to find ourselves with the same problem, which is that we're never
going to stop because we're going to keep getting more and more negative, as opposed to ever getting up
to the number three. So I think you're right; I need to change this to be "I equals I plus one." And now,
notice just for clarity too, the equal sign is again our assignment operator from right to left. Logically, this
might otherwise strike you as strange, like how can I equal itself plus one? Well, it doesn't until you execute
this code from right to left; you add one to I or you subtract one from I, and then you update the value of I
on the left. The assignment copies the value from the right to the left. Well, how else might I do this? Well, I
will say that most programmers, computer scientists more generally, tend to start counting from zero. It's a
convention, and it actually has upsides even in Python and other languages, where generally speaking, it's a
good thing to start counting from zero instead of counting like we might in the real world from one. Let's
go ahead and adopt that convention. Now, let me set I equal to zero, and I need to make a change. Now,
notice, if I don't change my logic, this program just became buggy; the cat has a bug. It's now meowing
four times if I run it as is. But the easiest fix here would be to change my inequality to be "less than" instead
of "less than or equal to." Now, I'm starting at zero, but I'm going up to but not through three. And even
though this might, of all the things we've seen thus far, seem maybe the least familiar, most of us might
start at one, two, then three. It's a good habit to get into now: start at zero and go up to but not through
the value that you care about ultimately, at least three in this case here.

2:59:18

Well, let me tighten things up a bit here. Not only will this now fix my counting problem, it now meows
three times as expected. There's a more succinct way to express "I equals I plus one," and this is because it's
such a popular thing to do in code. You can instead just say "I plus equals one," and that's it. You don't
need to put everything on the right-hand side. This is a special syntax that says the exact same thing:

53 / 96
increment I, but it does it with a few fewer keystrokes. It's just a little more pleasant to type; it's a little faster
to read. It's just a convention. Those of you who have programmed in C, C++, Python (not Python, sorry), C,
C++, Java, JavaScript might have seen "plus plus" before or "minus minus" (sorry, Python doesn't have it, so
you cannot use that). This is as succinct as your line of code might get. All right, let me pause here to see
then if there are any questions about these implementations of while loops. Can we use stuff like for loops,
which have a certain I value initialized to it at the start and it runs from the particular condition you put into
the thing and increment it as you go along?

3:00:04

Short answer: no, you cannot do what you're describing, but there is another type of for loop that we will
soon see. But let's compare to that in just a moment. Other questions on loops using while here?

3:00:12

So I had a question about the flow charts. Okay, there were certainly certain symbols for certain kinds of
statements. I deliberately used certain types of symbols, certain shapes here, whereby an oval is
conventional for start and stop. I used rectangles for any statement of code, like an assignment or a printing
and so forth. And I used diamonds to represent questions that you might ask, conditions as we've seen. If
you're doing this for yourself, if you're just trying to make sense of your code and writing it down, you
certainly don't need to use these formal symbols, but I tried to be consistent with some best practices.

3:01:39 And in fact, let me come back to the same picture because this was the first version of our picture,
but we've since modified our code a couple of times. This recall was the version where the question we
were asking was, "Is I not equal to zero?" Let me go ahead and just change this code now to represent the
next version we did, which recalled changed our logic to start counting from one, changed our question to
check, "Is I less than or equal to three?" But then everything else was the same, except for the counting,
which is now plus instead of minus. And then we refined it a little bit further by counting now from zero up
to but not through three, and we tightened up this code here by just incrementing one by using the slightly
more succinct syntax. So at this point, these flow charts might become less and less useful for us because
once you've wrapped your mind around the concept, and hopefully the picture helps bring that concept to
life, it's certainly fine to focus entirely on the code and only think about or even draw something like this if
you need to wrap your mind around something more complicated than you're used to.

3:02:43 Well, let me go ahead, if I may, and propose that we transition to another approach of types of
loops using another keyword here, namely a for loop. And this is a word that does exist in other languages
but doesn't necessarily have as many features as other languages might use it for. But there is a different
type of loop, not a while loop but a for loop. And a for loop is going to allow us to express ourselves a little
differently, but to do so, I'd propose that the easiest way is if we introduce one other idea in Python, which
is that of a list. And here too, no pun intended, we're adding to the list of data types that Python supports.
We've seen strings or strings, integers or ints, floats or floating-point values, bools or Boolean expressions.
Python also has lists, which is another type of data but wonderfully, this one's probably pretty familiar. A list
of things in the real world is a list of things in Python. It's a way of containing multiple values all in the same
place, all in the same variable. So what do I mean by this?

54 / 96
3:03:41 Well, let me propose that we go back to our VS Code here and let me kind of start fresh with my
code here and not use a while loop at all, but let me use this new keyword, "for." The way the for loop
works is that it allows you to iterate over a list of items. So what does this look like? It might look like this:
for i in [0, 1, 2]. This is my starting point, and on each iteration of this loop, that is, on each execution of
this loop again and again, I want to print out "meow."

3:04:10 Now I'll admit, I kind of like the look of this code already, even though there's some new syntax here
because it's just shorter than the while loop, right? The while loop had multiple lines a moment ago, and it
was entirely up to me to decide what i is, I have to check a condition, I have to increment or decrement i. I
was doing a lot of work, relatively speaking, to make that thing turn, to make that loop go and go. It was
very mechanical in a sense. You could kind of, in your mind's eye, maybe see the gears turning as all of
these variables are changing, and these questions are being asked. A for loop kind of simplifies all of that
and it just says, if you want a variable like i, a number, and you know in advance how many times you want
this loop to execute, three times, we'll just kind of specify what it is you want i to take on as values explicitly
in this loop. i will be automatically initialized by Python to be zero, then "meow" will be printed, then
Python would automatically update i to equal one, then "meow" will be printed, then Python will
automatically update i to be two, and "meow" will be printed. And because that's it for the values in that
list, Python will stop, and it will only map "meow" a total of three times.

3:05:21 What is the list? The list in this program is exactly that: [0, 1, 2], and notice the square brackets.
Those aren't parentheses; those are square brackets that represent a list. That's how you know visually as
the programmer, that's how Python knows as the language that you intend for that to be a list.

3:05:41 So let me go ahead and run this python [Link], and it works just the same, but it's only two lines.

3:05:48 It's pretty readable once you have familiarity with that construct, but to my constant point about
correctness, not necessarily being the same as design, in what sense is this program perhaps poorly
designed? It seems to work, it meows three times, but why might this not be the best way to solve this
problem, even if you've never programmed before? Again, think about corner cases, things that may or may
not happen, think about extreme cases that really test the quality of this code.

3:06:10 Okay, I think that because like again, we are saying 0, 1, 2, please, subscribed, and then like if you
want to print a million, you say one, two, three, yeah, exactly. And that's what I mean about thinking about
the extreme cases. If you're trying to decide for yourself if your own code is good or someone else's code is
good, it might look so at first glance, but think about the extreme, well, what if it's not three things, it's a
million things? I mean, are you really gonna write out one, zero, through a million, or zero through nine,
999,000, 999,999? Like, no, you're not gonna write that many numbers on the screen. There's got to be a
better way. So let's do the better way from the get-go, rather than set the stage for doing something
poorly. And the one way we can solve this problem to improve the design is don't just manually specify the
list of values, use a function, someone else's function that comes with Python, that gives you the list you
want. And the easiest way to do that in Python is to use a function called range that returns a range of
values. It expects at least one argument, and that number is going to be the number of values you want
back. Those values are going to start at zero and go to one, two, and so forth, but they will go up to but not
through the number you specify. So by specifying range(3), you're essentially being handed back one, two,
three values, and by default, those values are 0, 1, and 2, and that's it.

55 / 96
3:07:45 But what's brilliant about this is that now, to Hope's point, if I do want to meow a million times, I
mean, that is an angry cat, I can now do a million by just typing "a million."

3:08:11 "I don't have to literally type zero comma one comma two comma three comma four all the way up
to 999,999. I just do this, so that's got to be a better way long term." That's indeed one improvement we
can make here, still using a for loop, but now using the range function.

3:08:30 And just to show you something else that's Pythonic, this is not strictly necessary, but it's commonly
done. There's a minor improvement we can make here even if we're just meowing three times. Notice that
even though I'm defining a variable i, I'm not ever using it, and it's kind of necessary logically because
Python presumably has to use something for counting, right? It has to know what it's iterating over. But
there's this convention in Python where if you need a variable just because the programming feature
requires it to do some kind of counting or automatic updating, but you, the human, don't care about its
value, a Pythonic improvement here would be to name that variable a single underscore (_). Just because it's
not required doesn't change the correctness of the program, but it signals to yourself later, it signals to
colleagues or teachers that are looking at your code, too, that yes, it's a variable, but you don't care about
its name because you're not using it later. It's just necessary in order to use this feature, this loop, in this
case here.

3:09:31 But to really get you intrigued by what's possible in Python, let's take this one step further. So, if we
really want to be Pythonic, this one, if you've programmed before, is kind of going to blow your mind, so to
speak. What if I want the cat to meow three times? What if I actually do this: print("meow " * 3)?

3:09:49 Alright, you have to be kind of a geek to think this is cool, but this is kind of cool. So you can
literally just print what you want, multiply it by the number of times that you wanted, and you will get back
exactly that result. Now, I've kind of made a mistake here, so let's see what this does.

3:10:14 "It's not quite as beautiful as this code might look to you, to some of you, to me, let me run python
of [Link]." Okay, it's a really like Hungry Cat or something; it's meowing really fast, but I can fix this, I bet.
Let's think about now some of the basic building blocks we've discussed. The problem is clearly that "meow
meow meow" is being repeated three times, but it's not as pretty as I want it. I want it to be "meow meow
meow" on separate lines. What might be a possible solution here while still using this multiplication
operator? Think back. We've used plus to concatenate strings. You can apparently use multiplication to
concatenate strings, but more than once, again and again and again. How could I clean this up without
reverting to my for loop or my while loop and still use multiplication in this way?

We can use an escape sequence. We should do a backslash and, amazing, yes. Think back to backslash n,
which is the way you, as the programmer, can express a new line in code. And I think, if I take your advice, I
put a backslash in there inside of my quotes so that at the end of every "meow," there's a new line. Let's see
how this looks. Let me clear my screen and run python of [Link].

3:11:32 "Okay, so close. I like this. Let me call on someone else. The only thing I don't like, and I know I'm
being really nitpicky now, is that it's 'meow meow meow' on separate lines, but there's kind of this extra
blank line, which I'm just not loving aesthetically. I think we can make an endeavor... Yeah, so here too, like
all of these things we've seen in past weeks, are kind of coming together. Right, recall that the print function

56 / 96
lets you control what the line ending is. By default, it's backslash n itself, which is why at the very end of this
print, the cursor is being moved again to the next line. Well, we need to just override that. So, let me go
into my code here and let me change this to , end="" so that it's no longer the default backslash n. It's
instead now going to be nothing whatsoever. That should eliminate then, hopefully, that additional blank
line."

3:12:27 "So let me run this one last time here, python of [Link], and there we have it. So now you know, at
least as programming goes, it's kind of cool that I can distill this into a short line and express myself all at
once. Now, to be fair, it's a little less readable; like now I've got backslash n, I've got times three, I've got
end="", so you don't have to do things this way. My previous approach with a for loop, totally fine. My
previous approach with a while loop, totally fine. And, in some sense, perfectly well-designed. But this is just
yet another way to do it, but it's not a good thing if you or your teacher, your colleague, your friend are
going to struggle to read your own code. But this is a feature of Python that some languages do not, in fact,
have.

3:13:11 Alright, well let me propose that things get more interesting still if we're not just meowing three
times only, but we're meowing some variable number of times. Let's ask the user how many times this cat
should meow. So, let me clear the screen here and let me figure out, well, how do I get a number from the
user? The catch here is that if I want the user to give me a number, I'm not doing math per se, I'm meowing.
And therefore, the user has to give me a positive value. The user has to give me a positive value. So, how
can I insist on this? Well, if I just do this n = int(input("What's n? ")), what's n? Question mark. Well, I want
to check. Like, I could say if n is less than zero, like if it's negative, well, I could do this, well then, ask again,
int(input("What's n? ")). Okay, well, what if the user still doesn't give me a positive number? What if
they're being really difficult, they're not paying attention and they typed in two negative numbers? Well, if n
is less than zero, well, let's do it again. n = int(input("What's n? ")) - this does not end well. You can't
infinitely many times keep checking 'Is it negative? Is it negative? Is it negative?' Right, the program would
never be done; it would never end. We can do this, I think, better maybe with a loop.

3:14:26 "So let me propose this: A very common paradigm in Python when you want to get user input that
matches a certain expectation - you have that it's all positive, it's all negative, or just something like that -
you just immediately say while True. You deliberately, and a little dangerously but a very conventionally,
induce an infinite loop. Now, what is an infinite loop? It's just one that goes forever, and we've seen how
that can happen accidentally. Mathematically, it's absolutely going to happen when you say while True.
Why? Well, the answer to the True question is always True. So this is a way of deliberately inducing a loop
that, by default, is going to go forever.

3:15:06 So we're going to need a way of breaking out of this loop when we have the number we want. The
convention, though, inside of this otherwise infinite loop, is to ask the question you care about - like 'give
me an int' by prompting the user for input like What's n?. And then just ask your question. So if n is less
than zero, then I think we want Python to just continue to prompt the user again; that is, we want the code
to stay in the loop. Recall the input() function and hope that the user gives us a better answer if this time
around it's less than zero. So let's just literally use Python's keyword continue, which says just that -
continue to stay within this loop.

3:15:42 Else, if it's not less than zero, let's go ahead and just break out of the loop altogether using another
keyword in Python: break. break will break you out of the most recently begun loop. In this case, if it's not
57 / 96
the case that n is less than zero, so this will work and it will allow us to get a value that's zero or greater
from the user. But I think we can tighten it up further so as to not bother having an if and an else. Why
don't we instead just say: if n is greater than zero, go ahead and break. In fact, it's not that interesting a
program if we even allow the user to type in zero. So let's wait until they give us an integer that is greater
than zero and then break out of this loop.

3:16:15 And what can I now do down here? for i in range(n): print("meow") and let me go ahead and
delete the line here that prints the n in between the for loop and the print() statement, because now we're
not using n for anything, it was just a temporary variable to get that user input. So, let me now run this
program with this new version of the loop. python [Link] and it's asking me, 'What's n?' and I'll give it a
positive number, like 5. And it goes ahead and meows 5 times. Let me try again, let's say 10, and it meows
10 times.

3:16:49 So this is a more robust way of getting the user input and making sure it meets our expectation.
And it's just using these loops in combination with the break and continue statements to control the flow
of the program and ensure we get the desired input."

3:16:23 "So what can I now do down here? For i in range of whatever that value n is, print 'meow'. And
honestly, I don't need i here, so let me come back to that principle before, and let me just change it to an
underscore, just to be Pythonic, if you will. So what's going on lines one through four is that I deliberately
implement an infinite loop that otherwise, by default, is going to go forever. But I'm asking a question
inside of that loop. After getting an int from the user on line two, I'm then checking if it's greater than zero
or is it zero or is it negative, none of which makes sense for a meowing cat. I want the cat to meow at least
one time, so if it is greater than zero, break. And this break statement, even though it's indented twice, has
the effect of breaking out of the most recently begun while loop.

3:17:09 So once the user gives you a positive value, then we get to line six, at which point we meow that
many times because of lines six and seven. So if I run this now: python [Link], enter. Well, what's n? Let's
start with 3, where we began: meow, meow, meow. Well, this time, let me go ahead and increase the size of
my terminal window just temporarily. Let me run python [Link]. Let me do it 10 times: meow 10 times now
appears on the screen. The takeaways here are not just that we can meow 10 times or do something again
and again, but this is a very common paradigm in Python when you want to do something again and again
and again but only until the user actually gives you a value that you care about.

3:17:46 Let me propose, actually, now that we practice a little more what we've been preaching, especially
when it comes to writing your own functions. You know, now that I'm doing all this meowing, it might be
nice to actually have a meow function that the inventors of Python didn't envision. So let me do this: Let
me actually get rid of all this code, and let me go ahead and do this. Let me go ahead and say, 'Define a
main function,' as I've done before, and let me just blindly call meow(3). meow doesn't exist yet, but when
it does, that'll be great. So let me go ahead now and define meow, my meow function."

3:18:33 "Should take as input a parameter called n or anything I want, and this part's pretty easy. Now, how
do you meow n times? Well, for _ in range(n), go ahead and just print 'meow'. So same code as before,
nothing new here. I'm just putting that logic inside of a meow function that's going to have this side effect
of printing 'meow'.
58 / 96
3:18:51 Now, as before, let me go down here and let me make sure I call main(). And if I now run this code:
python [Link], meow, meow, meow. It's always going to do three because I've hard-coded the three. Well,
let's make one improvement here. Let me go ahead now and maybe do this: let me ask the user for a
number. So, let's say something like this: number = get_number(). Unfortunately, there is no function in
Python called get_number() that gets a positive number from the user, but I can invent that.

3:19:25 So, define get_number() with empty parentheses. Inside of this function, let me do this: while True,
go ahead and get a number from the user, converting it to an int, asking them: 'What's n?' Then, if n is what
I want, a greater than zero value, a positive number, I don't want to break this time necessarily, although I
could. I instead want to return the value.

3:19:47 And this, too, is a feature of Python - this ability not to just break out of a block of code, but also to
return a value in code, to actually return a value, gives you the ability, ultimately, to return explicitly a value
so that your function has not just a side effect necessarily, but it actually hands back - just like input() does,
just like int() does, just like float() does - an actual value to the user. Now, to be clear, I don't have to
return n here. I can still break out of the loop, as I've done in the past with code like this, but then after the
loop, I still have to return n.

3:20:15 And so, what's happening here is that if you use break to get out of the loop, but you need to hand
back a value from a function, you still have to use the return keyword now explicitly, either in the loop as I
did or now outside of the loop but still inside of the function.

3:20:48 "The last thing I'm going to do here now is change that 3, which we hardcoded earlier, to actually
be the value of the variable we've gotten from the user, so that now, down here, if I run python [Link],
enter, 'What's n?', I can type in three, and I get my three meows. Or, if I only want one, I now get one
'meow' instead."

3:21:05 "So, if we now have this ability to do things again and again in these loops, let's see if we can't solve
some other problems via which to express ourselves cyclically but get back some interesting answers as
well. Let me propose, for instance, that we look a little more closely at these lists. It turns out that in Python,
and really in programs in general, it's useful to have a list of values because we're going to be able to work
with more and more data, larger and larger datasets."

3:21:29 "So, let me propose that we come back to VS Code here and let's do something that's perhaps a
little familiar to some folks - the world of Hogwarts. Let me go ahead and code up a file called
'[Link]', and let's see if we can't have a list of students at Hogwarts. I'm just going to know from the
get-go that the three students I want to consider are these: Hermione, Harry, and Ron. This is a list of length
three, and it's similar in spirit to my list of length three earlier, but that had three integers, 0, 1, 2. Now I
have a list of three strings instead."

3:22:29 "This isn't very useful at the moment, but let me just do something as a check for myself. Let me
print out each of these students. Well, wait a minute, how do I print the contents of a list? Well, in the past,
when we've printed a variable, we've just printed out the name of the variable. But I don't want to print out
just the name of the list here, I want to print out its contents. We'll see in just a moment that Python

59 / 96
actually has a very powerful loop that'll allow us to print out each of the values in this list, and it's called a
'for-each loop.' It's a different kind of loop entirely."

3:22:49 "But I don't want to print out all of Hermione and Harry and Ron all at once. Maybe I want to print
out Hermione first, then Harry, then Ron. So, I need a way to express more precisely which value do I want
from this list. The way you do this in Python is by using square brackets in another way. If you have a
variable, in this case called 'students', and you want to go inside of that variable and get a specific value,
that is to say, you want to index into the list, you use square brackets this way using numbers inside of the
square brackets."

3:23:17 "Here's where we see that it is useful to think and count in terms of zero on up, instead of one on
up. These lists in Python are zero-indexed. The first item in a list is at location zero, the second item in a
Python list is at location one, and the third is at location two. So, you're always kind of off by one mentally,
but you get used to it if you've never programmed before over time."

3:23:46 "Let me print out all three students. So, let me print out 'students[0]', then 'students[1]', and then
lastly, let me print 'students[2]'."

3:24:05 "Of course, if I run this code, it probably does what you would guess. If I run 'python [Link]',
there's Hermione, Harry, and Ron, each on their own lines. But there's got to be a better way, right?
Especially if I don't know in advance who's going to be in this list. If next year, there are some new students
at Hogwarts, we can use a loop to do something automatically, without having to manually type out zero,
then one, and then two."

3:24:17 "Here's another feature of Python: you can use a for Loop not just to count from zero to one to two;
you can use Python to just iterate over anything, not just numbers, but strings. So, I could actually do this:
for student in students: and then indented underneath that, I can say print(student). Now, it doesn't
matter if I have three students, or four, or four hundred; this two lines of code, this Loop, will print all of
those students for me, one at a time.

3:24:52 "So, if I now run python [Link], there's the same list, but I don't need to know in advance
how long that actual list is. Now, notice I made a conscious decision here. I didn't call this variable _ because
this time I'm using the variable, and while I could do this now, no, no, no, no, your code is getting way too
cryptic. If you're naming the variable _ and you're using the variable _, now you're helping no one, now
you're confusing the reader, yourself down the line. You should call your variables what they are, so in a
very appropriate name, though I'm sure you could come up with others, would be student. And here you
could say student as well if you'd prefer to be more succinct. It's not unreasonable to do something
succinct in a loop like this, for s in students, using maybe the same letter that the list itself begins with. But
again, why bother? Python is meant to be more readable. If you have a list of students, iterate over them
one student at a time."

3:25:46 "Let me pause here to see if there are any questions about lists as I've now defined them, a list of
strings in this case, or using a for Loop now to iterate over and print each of those names. Yeah, so is it not
necessary to initiate student in this case, or can we just declare a variable in the loop? Good question. You

60 / 96
do not need to manually initialize it. Python takes care of initializing the student variable to 'Hermione' first,
then 'Harry' second, then 'Ron' third. Unlike other languages, you don't need to initialize it to something
yourself; it just exists, and it will work."

3:26:17 "Other questions on loops and lists in this way since you describe 'break,' so is there any concept of
'continue' so that we can skip a particular case in Loops? Yes, you can 'continue' using another syntax as
well. We haven't shown that for now; we focused only on 'break.'"

3:26:28 "Okay, so can this for Loop work with hash tables or different kind of data tables or arrays? Indeed,
so we're getting ahead of ourselves there, but there are yet other types of data in Python, and indeed,

3:26:48 "You can use a for Loop to iterate over those as well. Anything that is iterable, so to speak, is a piece
of data that can be used with a loop like this, but more on those soon. In fact, let me transition here to
show just another way of solving the same problem. Up until now, when we've used Loops, we really have
relied on numbers, and that's fine if you prefer to sort of stay in that space. Suppose I did want to iterate
using numbers like 'i' in 0, 1, 2, and so forth. Let me propose that we could change this code as follows. If
you would prefer to think about or if the program you're trying to implement requires that you use
numbers like this, you might do this: for i in students."

3:27:20 "I don't want to just say students, because then 'i' is not going to be a number; 'i' is going to be
literally 'Hermione,' then 'Harry,' then 'Ron.' I need to iterate from zero to one to two. Right? If I know a list
with three elements has these locations 0, 1, 2, I need to create a loop somehow that starts at 0 and ends at
2. Previously, when I wanted to do that, I needed range, but this 2 is not going to work. I can't just say in
the range of students, because students is not a number; it's not an integer, so you can't pass it to range.
range expects an integer, but there is a solution here. It turns out that there is a function in Python called
len() or len that will tell you the length of a list and other things down the line, too. And now, I think I can
assemble these building blocks in a way that can allow me to use numbers in this way. So, range doesn't
take a list of strings; it takes a number, and ideally, that number is going to be three so I get a range of
values 0, 1, and 2."

3:28:00 "So, I think I can nest my functions like this. If I first get the length of the students list, that's going
to be 3. Then, I pass that return value as the argument to range, and that's going to give me back a range
of values 0, then 1, then 2. And what that's going to allow me to do then in code, if I want, is not just this. I
could do print(students[i]), and this is now where the syntax we're seeing is getting very expressive, new,
and perhaps unfamiliar.

3:29:04

"But if I can do [Open Bracket] zero [close bracket] or [Open Bracket] one [close bracket] or [Open Bracket]
two [close bracket], turns out I can actually put a variable in there, and I can express any number inside of
those brackets. So, as to print these all out dynamically in a loop, let me do this: python of [Link],
enter. There's Hermione, Harry, and Ron. And now, if I'm just curious, I just want to poke around, or maybe I
want to do a ranking like who are the top three students in the school or in Gryffindor, well, I can print
multiple things at a time we've seen. Let me print out not just the students at location I, but rather let's print
I first and then the student at location I. So, two things to print, and we know that print can take two

61 / 96
arguments, we've seen that before; they'll be separated by a space. Let me go ahead and rerun this. Now I
see that, okay, Hermione is the top student, but she's in the zeroth place. That's a little weird, like we don't
need to show the human using my program that we started counting at zero. I can clean this up; I can just
add one to the I up here, and now we see sort of a top three list of students: Hermione is number one,
Harry's number two, and of course Ron is number three. So, we can get access to all of those same values
as well or any questions now on these lists?"

3:30:21

"This length, these ranges, or otherwise, my question is 4i in range, can you explain this once more? So, let
me rewind in time. We started off doing this for I in 0, 1, 2, and then we printed out 'meow' three times in
that way. The way that the for Loop works is that it creates for you a variable that I've called I, but I could
call it anything I want. It then assigns I initially to the first thing in the list. It then automatically assigns I to
the next thing in the list, and then it assigns I to the third thing in the list. And each time it does all of the
indented code underneath.

3:31:07

"Realize, though, that this is not going to scale well if I want to do something like a million times. So we
introduced 'range' instead; that has the effect of doing the same thing. It returns to me a range of values, a
list of three things, really. So, the behavior is exactly the same if we now fast forward to this Hogwarts
example. Now, though, what I'm doing is just combining these smaller ideas. I'm still creating a 'for' loop,
I'm still creating a variable called 'I.' I want to do it over a range of values, but how many values? Well, if I
use the 'length' function and pass to the 'length' function the list of values, length's purpose in life is to tell
me how long is this list, and it's three. So, that's almost as though before I had just done something like
this, but I don't want to hard code three; I want to dynamically figure out how many students are at
Hogwarts. So, I'm just composing, composing, composing, or nesting all of these various ideas. Alright, if I
may, let me transition now to hog in Hogwarts, still, to introduce one final type of data before we combine
everything with a few final programs. It turns out in Python there's not just strings, not just ints, not just
floating-point values, not just booleans, not just lists, there are also what are called dictionaries or 'dicts,'
which are a data structure that allows you to associate one value with another, literally a dictionary like in
the human world. If you were to open a dictionary, be it in English or any other human language, what's
inside of a dictionary? Well, it's a bunch of words and definitions. A computer scientist, though, and a
programmer would describe those more generically as keys and values, something associated with
something else. That's all a dictionary is; it allows you to associate something with something else. And
notice, this is already more powerful, more interesting than a list. A list is just a set of multiple values, but a
dictionary is sort of two-dimensional, if you will, just like a human dictionary, a book. It associates
something with something else, like words with their definitions. Now, what does this actually mean in
practice?

3:33:09

"Well, suppose that we wanted to keep track of who is in what house at Hogwarts. Well, I could do it using
lists alone. Let me go back to VS Code here, and let me just temporarily, but in a way that I'm not going to

62 / 96
ultimately, let me create another variable called 'houses,' set it equal to Gryffindor, corresponding to
Hermione's house, Gryffindor, corresponding to Harry's house, and Gryffindor, corresponding to Ron's
house. And let's add Draco in there, so now we have four instead of three students, just so we have a little
variety, and he was in Slytherin. So now we have two lists, and we could just agree amongst ourselves that
whoever is first in the 'students' variable lives in the first value in 'houses.' Whoever is second in students
lives in the second house, there's our third in students lives in the third house. We could do that, but
honestly, that is going to break down quickly when we have a lot of students, when we have a lot of houses.
And what if we want to keep track of more things than that? What if we want to keep track of every
student's house and the Patronus, this image that they conjure up magically? Well, then we need a third list.
Like this is just going to get messy quickly if we're just on the honor system using multiple lists where
everything lines up logically, it doesn't end up well when your code gets more complicated. But I do want to
implement this idea. I want to associate something with something: a student with a house, a student with a
house, a student with a house, and so forth. So how can I go about doing this? Well, let me go back to my
code here, and let me propose that we do this using a Python dictionary, and this is the last of the new
syntax really that we'll see. Here's the new syntax: instead of using square brackets, we're going to use curly
braces for dictionaries as well. We've seen curly braces in the context of f-strings, completely unrelated.
Sometimes you run out of keys on the keyboard, and the authors of a language need to start reusing
symbols in different ways. That's what's about to happen; we're using curly braces in a different way now.

3:35:10

"So let me create a variable called 'students,' and let me go ahead and set it equal to an open curly brace
and a close curly brace. This is an empty dictionary at the moment. And here's how a dictionary works: it
allows you to associate something with something else, and you do that like this: 'Hermione' (quote
unquote) colon, and then the value thereof. What do you want to associate with Hermione? Well,
Gryffindor. What do I want to associate Harry with? Well, I want to associate him with Gryffindor. What do I
want to associate Ron with? Well, I want to associate him with Gryffindor. Well, this is actually not gonna...
this is gonna get very ugly quickly once we add in Draco and Slytherin; my code is going to get too long;
it's going to start wrapping. So this is purely aesthetic; it is perfectly acceptable in Python and other
languages to format your code a little more readily and just add new lines if it makes it more readable. And
one way of doing this might be as follows: I still have my curly brace up here, I still have my curly brace
down here, but notice it's a little more readable now in that I have my keys on the left, my 'somethings,' and
my values on the right, my 'other somethings.' It's just a little easier to skim top to bottom. You could
format it differently as well, but I'm going to go ahead and add in now... Draco, who lives, of course, in
Slytherin. So now I have each of these keys on the left and values on the right, which is really, again, just a
code implementation of this idea, a little chart that you might write up with paper and pencil when
associating something with something else. So how do I now use this code in an interesting way? The
syntax is almost the same. If I want to print out the very first student, Hermione's house, I could do this:
print out the name of the variable, but I need to go inside of the variable; I need to index into it. And what's
neat about dictionaries is that whereas lists have locations that are numeric (0, 1, 2 - Hermione, Harry, Ron,
respectively), dictionaries allow you to use actual words as your indices, so to speak, your indexes to get
inside of them.

3:37:19

63 / 96
"So if you want to print out Hermione's house, the key you care about is quote unquote Hermione, and
what this syntax here will do, notice it's not a number (0 or 1 or 2), it's literally Hermione's name. This is like
going to the chart earlier and saying, 'Alright, give me Hermione' - Hermione is my key, Gryffindor is the
value. That's what we're doing here syntactically; we're looking up Hermione and getting the value thereof.
So, if I go back to my code, that should print out Gryffindor. And if I do this a few times: 'students[quote
unquote Harry]' should give me Harry's house, 'students[Open Bracket] Ron [close bracket]' should give me
Ron's house, and lastly, if I do this with 'students[bracket Draco],' that should give me Draco's house. Now,
it's a little manual still, I bet we can improve this, but let me run Python on '[Link],' and we should see
Gryffindor, Gryffindor, Gryffindor, Slytherin, which is exactly what we'd expect. Now, all we've done, again, is
we've just now moved from having just a simple list of names to, again, sort of two dimensions, associating
like we would on paper and pencil - something with something else, keys with values, respectively. Allow
me, if you will, even though I realize this is getting a little fancy, allow me to escalate things slightly here
and transition from looking at just, for instance, that pattern there, just hardcoding those values there, to
actually printing these out more dynamically. Let me go ahead and use our loop, and this question came up
earlier as well: let me go ahead and say 'for each student in students,' go ahead and print out, for instance,
the students variable at, well, let's just say 'student' first, let's keep it simple. So this is not going to be that
interesting yet, but when I run Python on '[Link]' and hit enter, notice what should I say? Let me take
a question here to see: what am I going to see when I hit enter now? When I'm doing 'for student in
students,' yeah, I think we will only see keys. Perfect, so good intuition.

3:39:19

"It could have gone both ways; it could have been values, the houses, but when you use a for loop in
Python to iterate over a dictionary, by design, it iterates over all of the keys. So we should see, I think,
Hermione, Harry, Ron, and Draco. Let me hit enter now. Enter, and indeed, you're exactly right; we see just
the keys. But that's not really that useful if what I really care about is who lives where. Can I print out both?
Well, I think I can. Let me go ahead and do this: let me print out not just the student's name, the key, but let
me use the key, their name, to index into the dictionary. Right? If I know the word in the dictionary, let me
look up its definition. If I know the student's name, let me look up their house. And the syntax for this, just
like a list, is 'students[bracket]' and just like in the past, we used 'I' when 'I' was a number, we can also, with
a dictionary, use a string. So if the student's name is the key, then this syntax 'students[Open Bracket]
student [close bracket]' will go to Hermione's location and get back her house; we'll go to Harry's location
and get back his house, and so forth. So if I do 'python [Link]' enter now, I see Hermione, Gryffindor;
Harry, Gryffindor; Ron, Gryffindor; Draco, Slytherin. Now, it looks like I've given them all new last names, but
I can clean that up; this is just a print thing. Let's go ahead and change our separator from the default space
to maybe a space comma and just using print features now. Let me run the same program again. Enter, now
I've just got some nice pretty commas in there to make clear that Hermione's last name is not, in fact,
Gryffindor, but that's just a print detail. Any questions then on these dictionaries and what I've just done?
Questions on these dictionaries and this looping over them here. Um, I just can't get my head around the
for student in students. Does, uh, if I'm just correct me if I'm right, does that mean it imports the list of
students and uses the indexes or, in other words, Hermione, Harry, and Ron as the indexes in the actual list
of students? Correct.

3:41:33

"So this is just a feature of Python. When you use a for loop with a dictionary, what happens is this: if this is
the dictionary here with the keys on top and the values on the bottom, you get to choose what the variable
64 / 96
is called. I called my variable 'student' just because it makes sense because I want one student at a time.
And what the for loop does, just like it did with numbers before, the zero, the one, and the two, it allows me
to, for instance, set 'student' equal initially to Hermione's name, and then the next iteration of the loop, the
next cycle, sets 'student' equal to Harry's name, then Ron, then Draco. It just kind of happens automatically
like that; that is what the Python interpreter does for you when it sees a for loop like that. So, it's very
similar in spirit to iterating with a for loop over a list, but rather than iterating over the numeric locations (0,
1, 2), it iterates over the bold-faced keys in this representation here graphically. And allow me to give us
one other example on Hogwarts before we look at one other familiar domain. At the risk of things
escalating a little bit, let me propose that we continue the story with one final Hogwarts example like this.
What if we have more information about each of our students, and this is kind of inevitable, right? If you're
implementing a program that's a database with people or customers or employees or anything else, you
can imagine having a lot of data about anything you're representing in your program. Here, for the sake of
discussion, suppose that every student at Hogwarts, of course, has a name, they have already a house, but
they also have a Patronus. For those unfamiliar, this is the animal or entity that comes out of the end of
their wand when they make a certain magical spell. The point here being is that we want to associate not
just one thing with the student, but multiple things as well: their name, their house, and their Patronus in
this case. Well, what might code like this look like?

3:43:28

"Well, let me go back to '[Link],' and let me start fresh for just a moment, and let me propose that I
enhance this with a bit more data, and this data is going to look as follows: my 'students' variable. Now, I'm
going to propose we think of it as a list. What if we have a list of dictionaries as follows? Indeed, I want to
literally implement this picture here, so notice that my previous picture just represented a single dictionary,
but suppose I wanted to compose a list of dictionaries, that is for students. So, a list of four students, and
suppose that each of those students is itself a dictionary, a collection of key-value pairs, keys and values,
something and something else. Well, here's one other way we can do this in code. Let me go back to VS
Code here, and let me define a variable called 'students' that is equal to a list, and I'm going to
preemptively move my cursor onto separate lines because I know this is going to be long, and I want to fit
all of the elements of this list inside of it. I'm now going to create a dictionary, one dictionary per student.
And how do I create a dictionary? I just use those curly braces, but it's up to me to define what those keys
are. And let me propose that one key, this time, won't be the student's name explicitly; it will literally be the
word 'name,' and they're going to have the name 'Hermione.' This same student is going to have another
key called 'house,' and the value is going to be Gryffindor. And this same student is going to have a third
key called 'Patronus,' and the value of that is going to be, I had to look it up, an otter, according to the
book. Now, I'm going to create a second dictionary inside of this list, and again, a dictionary is like literally
like the human dictionary of words; it's a book that contains keys and values, words and definitions. What
are the three words I'm storing in each of my dictionaries? 'name,' 'house,' and 'Patronus.' What are the
definitions of those words for Hermione? Hermione, Gryffindor, and Otter, respectively. For Harry, the
definitions are going to be different.

3:45:31

"In this new dictionary, let me give myself another pair of curly braces and say this: 'name' (quote unquote)
colon, Harry; a house here is again going to be Gryffindor, and this one, I knew, his Patronus is going to be,
in this case, a stag. All right, next, a third dictionary. The name here will be Ron, and I'm going to go ahead
and do that just like this. Next, I have the house, and he too was Gryffindor. Lastly, I had to look this one up.
65 / 96
Ron's Patronus was a Jack Russell Terrier. Lastly, is Draco in a third, in a fourth dictionary now. So, another
pair of curly braces, the name of the student is, of course, Draco; the house of this student is Slytherin, and
Draco, interestingly enough, at least according to the internet, has no Patronus. It was never revealed in the
books or the movies. So, it turns out this is actually a wonderful teachable moment. There is a special
keyword in Python that is literally 'none,' N-O-N-E, with the first letter capitalized. This represents officially
the absence of a value. So, I could, a little sloppily, do something like 'quote unquote,' but does that mean I
didn't get around to typing it or not? It's a little clear semantically to say literally 'none,' a special keyword in
Python to make clear that I know Draco has no Patronus; it's not just an oversight on my part. Now that I
have this, what do I have in the computer's memory? I have a list. How do I know it's a list? Because I see a
square bracket at the beginning and another square bracket at the end. That's just my visual clue, okay? I
don't know necessarily what else is going on here, but there's a list of something. What is in that list? Well,
here too, the syntax is our clue because this line 2 starts with a curly brace and ends with a curly brace. I just
know that is a dictionary, a collection of key-value pairs. Now, this all fit on my screen perfectly, so I didn't
bother moving all of the key-value pairs onto new lines. It would have made it really tall, so I kept it all
together here this time. But how many keys does this first dictionary have?

3:47:36

Put another way, in Hermione's physical dictionary, how many words are in that dictionary? Three. The
words are "name," "house," and "Patronus." What are the three definitions or values of those words in
Hermione's dictionary? Hermione, Gryffindor, and Otter, respectively. And the same story goes for Harry,
then for Ron, and then for Draco. I have, by design, chosen to give them dictionaries that have all the same
keys, all the same names, but they all have unique values, and that's my design. That's my prerogative as a
programmer. So why is this useful at the end of the day? Now I have access to a whole collection of
interesting data about all of these students, and I can still do a loop. I can say, "for student in students,"
that's going to allow me to iterate over this list of students, and let me go ahead and print out just one
thing at a time. Let me print out the current student's name. So as complicated as the dictionary is, this
should be pretty comfortable. For "student in students" is just going to iterate over every student in the list,
one, two, three, four total. The next line is just going to print out the value of the "name" key. It's like
opening a physical dictionary, looking up the word "name," and giving us Hermione, Harry, Ron, and Draco,
respectively, from each dictionary. So if I run this version of Hogwarts and hit enter, there I get all three of
their names. But what if I want more information than that? I want both their names and their houses. Well,
just add two print arguments: student["House"]. Alright, let's go ahead and run this Python script
"[Link]" and hit enter. So I now see Hermione Gryffindor, Harry Gryffindor, and so forth. Well, we can
aesthetically clean this up a little bit by adding a separator with print, like a comma and a space, just so that
when I run this again, I now see some commas separating these values. But recall that students have not
just a name, not just a house, but also that Patronus. So if we want to print that out too, we now have the
syntax via which to go into that same dictionary for each student and output their Patronus as well as their
house and their name.

3:49:44

So if I run this program one final time, now I see all of the data in this here dictionary. This is a lot to absorb
all at once. I'm sure it's the last of our new data types. On top of lists, we have these dictionaries, but again,
a dictionary at the end of the day is just a collection of values, similar to these values here, that allow you to
associate keys with values. The first version of this program associated literally the students' names with
their houses. But then I realized in my next version, "Wait a minute, what if every student has not just a
66 / 96
name and a house, but a Patronus?" Let's actually standardize the names of our keys to be "name," "house,"
and "Patronus," and then the values of those keys can actually be the data, like Hermione, Gryffindor, otter,
and so forth.

Questions now on these dictionaries and iteration thereof. I just was wondering if the suppose the
dictionary is very huge and if I want to look up for a specific student, how do I know where to look that
student from? Can we sort it out in alphabetical order or numeric order or anything like that?

In short answer, yes. One of the features of Python is that it makes these dictionaries very highly performant
for you, even if they're very large. As they will be in future weeks when we manipulate more data, Python
will find the data you care about quickly for you. In fact, that is a feature of the language, that is, a feature
of a dictionary - to get you the data quickly. And there are functions that you can use; you can sort the data,
you can sift through it, you can do very performant operations. As we eventually allow me then to propose,
as we wrap up these loops, that we solve just a few final problems that will perhaps evoke fond memories
of yesteryear, at least for me, wherein one of my favorite games growing up was this one here on the
original Nintendo. This is a two-dimensional world where the characters move up, down, and right, not so
much to the left, in jumping over pyramids and obstructions like these. And allow me to propose that we
use this just for inspiration, not to do something that's quite as colorful or graphical as this, but just to focus
on, for instance, this barrier in the middle of the world here that Mario or Luigi had to jump...

3:51:48

And allow me to propose that we use this just for inspiration, not to do something that's quite as colorful or
graphical as this, but just to focus on, for instance, this barrier in the middle of the world here that Mario or
Luigi had to jump over. And so, this here seems to be like three bricks stepped on top of one another, and
we won't do things quite graphically, but let's just implement a very simple Python-based version of this
textually using maybe just hashes for bricks because there's a pattern here, one on top of the other, and I
bet we can solve this in any number of ways.

Well, let me switch back over to VS Code here, and let me propose that we create a program called
"[Link]" using code in the terminal window. Then, up here, let me start by implementing that same
picture as simply as I can, printing out just literally the hash and then the hash and then a third final hash.
This is going to be a very textual approximation of it, but I think if I run "python [Link]," I've got a very
simple version of that same column of bricks, so to speak.

But you can imagine that certainly in a game where maybe these columns get higher or lower, it would be
nice to write code that's actually a little more dynamic than that and doesn't just use print, print, which is
literally copy and paste, it would seem. So let me at least adopt some of today's lessons learned and instead
do something like this: "for underscore in range(3):" let's now print out just one of these at a time. But the
fact that I've now used a "three" in "range" means if I want to change it to something bigger or smaller, I
change it in one place, not in three or more places. And this code, too, of course, if I got it right, is just
going to print out the exact same thing. So we're iterating here, but let's see if we can't now integrate our
discussion of writing functions of our own to begin writing something a little more dynamic and solving
more complicated problems.

67 / 96
Ultimately, one of the nice things about functions is that they allow us to not just write code that we can
use and reuse, they allow us to create abstractions, if you will.

3:53:48

An abstraction is a simplification of a potentially more complicated idea, and we've seen this a few times
over the course of the weeks. For instance, we had a function called "hello," which, granted, didn't do all
that much - it just printed "hello." But it allowed me to think about the function as exactly what it does, not
generically printing something, but literally saying "hello." I've been able to get a number using something
similar by defining my own function, like "get_number."

Well, let me go ahead and, for instance, assume for the moment that I've had the forethought to, in my
function "main," use a function called "print_column." That seems as good a name as any to use a function
that prints a column of bricks. Well, how can I go about now implementing this abstraction, this simple idea
"print_column," with actual code? Well, we've seen before with "def," we can do just that. Let me define a
function called "print_column." Let me accept, as its input generically speaking, a parameter called "height."
I could call it "n" or "H," but I'll be a little more explicit now with "heights," just so I remind myself what it's
doing. And now, I think I can just borrow some of that same code from before: "for underscore in
range(height):" Go ahead and print out a single hash. And then, at the end of this whole program, let's just
call "main."

So, I've kind of complicated the code; it doesn't do anything more just yet, but it's setting me up for solving
what I think are going to be more sophisticated problems. If I run "python [Link]," we're back where we
began, but I now have a function, an abstraction, "print_column," that's going to allow me to think about
printing some chunk of the world of Mario at a time, and I can do this in different ways too. Notice that if I
really want, I could do something like this: I could re-implement now "print_column" in different ways,
especially if I'm using "print_column" all over my code or maybe still a colleague of mine, a friend, someone
else on the Internet is using my "print_column" function.

3:55:46

What's also nice about functions you've written is you can change the underlying implementation details of
them, but so long as you don't change the name of the function or its parameters, or what it returns (if
anything), no one else knows the difference. You can change the internal implementation as much as you
want if you want to improve it or make fixes over time.

For instance, another way we could implement "print_column," recall, would be something like this, a bit
clever, with one hash and then a new line and then maybe we could do multiplication of strings and then
end this line with "quote-unquote" again. It's okay if you're not comfortable with this syntax; this was a
more clever approach we saw in the past. But if I run "python [Link]" here, I'll still see a column of three.
But what's important here is that "main" does not need to know that the underlying implementation of
"print_column" has changed.

68 / 96
Well, let's transition to a different dimension, if you will, and rather than print out just these vertical bricks,
let's fast forward in the game to this part of the world here. At some part, Mario encounters these bricks in
the sky that if he jumps up underneath, they become coins, and so he gains points to his score. But let's go
ahead and focus only on those coins, and let me propose that we print out, oh, just these four question
marks here. And let me go back to VS Code here and let me propose that within VS Code here, just like
before, we try to abstract this away.

So let me go ahead and get rid of this version because we're now going horizontal instead of vertical with
our output, and let me just say, "Well, print_row four times." Let me just abstract away the problem at hand.
I don't know yet how I'm going to print those four question marks, but let's call it "print_row" four, and I'll
assume I'll now solve this problem. Let's now go down that rabbit hole of solving the problem. Define a
function called "print_row." It's going to take a "width" instead of a "height" because it's horizontal instead
of vertical. And how can I do this? Well, now we have an opportunity to do string multiplication even more
elegantly.

3:57:47

I can say quote unquote question mark times with, and this is a very pretty pythonic way of printing what
could otherwise be a loop, and that's fine, but this is going to go ahead and print those question marks for
me. Let's do python of [Link], enter, and now I've got four question marks. It's not nearly as pretty as the
more graphical version, but it is at least a building block toward having now a reusable function like print
row.

3:58:11

Am I doing all this, like why are we over-engineering the solution to these problems by having print column
and print row? Well, it's a useful problem-solving technique as soon as your world does not look one-
dimensional like this or with the column version. But what about this later in Super Mario Brothers? Does
Mario have to jump down into this world where there's a lot of these underworld barriers, and this one
here, for instance, looks like a square; it's two-dimensional; there's a height and a width to it, and that is to
say there's a bunch of different ways we could implement this thing. If maybe for discussion, it's like a three
by three grid, a three by three square of sorts.

3:58:49

Well, how can we go about solving this here problem? Let me propose we come back to VS Code, and let
me propose that we think about this in a couple of different ways. I could do this, hmm, like this.

3:59:02

If I know where I'm going, you know, maybe I'm a seasoned programmer; let me go ahead and do this. Let
me print out a square, the width and the height of which is three. That's an abstraction I'm just taking for
granted for a moment that there is already a function called print Square that's going to be with 3 and
height 3 as well.

3:59:20

69 / 96
Someone's got to implement this, and at the moment there's only me at the keyboard, so let's go ahead
and implement that square. Let me go ahead and define a function called print square that takes in a
specific size both for height and for width, and here's where we have an opportunity to use some of those
loops, and we can use those loops in a way we haven't yet.

3:59:41

If I want to print out all of these rows but also all of these columns, I now have to think not just cyclically
like a loop allows, but I need

3:59:48

to think two-dimensionally. And if you're familiar with, like, an old-school typewriter or even a printer
nowadays, it generally prints from top to bottom. So even if you have multiple columns, you print out one
line at a time. And while you're on that line, the printer or the typewriter prints from left to right. That's kind
of the mental model to have with your black and white terminal window. All of the output for every
example thus far starts at the top and goes down to the bottom, from top to bottom, left to right. So we
have to generate our output, our square, in that same way.

4:00:11

Let me propose that we do this. Let me propose that we know we need to iterate this many times, three, or
more generally, size. So let me do this: for I in the range of size, what do I need to do three times? Well, I
want to print out what one, two, three rows of bricks. But within each row of bricks, what do I want to print?
One, two, three bricks, specifically. So if we go back to our diagram here and I stipulate that it's indeed
meant to be a three by three square, three wide and three tall, what do I want to do to print the first row? I
want to print brick, brick, brick, brick, brick. What do I want to print on the second row? Brick, brick, brick.
And the third row? Brick, brick, brick. So I'm doing three things three times; there's a lot of printing that
must happen.

4:01:12

So let me go back to my code here and let me propose now that we think of this outer loop that I've just
started as representing each of our rows. For I in the range of size is going to ensure, no matter what I do
next, that I can print out one, two, three rows or, more generally, size, where size could be three, but it
could be smaller or larger.

4:01:38

What do I want to do on each of the rows? Just like an old-school typewriter or printer, on each row, I want
to print out brick, brick, brick, brick, brick, brick, brick, brick, brick. Well, that sounds like a cycle, some kind
of loop. So maybe I can have inside of one loop another loop.

4:01:58

70 / 96
I don't want to use I again because I don't want to use the same variable and mess up my counting. So I'm
going to, by convention, use J. It's very common to use I and then J, maybe K, but after that, you shouldn't
keep nesting inside of each other. Let me go ahead and say for J in range of size 2 because it's a square,
and then each of these rows, let me print out a single hash but no new line. But after each row, let me print
only a new line.

4:02:24

So there's a lot going on here, especially if you've never touched Python, let alone loops. But notice what
I've done here too, and I'll add some comments for clarity:

For each row in the square,

For each brick in the row,

Print brick.

4:02:50

Here is where comments and, more generally, pseudocode can really help explain to yourself and to others
what your lines of code are doing. On line eight, I'm iterating from I equals zero on up to size (0, 1, 2). On
line 11, I'm doing the exact same thing, but using J (0, 1, 2). But that's good because I represents now each
of my rows, and while I'm on each of those rows inside of this outer loop, I'm going to do brick, brick, brick
(1, 2, 3) for each brick in the row.

4:03:08

But I don't want my cursor to keep moving to the next line while I'm on a row, so I'm just overriding that
line ending. But let me ask a question of the group now: why on line 16 do I have a print here all by itself?
Why do I have a print all by itself? Notice that it's below the inner loop but inside of the outer loop, so to
speak. What is that loop on line 16 doing? Ultimately, every time you finish a line, you have to add a new
line at the end of it, so print() prints a new line. Perfect! I don't want a new line after every brick; I only want
to do that at the end of the row, and that's why my comments now are perhaps enlightening.

4:04:07

Notice that this loop here is just iterating for each brick in the row. Once I'm done with that inner loop, so
to speak, once I'm done with these highlighted lines here, to Evelyn's point, I need to print out one blank
new line.

4:04:25

And we've not done this before, but when you call print() with no arguments, all you get is that automatic
line ending, the backslash n, where the cursor moves to the next line. So if I now go back to my terminal
window and run [Link], I think I should get a three by three square. And it doesn't quite look like a square
on my screen because these hashes are a little taller than they are wide, but it is, in fact, three by three.

71 / 96
4:04:43

But let me propose, as we've always done here, how we might tighten up this code further just for clarity's
sake. Let me get rid of my comments for a moment just so we can see how many lines of code we have
total. And let me propose that we maybe do this: let me propose that, you know what, this inner loop,
especially if you're having trouble wrapping your mind around one loop inside of another loop, you don't
strictly need it.

4:05:08

What if we do this trick again? What if we print out, inside of the outer and only loop, each of those hashes
times the number of times we want them, right? We draw inspiration from an earlier approach, and we run
python now of [Link], same result, but now print_square() is really nice and compact. It has one explicit
loop, and it's still printing out using string multiplication all of the hashes at once on that row. If you like
abstraction and you'd like to wrap your mind more around what the code is doing, well, let's do this. If
you're not quite clear on what's going on, let's propose that you implement a function called print_row(),
passing in size.

4:05:51

Let me propose that this print_row() function simply takes in that width and prints out the individual hash
times that many times. In other words, here's an opportunity for abstraction, whereby, well, what does it
mean to print a row? When you're implementing print_square(), I don't really care what it means to print a
row; I just need to know that someone's taking care of printing the row. You can kind of pass the buck to
another function altogether.

4:06:14

And how does print_row() work? Well, it could use a for loop; it could use this string multiplication trick.

4:06:27

This is a way to take a larger program, and this is probably the most complicated one we've looked at thus
far, and to decompose it into these smaller components that, once assembled, achieve your final idea.
Seeing no questions, that's the end of our look at loops in Python. This ability to do things cyclically, again
and again, and when we combine those with conditionals, this ability to ask and answer questions and
combine them with our functions and variables, we really now have most of the building blocks we need to
solve much larger, much more interesting, much more personal questions. So in the weeks to come, we'll
start to see exactly what could go wrong, though when we do so, but we'll introduce you to all the more
tools by which you can troubleshoot those same problems.

4:07:25

[Music] Thank you.

4:07:33

72 / 96
Alright, this is CS50's Introduction to Programming with Python. My name is David Malan, and this is our
week on exceptions. Exceptions in Python, as well as in other programming languages, refer to problems in
your code. Indeed, when something is exceptional in your program, it actually doesn't mean it's a good
thing; it means something has gone wrong that ideally you will somehow solve.

4:07:46

So, what are some of the things that can go wrong? So I'm going to go ahead and open up VS Code on my
computer here, and in the terminal window, I'm going to go ahead and run `python [Link]`. That's going
to, of course, open up a brand new tab for me, `[Link]`, in which I can write my code. And let me go ahead
and write some very simple code just to say hello to the world. Let's go ahead and say `print("Hello,
world")`, and then let me go ahead and I'm forgetting to close that quote. So, a mistake that you yourself
might have already made or might surely, in the future, make, and it's a little subtle because you might not
necessarily notice that you've just missed that one character.

4:08:05

Well, let me go ahead and somewhat optimistically go down to my terminal window now and run `python
[Link]` and hit enter, and that's the first of my errors.

4:08:44

My gosh, I've only written one line of code, and I seem to have more lines of errors on the screen. But the
salient point is this bottom-most thing here: notice where it says "SyntaxError." SyntaxError is a problem
with the code that you have typed. Your syntax, just like English and other human languages have syntax
associated with them, so does my code, and it's not quite correct; something is awry. I didn't follow the
instructions properly, and it does elaborate for me, "unterminated string literal." Now, that's a bit arcane,
that is a bit of a confusing error message, but "unterminated" would generally mean that I started
something but didn't stop it; I didn't terminate it. A string, of course, is a sequence of text, like we discussed
before, or `str` in Python, and "literal" generally refers to something that you literally typed. It's not a
variable; it's something like `"quote unquote"` or just `"Hello, world"`. So, the fix here, of course, is going to
be to go ahead and terminate that string and actually close the quote. And if I now go back down into my
terminal window and rerun `python [Link]`, now I'm saying "Hello, world."

4:09:40

The catch with syntax errors here is that syntax errors are entirely on you to solve. A syntax error is a
problem that you've got to go back into your code and fix from the get-go. You can't just kind of hope that
it's going to resolve itself or expect that other parts of your code will catch it for you. Syntax errors just
must be fixed.

4:09:59

But there are a lot of other types of errors in Python that might be described as runtime errors that happen
while your code is running, and it's really up to you to write some additional code defensively to detect
when those errors happen because you don't necessarily know, for instance, what input humans are going

73 / 96
to type into your program, and so you better be ready defensively to accommodate things that they type or
even mistype.

4:10:24

For instance, let's go back over here to VS Code, and let me propose that we take a look at a new file
altogether. I'm going to close `[Link]`, and I'm going to write `code [Link]`. So, let's play around with
some numbers in Python, and the first thing I'm going to go ahead here and do with `[Link]` after
opening this new tab is I think I'm going to go ahead and print-type up a relatively simple program that
maybe prompts the user for an integer like `X` and then just prints out what `X` is. So we're going to start
super simple, but again, in starting simple, we'll be able to really see where I've done something wrong.

4:10:49

Well, here we go. I'm going to go ahead and say a variable called `X` is going to get assigned the value of
the return value of `input("What's X? ")`, and I'm going to include a space to move the cursor over a little
bit. And then, ultimately, I'm going to go ahead and... Oh, wait a minute, if I'm wanting to get an integer
from the user, recall that I need to do something proactively; I need to actually convert that input to an
integer using the `int()` function in Python. So now, I'm passing the return value of `input()` as the argument
to `int()`, and that will store in `X` ultimately an integer, not a string that looks like an integer.

4:11:26

Alright, let me go ahead now and just quite simply print out what this is. I'm going to go ahead and print
out `"X is {X}"`, but I don't want to literally say "X is {X}". I want to plug in the value of `X`. So maybe the
easiest way to do that is to surround it with curly braces, and then if I'm using these curly braces and I want
Python to interpolate the value of that variable, that is, substitute what `X` actually is in between those curly
braces, recall that I need to use a format string or an F-string by prefixing this whole thing with an `F`. Now
that I've done that, let's go ahead and see what happens.

4:12:08

I'm going to go ahead in my terminal window and run `python [Link]`. I hit enter, and so far, so good;
all is well. I'm being prompted for `X`. Let me go ahead and type in a number like 50. Alright, that seems to
work; the program seems to be correct. Or is it?

4:12:27

What could go wrong in this program, even though nothing did just go wrong, but if I run it and run it and
run it again during the running of my program, what could still go wrong, especially if I'm not the human
interacting with it, but some other human instead, and he volunteers here for this one, what could go
wrong, and in what way is this program not really correct, even though at first glance it seems so?

4:12:46

But what is an interface we got in a in a integrated IDE?

74 / 96
4:13:00

We can't code in an interpreter, so I'm not calling an integer. I'm still having trouble hearing you, but what I
think I heard is that if what the user types in is not, in fact, an integer, I can't just blindly convert it to an `int`.
If I'm not putting too many words into your mouth, I think what I should perhaps do here is be a little
defensive.

4:13:21

And let me see if I can't simulate exactly the problem that could go wrong here. Let me go ahead and run
again `python [Link]`. Let me try another number, and in fact, when testing your code, generally, it's a
good idea to test corner cases, maybe numbers that aren't quite as plain as 50 or 49 or 51. Let's choose
some numbers that might be a little more interesting, if only mathematically, like zero. Alright, zero seems
to work; my code still prints out that `X` is zero. What might be another corner case to consider? Well, let
me go ahead and try a negative number that 2 is pretty different in spirit from 50. Negative one, okay, that
works too.

4:13:57

Well, let me try it one more time. I've tried positive numbers, negative numbers, zero. Let me try something
like "cat." So literally, "cat," typing in a string that doesn't even look like a number. And yet, let's see now
what happens when I hit enter. Alright, we'll see; now we've got another kind of error. It's not a syntax error
because I didn't make a typographical mistake; I didn't forget some piece of syntax. I actually now have an
error with one of my values, and it's a value I didn't even anticipate; the human, me in this case, typed it in
long after I wrote the code.

4:14:28

So, what does this refer to? A `ValueError`. Well, let's see what the explanation is: "invalid literal for `int()`
with base 10: 'cat'."

4:14:35

Now this too is a bit of a mouthful, and unfortunately, in Python, in a lot of programming languages, the
error messages are written for pretty comfortable programmers. And, of course, when you're learning
programming for the first time, you might not be so comfortable with the programming language, let alone
the error messages. But let's see if we can't glean some insight. "Invalid literal" - well, again, a literal is just
something that's been typed in. It would seem for `int()`. What is `int()` exactly? Well, `int()` is the function
I'm using to convert the user's input to a corresponding integer. "Base 10" - that refers to the decimal
system, which is this - the default that Python's using. And it looks like at the end of the day, what Python
really doesn't like is that I passed "cat" to the `int()` function.

4:15:16

So how do I go about actually fixing this problem? Well, I could just add instructions in my program. Maybe
I could add a line of `print` telling the user more explicitly, "Be sure to type in an integer," or "Please don't

75 / 96
type 'cat'; please don't type strings." Of course, the user might still not oblige; they might not be reading
the instructions, so that too is probably not an effective strategy. What we really want to do is write our
code with error handling in mind. We want to write lines of code that not only accomplish the problems we
care about but that also handle errors that might unexpectedly happen. And in general, when programming
defensively, assume that the users aren't going to be paying attention, or worse, they're malicious; they're
trying to crash your program. So we want to handle as many errors as we can.

4:15:58

Now, how do we go about doing that in Python? Well, it turns out whether you want to catch a `ValueError`
or other types of errors as well (though not syntax errors), Python actually has this keyword called `try`, and
it's sort of aptly named. If you want to try to do something in Python, you can literally use this keyword, and
you can check whether or not something exceptional, something erroneous, has happened. So using both
`try` and this other keyword, `except`, can I go and try to do something except if something goes wrong, I
can do something else instead.

4:16:28

So let's consider how can I go about trying to convert the user's input to an `int`, except if something goes
wrong. Well, let me go back to my code here, and let me propose that I now modify this example as follows.

4:16:49

Let me go ahead and above my first line of code, I literally write `try:` and a colon, telling Python, "Try to do
the following." I'm going to go ahead and indent my existing lines of code here by the same number of
spaces, four in this case. And then I'm going to add one more new line down here that literally says `except
ValueError`, and notice it's important that I've capitalized the `V` and I've capitalized the `E`. These symbols
are case sensitive, and this is now an opportunity after this colon to tell Python what I want to do in
exceptional cases when the number or the input from the user is not, in fact, a number. And I'm going to
say something plain like `print "X is not an integer"`. I'm at least going to tell the user roughly what the
problem actually is. So notice another detail: the indentation is important. Because I have `try` on line one,
and I've indented lines two and three, those are the two lines of code that I'm trying. Except if I see a
`ValueError`, line five, because it's indented, is what is going to get executed in cases of those errors.

4:17:50

Let me go ahead now back to my terminal window and run `python [Link]`. Enter, and let's go ahead and
type in 50 again. Still seems to work, and of course, I'm trying and succeeding. Let me go ahead and try
once more, this time though with the word "cat" or really anything that's not a decimal number, and now
you'll see much more cleanly that "X is not an integer". I'm not seeing some scary error message that I have
a user, and I'm going to have no idea how to handle. Now you, the programmer, have anticipated that
something exceptional can happen, and you've gone about actually handling the error for the user, giving
them an appropriate error message instead.

4:18:25

76 / 96
Let me pause here and see, are there any questions now on what we've just done by introducing `try` and
`except` to handle this `ValueError`? Is `ValueError` the only type of error you can get, or are there other
types of errors as well? We'll see a few of them today, and there's many, many more, honestly, that if you
continue programming in Python, you're going to see a lot of them over the weeks, the months, the years
to come.

4:18:51

"But the technique for handling them is going to be largely the same. Other questions on try-accept or
these exceptions, more generally. Uh, yes, sir. Actually, do use the accept block. You need to know the type
of error, right? Like here, you knew it was a value Adder 40. What if you can't anticipate this particular type
of error? A really good question. So I'm being very good about catching, so to speak, the very error that I
know might happen. I don't know when it might happen because it's going to depend on the user, but I
know what kind of error will happen from the int function.

4:19:24

There is a way in Python where you can say 'except' if anything goes wrong, and you can literally omit
'ValueError' and just catch everything. The problem with that is that it sometimes hides other bugs in your
code because you don't necessarily know what's going wrong. And if you don't necessarily know what's
going wrong, how can you possibly handle it correctly? So, bad practice. And, put another way, it's lazy to
do that, to just say catch everything and I'll deal with it here. So a much better practice would be to figure
out what kind of errors could happen and include mention of them explicitly, as I've done.

4:19:56

Now, with that said, if you read Python's official documentation, as you'll eventually, invariably do, it is not
great about telling you proactively what kinds of errors can be raised in this way. So it's a bit of
contradictory advice; you should do it this way, but it's not always obvious what you should be checking for.
But you get better at it with practice, and sometimes the documentation does spell out what could go
wrong. Let me turn our attention now back to this and point out that even though this is better code, it is
more correct in the sense that I'm not just leaving it to the user to see some really ugly default Python error
message that most people are going to have no idea what to do with. I'm at least handling it more
elegantly, and I'm printing out 'X is not an integer', so it's at least more instructive.

4:20:42

But this isn't necessarily the best way to implement this code. Well, here too, I'm actually still being a little
lazy. So notice that I'm trying to do not one line of code but two lines of code, and this isn't a huge deal
because we're only talking about two lines of code.

4:21:02

"But in the interest of preaching best practices, you should really only be trying to do the one or very few
lines of code that can actually raise an exception, that can actually fail in some way. I am pretty sure that
calling print here is not going to raise a ValueError, whether X is an INT or a string or a float or anything

77 / 96
else. The format string feature of Python is going to handle printing it just fine. So really, what I'm going to
do is this: I'm going to move this line three down to the bottom of my code. I no longer need to indent it.
I'm just going to execute it at the bottom of my file.

L here, unfortunately, by doing this, I've done a good thing by now only trying to do the minimal amount of
work necessary that might raise the exception of ValueError, but I fear I've introduced a new mistake. Well,
let's see what is now incorrect. Let me go ahead and again run Python of [Link], enter. Let me go ahead
and do it correctly with 50, and all seems to be well. But again, let's try those corner cases, the zeros, the
negative numbers, or in this case, the cat. Let me go ahead and type in 'cat' again, enter. Now I have a
NameError, so now it's yet another type of error in my code that I've introduced here. And what does this
NameError mean?

Well, just as a ValueError refers to the value of some variable, the value that someone has typed in is
incorrect, NameError tends to refer to your code, like you're doing something with the name of a variable
that you shouldn't. And why might that be? Well, let me turn our attention back to the code here and
consider what it is complaining about. The NameError is what I see down here, and it's telling me name 'X'
is not defined. And notice if I look further here, it is mentioning line six, so I know the problem is with my
code on line six, and that worked a moment ago, and I'm defining X on line two. But let me ask the group
here, why does X not, in fact, exist on line six? Why is it not defined even though I'm pretty sure I was
intending to define it on line two? Maybe the scope of the variable is between the try block, so good
terminology—scope refers to the portion of code in which a variable exists.

4:23:20

"That too, though, isn't quite right in Python. That would be true in C/C++ and Java where indentation or
curly braces tend to define the scope of a variable. But again, here in general, and this worked a moment
ago, X exists once it's defined on line two because remember I printed out 'X is 50' a little bit ago. Let's try
one more hypothesis here. One more hint: 'Y is X'. Somehow, still not defined. Um, yeah, so is it because it's
a local variable, meaning that like it doesn't define outside of scope? Is it like what people have mentioned?
It's asked it prompts the input in try, right? But outside of it is undefined. So, still good instincts and good
terminology too. There's this notion of local variables, which tend to exist inside of functions, for instance,
global variables, which can tend to exist in entire files. In this case, too, though, that's not quite the case.

What's happening here boils down to the order of operations. Let me come back to the code here and
recall that anytime we've discussed the assignment operator, the single equal sign, that copies a value from
the right to the left. But consider for a moment at what point something is going wrong. Well, the input
function is probably working just fine because we've used that a lot now to get users' input. It always
returns a string or a stir in Python. But what could be going wrong? Well, if I'm passing that string to the int
function as its argument, it's probably the int function that's erring. And indeed, if you think back earlier
when we had the ValueError, it was, in fact, the int function that did not like 'cat' as input. So this is all to say
that this portion of my code, highlighted now to the right of the equal sign, that's the code that's creating a
problem. That's the code that was creating a ValueError. And in this case, we're catching the ValueError, but

78 / 96
because the ValueError is happening on the right of the equal sign, there's no value being copied to the
left. The error is interrupting that whole process. So even though we see 'X = ...' on line two, the portion of
that line to the left of the equal sign isn't getting evaluated ultimately because the ValueError is happening
too soon.

4:25:31

"And so when we finally get down to line six, even though it looked like I was defining on line two and I
would have defined X on line two if all had gone well, we didn't get to the part where the value is copied
from right to left because the ValueError happened first. So this code is just incorrect now. So how do I go
about solving something like this? Well, it turns out that there's another feature of the try and except syntax
that Python supports, which is that it also supports the keyword 'else'. Now, we've seen 'else' before if you
think back to our discussion of conditionals, we saw 'if', we saw 'elif', we saw 'else', which was kind of this
catch-all, what you should do in the event that nothing else is relevant. That's kind of the same intuition
here for the try-except feature of Python.

What you can do is this: you can try to do the following, as I've done, except if this goes wrong, but if
nothing goes wrong, else go ahead and do this. So this is one way I can solve this same problem. Now, no
matter what, now Python is going to try to execute line two. If something goes wrong, it's going to execute
lines three and four to handle that ValueError. However, if you try and this code succeeds, then there is no
exception to handle, so you're then going to execute this line here.

It's a little confusing perhaps in that we're now using 'else' both for conditionals (if, elif, else), and we're also
using 'else' with these try-except blocks, but that's okay, that's part of the language, that's one of the
features. So now if I rerun this code in my terminal window, 'python of [Link]', let's do something
correct like 50. I see that X is 50. So, line one is executed; we're trying to do the following. Line two is
executed because the conversion happened and was successful, and the number 50 gets copied from right
to left. The exception does not happen, so we ignore lines three and four. We jump immediately to line five
and six, which prints out the result.

By contrast, though, let's do this one last time: 'python of [Link]'. Let's type in 'cat' or again any other
word and hit enter. Now we don't see what X is; rather, we see 'X is not an integer', which is what's being
handled in my accept clause.

4:27:48

"All right, let me pause here because that's a lot of new syntax and see here if there are any questions on
'try', 'except', 'else', 'NameError', or 'ValueError'. Can you please repeat 'try', the 'NameError'? What's the
problem with the NameError? Yes, yes, yeah, so let's just rewind a couple of lines here before I fix this
problem by now getting rid of the 'else'.

A moment ago, we had code that looks like this whereby I was getting a NameError:

'python of [Link]' -> (enter) -> typing in 'cat'

79 / 96
And that looked like this, where 'name 'X' is not defined', and the problem was on line six, according to this
output in Python. Well, let's think about this now deductively; let's try a different approach.

On line six, I'm seeing an error that 'name 'X' is not defined.' Okay, Python's already telling me X does not
exist at that point. So how could that possibly be? Well, where should X be defined? Well, presumably, X is
defined on line two up here. So what could go wrong? Well, if the user has inputted something that doesn't
look like a number, like the word 'cat', passing 'cat' the return value of input as the argument to int to
convert the word to an INT makes no sense. You can't convert a 'cat' (c-a-t) to an integer at all. So the int
function is raising a ValueError at that point, and the error is being handled with this code here.

But notice this line six is not indented; it's left-aligned with the rest of my code, which means no matter
what, line six is going to execute. It's going to execute whether I typed in 50 or I typed in 'cat'. But if I typed
in 'cat' again, X never gets a value, so it's not defined here on line six. So when I introduced finally the 'else'
statement that makes sure that these things are mutually exclusive, I only execute the 'else' if I tried and
succeeded up above.

Well, let me propose that we refine this just a little bit further as well and consider how we might improve
this example a little bit more. It's a little unfriendly of me to be rejecting the user's input after they fail to
provide an integer and just quitting the program, really, right? It'd be more user-friendly if I just prompt or
reprompt the user again and again.

4:30:04

"And in the chat, if you could, what's the feature of Python that you can use if you want to do something
again and again and again until such time as the user cooperates and gives you what you're looking for, like
a number? So yeah, loop, loop, loop. So a loop is something that happens again and again and again. And
maybe we can use that same mechanism, a loop, in order to prompt the user for 'X', and if they don't give
us a number, prompt them again, and if they don't prompt them again, and again, and again. We don't
need to just quit out of the program so quickly.

So let me propose this. Let me propose here that I improve this code by deliberately doing this. Let me
induce an infinite loop at the very top of my code with 'while True'. Recall that the 'while' keyword induces a
loop, a cycle that behaves like this, and it asks a question, a Boolean expression that needs to evaluate
either to true or false. Well, if I want this thing to loop forever, at least initially, we'll just say 'while True'
because True is true. So this has the effect of doing something no matter what, forever, unless we break out
of it early.

Now I'm going to go ahead and do this. I'm going to go ahead and move my try-except code, indented
underneath this loop, so that I'm trying to get an 'X'. If I have a ValueError, instead, I print that 'X is not an
integer'. But this time, what do I want to do if the user does try and succeed in giving me a number? Well, I
can do this: I can just break out of my code here. And down here, now I can use that same line of code from
before, an F-string that says 'X is', and then in curly braces, 'X' again.

So what's going on here? I think this code now, because I've added the loop, is going to have the effect of
trying at least once, maybe a second time, maybe a third time, maybe 500 times, until the user finally gives

80 / 96
me what I want, which is an integer. And once they do, once there's no ValueError happening, then I break
out of the loop, and line 9 executes as I would hope.

So let me go ahead and try executing this version: 'python of [Link]' -> (enter) -> What's 'X'? Let me
go ahead and type in the easy thing first, 50. 'X is 50.' What just happened in terms of the control flow of
this program, the flow of my logic? Well, I first found myself on line one, inside of a loop.

4:32:22

"Hopefully, I'll get out of this loop. What did I then do on lines two and three? I tried to get input from the
user and convert it to an INT. Well, I was a nice guy this time, and I typed in 50, which looks like and is a
number, so the int function converted it just fine and stored it from right to left in 'X'. Except, ValueError?
There is no ValueError because if I typed in a number, there's nothing exceptional happening; this is a
boring good execution of my program.

So what happens? I break out of the loop. So again, the 'else' clause is associated with the 'try', not with the
'except', and once I'm out of the loop, of course, I'm just printing out what 'X' is. Well, let's try the other
scenario that might happen: 'python of [Link]' -> (enter) -> What's 'X'? Let's try 'cat' or any other word
-> (enter) -> Ah, this is now a new feature. I'm being informed what I did wrong: 'X is not an integer'. So I'm
getting some useful user feedback, but notice again, I'm prompted, 'What's X?'. Let me try typing in 'dog' -
> 'X is not an integer'. 'What's X?' Let me try 'bird' -> (enter) -> 'X is not an integer'. 'What's X?' And suffice
it to say, this will happen now forever if I'm in an infinite loop until I try and succeed, at which point I break
out.

So let's try again: 'python of [Link]' -> (enter) -> What's 'X'? Let me go ahead and type in '50'. Okay, 'X
is 50'. 'What's X?' Uh, okay, maybe it's '49'. 'X is 49'. Uh, okay, maybe '48'. Unfortunately, I think you're
laughing; you see it. I never break out of the loop, which maybe that's a feature, maybe you want this to be
your program, but I didn't. I'd eventually like this game to stop, so I need to break out in that way.

4:34:43

"But I can do it a little differently, and let me propose that we modify this a little bit. But first, any other
questions on this syntax here? Let me rewind to the prior version. Hi, uh, can I use 'break' or 'except' or
'else', for example, in another 'print'? Can I use prints together with 'break', or something like this?"

4:35:03

"You can use 'break' inside of loops to break out of loops, and you can use it inside of a conditional like an
'if', an 'elif', or an 'else'. You can do it inside of a 'try-except-else' statement too. Anytime you're in a loop
that you want to break out of, you can use this keyword 'break'. I'm using it in the context of exceptions,
but it's not restricted to that. And let me show you too, it doesn't even have to be in the 'else'. If I wanted
to, I could actually do this: I could get rid of my 'else', and I could go back to line three, add another line
that's indented (line four), and break out here."

4:35:40

81 / 96
"Now, why is this logically okay? Well, consider what I'm now trying to do: I'm trying to execute line three
and convert the user's input to an INT, and I'm trying to store the result from right to left in 'X'. If something
goes wrong, the code we've already seen is immediately gonna jump to line five and then six to handle the
exception. But if nothing goes wrong, my code presumably should just keep on executing line by line, so I
could technically logically put the 'break' here and watch what happens when I run this version: 'python of
[Link]' -> (enter) -> 50 -> (enter) -> It worked, I broke out of the loop."

4:36:21

"Which way is better? Honestly, I think it could go either way at this point. This program's so relatively short
that even though I'm trying to do two things now, one of which the 'break' is not going to fail (like, you
either break or you don't; there's no piece of data from the user that's going to influence that), we don't
strictly need to have those two lines of code there. But it's only two lines, so I think it's okay. And if you
recall our discussion in the past, not just of correctness (does the code work as it should) but design, I think
you could argue it either way. If you prefer the readability of this and the fact that you don't have an 'else',
that's fine. If, though, you prefer to minimize just how many lines of code you're trying to execute in case
something goes wrong, the 'else' is a reasonable approach too."

4:37:03

"Well, allow me to propose too now that we refine this further. I think we're at the point where it's pretty
darn correct, but suppose now that I find myself today and tomorrow trying to get numbers from the user
quite a bit. It would be nice, as we've seen, to maybe just invent my own function 'get_int' to get an integer
from the user both today and tomorrow and beyond. And heck, maybe I can even share that function with
other people if they want to write programs that get integers from users. So how might I go about doing
this?"

4:37:27

"Well, let me go ahead and propose that we do this. Let me get rid of the print line but keep most of my
loop here. Let me define a function called 'get_int' that takes no arguments for now, and I'm going to go
ahead and indent all of the code I already wrote underneath 'get_int', so now I have a function called
'get_int' that tries to do the following: try to get an integer from the user. If something goes wrong and
there's a value error, yell at them with 'X is not an integer'. Else, break. But it's not just breaking that I want
to do here. Now that I'm in a function, recall our discussion of return values. If you're inventing your own
function whose purpose in life isn't just to print something on the screen like a side effect, but is to hand
back a value - to hand you back a value like on that same Post-It note from our discussion of functions -
well, you need to return 'X' explicitly. How do I now use this function? Well, as soon as we start making our
own functions, it tends to be convenient to define our own main function as well. That's the main part of
our program. And I'm going to keep this simple. I'm now going to say 'x = get_int', and then on the next
line, I'm going to do that print from before: 'X is' in curly braces 'X', and at the very bottom of my program,
recall I'm going to call 'main', so that no matter what, I'm invoking my main function after everything's been
defined."

4:38:48

82 / 96
"Well, let's see how this works. Let me go ahead and run 'python of [Link]' -> (enter) -> Let's type in
50, and it seems to work as before. Let's go ahead and run it again, typing in 'cat', 'c', 'a', 't' this time. 'X is
not an integer', and I'm being prompted. 'dog', and I'm being prompted. 'bird', and I'm being prompted.

4:39:06

Fine, fine, 50. That's an INT, and so it is printed. So, what's worth noting here? Well, I'm manifesting a couple
of good properties here. One, I've kind of abstracted away this notion of getting an integer, and even
though I just artificially hit enter a whole bunch of times just to hide that function for now (it needs to be
there but we don't need to see it at this point), notice that now this entire program really boils down to just
these three lines of code. Now, why? Because I've abstracted away that whole process of getting an INT
from the user into this new function of my own called get_int.

4:39:12

Can I improve upon this? Well, let me go ahead and undo all of those blank lines and pull this up just so we
can see more on the screen at once. Can I tighten up my implementation of get_int? It is correct, I claim.
This is correct; it's handling errors and returning X. But I don't, strictly speaking, need to write the code as
long. What else could I do? Well, let me propose that if all you're doing on this line 13 is breaking, and then
immediately after that, per the indentation, you're executing "return X" on line 14. Why are you wasting
everyone's time? Once you know you're ready to return the value, you could just "return X."

4:39:25

So, in my "else," I could break out and return a value. So here, too, "return" is used to return values from
functions, "break" is used to break out of loops, but it turns out that "return" is sort of stronger than
"break." It will not only break you out of a loop, but it will also return a value for you, so it's doing two
things at once, if you will.

4:40:33

But can I make this even more compact? If my goal is to just tighten the code up, even though it's already
correct, can anyone think of a further refinement, whether you've programmed in Python before or not?
Can I shorten this implementation further, just a little bit, if only to decrease the probability that I've made a
mistake by having fewer lines and just make it a little easier to read because it's shorter? Any suggestions
for tightening up my implementation of get_int? You can just return the value on the try statement when
you're trying, you take the input X, and then return X. Good, we can just return X a little higher up, and let
me correct folks as we go. It's not a try function; it would be a try statement. Technically, a function typically
has parentheses, and another one, in this case, it's just a statement.

4:41:26

So, but we can do exactly that. I don't technically need the "else" if I really want. I could do this right after
line nine. I could return X here, or recall our discussion of defining variables unnecessarily sometimes. Like,
why define a variable here if you're immediately going to use it here and then never again? So we could
avoid a new line here, and I could avoid even defining X explicitly. I could just say something like this: I

83 / 96
could return int(input("What's X?")). I can do it all at once. Now, which is better? I don't know. I mean, again,
this is where reasonable people might disagree. I'd argue that on the one hand, we're tightening up the
code, we're using fewer lines, it's easier to read, lower probability that I've made a mistake. On the other
hand, it's a little more complicated to understand, perhaps. It's a little less obvious where I'm returning
from, so I think arguments can be made either way. At the end of the day, what's important is that you've
done this consciously. You've made a decision to do it this way or this way, and you can justify it in your
mind, not that your answer is, "It worked, so I left it alone." Like, have a good reason, come up with a good
reason, and that will come with experience and practice.

4:42:32

Well, let me propose to you that we make one other refinement here. Suppose that you're finding your
programs to be a little noisy, and it's a little obnoxious that you keep telling the user, "X is not an integer. X
is not an integer. X is not an integer." What if you want to make things a little gentler and just prompt the
user again with the same words? "What's X? What is X? What's X again and again?" Well, you can do that as
well, and it turns out that if you want to handle an exception in Python, but you want to pass on doing
anything with it, so you want to catch it, but you essentially want to ignore it, you don't want to print
anything, you don't want to quit the program, you just want to silently ignore it, like if you're talking in a
room full of people and it's your turn to talk, and you're just like "pass." They're still calling on you, but
you're not doing or saying anything more. Well, we can add this keyword to our code. Let me go back to
my program here, and instead of printing out again and again, "X is not an integer," I could just do this: I
could pass on handling the error further.

4:43:33

I'm still catching it, so the user is not going to see a scary message even mentioning value error. My code is
catching it, but I'm passing on saying anything about it. I'm going to stay in the loop, I'm going to stay in
the loop and keep prompting and reprompting the user. So now the effect looks a little something like this:
"python of number dot Pi." Let's type in cat, what's X again? Let's type in dog, what's X again? Type in bird.
So it's just a little, maybe more user-friendly, and that you're just reminding the user what you want.

4:44:00

Maybe it's worse, maybe it would be helpful to tell the user why you're prompting them again and again.
It's not obvious, so it could go both ways. But again, it's just another mechanism now for handling these
errors. We use the accept keyword to catch a specific error, but we don't have to handle it more than that.
We can just pass on doing something further. Let me pause here and see if there's any questions now on
try-except else or pass. Okay, yeah, no, I was just kind of curious.

4:44:30

I guess about the idea of when you were indenting with the get-in function, for example, because I'm
noticing you know, obviously going through it with the whole logic and breakdown of the entire uh, the
entire function. You know, while True, do this, but I'm just kind of curious on the library with the
indentations for the code. More, yeah.

84 / 96
4:44:49

So the indentation is deliberate. Logically, some languages don't require as rigorous indentation. You can
use curly braces or other symbology to make clear what is associated with what. In general, anytime you
indent something in Python, on this line, so rather anytime you write a code line in Python that's here, and
the lines below it are somehow indented, that means that those lines are somehow associated with that first
line, and presumably those indented lines should only be executed if the first line told the computer to do
so. So concretely, what does this mean? On line six, here we're defining a function called get_in that takes
no arguments: everything that's indented by at least four spaces Hereafter is part of that function. Why?
That's just the design of the Python language.

4:45:40

Frankly, I think the designers got tired of seeing really ugly code in languages like C and C plus and Java
that don't necessarily enforce indentation to this extent. So now it's baked into the language, and my
chronology might be a little off there, but there have been many languages that are looser than Python
when it comes to indentation. The indentation is meaningful on line seven, too. Notice that because the
"while True" is indented by four spaces, that just means it's part of the "get_in" function. But notice below
the "while True" statement, there's eight, there's twelve, there's eight, there's twelve spaces here (and I'm
just quickly counting the dots), that means that all of the lines I've just highlighted are inside of that while
loop. "While True" means to execute lines 8 through 11 potentially again and again and again.

4:46:24

And now, lastly, on line eight, because we have "try" and indented below, it is line nine that just means that
what you should try is what's on line nine, and similarly, on line 10 below it, we have indented line 11. You
should only "pass" when there is an exception of a ValueError. So the indentation just means what is
associated with what, and once you get comfortable with that, you'll see that it helps. The indentation alone
helps explain the logic of your program, and it has a wonderful side effect that for yourself the next
morning, for your colleagues, your family, your friends, your teachers, your code is much more readable as a
result. It's not one big mess of a blob of text. Other questions now on try-except, else, or pass?

4:47:09

Yeah, thanks. Um, two questions. Question one: Um, once you say "pass," can the caller still learn anything
about this error through a system variable or whatever? And question two, problem set zero referenced
some string methods, including "isnumeric." Is it any different to go via "isnumeric" here? A good question.
So, on the first question, if I'm handling the error in this way, the caller is not going to know anything about
it. That's the point of my handling it so that main or other callers don't know that anything technically went
wrong.

4:47:53

On the second question, "isnumeric" is another function that you can call that can look at a string and
determine, is this, in fact, a number? I could use a mechanism like that. I could use a conditional, if this looks
like a number, then pass it to the int function and go ahead and convert it to an integer. That's totally fine. I

85 / 96
would generally say that the pythonic way of doing things is often for better, for worse, to try things, hope
they work, but if they don't, handle the exception.

4:48:17

So, other languages are more in favor of checking if, if, if, if, L if, else in all of these conditionals. Python
tends to be a little more of the mindset, "eh, try it, but just make sure you're handling the error." So this
would be the pythonic way of doing it. Your way, though, checking with the conditional, "is it a number"
first, is totally reasonable too if you want to go that way. Well, let me propose some final refinements to this
program that really just kind of tighten things up.

4:48:47

One additional step to improve the implementation of this "get_int" function. Let me propose that we not
hard code, so to speak, that is type manually "X" all over the place. Let's make this function "get_int" a little
more reusable. Right now, notice that I'm just kind of using the honor system that, well, main is defining a
variable called "X" and "get_int" is asking for a variable called "X," but it would be nice if the caller, main,
doesn't have to know what the callee is naming its variables, and vice versa. So, caller to call a function
means to use it. The caller is the function that's using it. The callee is just the function being called.

4:49:26

It would be nice if I'm not just hoping that "X" is the same in both places. So, let me propose this: let me
propose that we actually add a parameter to "get_int" like this: "What's X?" That is to say, if main wants to
use the "get_int" function, well then main should probably tell the "get_int" function what prompt to show
the user. Just like the input function recall that comes with Python, it's up to you to pass in a prompt that
the user then sees when the human is asked for input. So, how do I make this work? Here, I can go down to
my definition of "get_int" and I can say, "Alright, get_int" is going to take a parameter now called "prompt."
I could call it anything I want, but "prompt" in English is pretty self-explanatory. It means, what do you want
the message the user will see?

4:50:09

And now, down here, when I actually use input, I don't have to presumptuously say, "What's X?" Because
what if the program the caller wants to ask for y or Z or some other variable? I can just pass to input
whatever prompt the caller has provided. So now I'm making more reusable code.

4:50:27

It still works just the same. I haven't changed the functionality per se, but now it's a little more dynamic
because now "get_int" doesn't have to know or care what variable is being asked for. It just needs to know
what prompt it should show to the user. So if I now run this program down here again, prompt: "Number
dot Pi," enter What's X? 50. It still seems to work. Let's run it again. Let's type in "cat."

4:50:52

86 / 96
It still seems to work. And if I type in "cat," "dog," "bird," or anything else, it will keep prompting me with
that same prompt, making this code, therefore, all the more usable. Now, it turns out, too, you can even
raise exceptions yourself using Python's "raise" keyword, but more on that another time. So, in the coming
days, the coming weeks, the coming months, as you write more code in Python, you'll see that errors are
inevitable.

4:51:16

Sometimes there's syntax errors, which you gotta just fix if you even want to run your program at all. But
there could be name errors, for instance, variables that you meant to define but somehow didn't. Value
errors where maybe the user didn't cooperate and provided you with something that you weren't
expecting, or a whole list of other possible errors or exceptions. But now, hopefully, you know how you can
handle these errors and respond to them in any way you like. This then was our look at exceptions, and
we'll see you. This is CS50's Introduction to Programming with Python. My name is David Malan, and this is
our week on libraries.

4:52:16

So, libraries are generally files of code that other people have written that you can use in your own
programs, or a libraries code that you've written that you can use in your own program, but maybe not just
this program, but another and another as well.

4:52:31

So, Python supports exactly this idea, this ability to share code with others, share code across your own
projects, and it does so by way of what it calls a module. A module in Python is just a library that typically
has one or more functions or other features built into it. Generally, the purpose of a library or a module
specifically is to encourage reusability of code.

4:52:50

If you find yourself using the same types of functions again and again, the same functionality, if you find
yourself copying and pasting from an old project into your new project, odds are there's an opportunity
there to factor out that code that you keep copying and pasting, that you keep reusing, and put it into a
library that you can then load into your programs moving forward, so as to not just copy and paste it and
have all these different copies all over. So what are some of the modules or libraries that Python comes
with? Well, Python comes with a random library, literally, which is to say that when you install the Python
interpreter on your Mac or PC or somewhere in the cloud, not only do you get Python, you get a whole
bunch of modules as well.

4:53:34

Now, these modules provide you with functions that you don't have access to just by default like you do
print and input; print and input and other such functions just work in Python. But sometimes, functions are
tucked away in these modules, so you have to be more deliberate about loading them into the computer's
memory. Somewhere on the computer's hard drive, once you've installed Python, there is also, it turns out,

87 / 96
a file probably called [Link] that someone else wrote, probably long ago, but that you have access to.
And in that [Link] file, there's probably one or more functions that you yourself can use in order to do
things randomly.

4:54:12

That is to say, how could you flip a coin in a program in Python? How could you pick a random number
between 1 and 10 in Python? Well, you need a bit of randomness. And while you could figure out
mathematically how to write functions like that yourself, it's a lot easier to stand on the shoulders of others
who've already solved that problem for you, so you can focus on the problem that you yourself want to
solve.

4:54:36

So, for documentation on most any Python module, you go to the official Python docs and you go to a URL
like this, where the documentation for that specific module lives, and within the documentation, you'll see a
list of the functions or other functionality that some module provides.

4:54:47

But how do you go about loading a module into your own program so that you can use the functions in
that module? Well, we need a new keyword in Python, and namely, it's "import." The "import" keyword in
Python allows you to import the contents of the functions from some module in Python. Well, how might I
go about using this in practice? Well, let me propose that there exists in that random module this function,
among others. So I have copied and pasted from the documentation this summary of a function called
"choice."

4:55:23

Now, the function exists in the "random" module, so to speak, not "a random module," the "random"
module. And so, generally, the documentation describes it fully like this: "[Link]" is how you would
technically call this function, though we'll see alternatives to that.

4:55:42

In parentheses, there is a parameter called "seq" for sequence, and sequence generally means a list or
something that is list-like. If you have a list of numbers or strings or anything else, and the documentation
elaborates, well, how can I go about using this function to solve perhaps a familiar problem? Well, let me go
ahead and open up VS Code here, and let me propose that we implement a program that simulates flipping
a coin, a coin that, in the US, heads heads or tails, the idea of which is to pick a decision with 50-50
probability.

4:56:12

50 probability of heads, 50 probability of tails, or you can use some other mechanism like that. Well, let me
go ahead and open a program with VS Code called "[Link]" because I want to start generating a

88 / 96
whole bunch of random information, the first of which is just going to be a coin toss. Now, how do I go
about using that function? Well, I first have to import the "random" library, so literally the first or among the
first lines of my file should be "import random," and that just gives me access to all of the functions in that
specific module. Now, suppose I want to flip a coin.

4:56:44

Well, I can do "[Link]," per the documentation a moment ago, and that again takes a sequence.
What's a sequence? It's a list or something that's list-like, and we know about lists. We've used lists to
iterate over numbers. We've used lists to iterate over students at Hogwarts. Let's go ahead now, and let's
iterate over just a list of two sides of a coin: "heads" (quote unquote) or "tails."

4:57:06

Now, I could call these anything I want. These are my strings. I just want to simulate tossing a coin, so I'm
just going to say, in all lowercase, "heads" and "tails." But notice the syntax. I have "heads" and "tails" in
double quotes. That's because they're strings. I could also use single quotes so long as I'm consistent.
There's a comma between them, which means the list has two elements. There are square brackets to the
right and the left, which indicates that this is indeed a list.

4:57:29

That's the syntax, recall, for defining a list in Python. And then, lastly, there's something more familiar:
there's the parentheses outside of those square brackets, but those are just the parentheses that belong to
the "choice" function and specify where its parameter gets passed in. But again, unlike past functions, I have
to specify what module this function is in, at least for now, and so I do "[Link]" to call the specific
function.

4:57:55

All right, well, it's one thing to flip a coin, picking between those with 50 probability, and that's what
"[Link]" does. It takes in a list and returns one of those values randomly with equal probability
because I've passed in two items. I've got a 50-50 chance. If I passed in three items, it'd be a 33% chance for
each of those items, and so forth. Python does the math for you, but I want to store the value of this in a
variable, so let's define a variable called "coin" equals whatever the return value is. So this is indeed like
flipping a coin.

4:58:25

I'm going to store in a variable called "coin" whatever that value is, "heads" or "tails." And now, just so I can
see what's going on, let's go ahead and print out the value of that string "coin."

4:58:37

All right, let me go ahead now and run this program in my terminal window: python [Link]. Enter, and
it looks like the first coin toss was heads. Let's go ahead and run it again, and it looks like it was heads

89 / 96
again. Maybe you want to chime into the chat here. If I run it a third time, what's it going to be this time? If
you want to type your thoughts in the chat, you might think there's a bug here, but this is probability in
action. If I go ahead and hit enter a third time, there it's actually now tails. And again, tails. And again, tails.
And again, tails. And again, tails. And again, heads.

4:59:09

Now, if we did this an infinite number of times, it would indeed work out to be 50-50. If we only do it a few
times, it might not work out as cleanly, but that's how probabilities indeed work. All right, so I've got that
now working. Could I have implemented this in a different way? Well, let me show you an alternative to
actually using the "import" keyword alone, and let me introduce the keyword "from" in Python. So "from" is
a keyword in Python that you can use when importing functions from a module, but it allows you to be a
little more specific than "import" alone. So if I go back to my code here, it's worth noting that what
technically I'm doing here by importing "random" is I'm technically importing everything that's in that
module.

4:59:53

So not just the function called "[Link]," but a few other functions as well ("help," etc.). Instead of
using this line of code at the top of my file: "import random," which will technically give me access to all of
the contents there, a downside of that is that I have to type in "[Link]," "[Link],"
"[Link]" because all of the functions I'm calling have to be associated with the scope of that module.
Well, suppose that I just want to call the function as its name, "choice." I can do that as well.

5:00:18

Let me replace this first line here with "from random import choice," and what this does effectively is it
loads the function's name, "choice," into my current namespace, into the scope of the file I'm working in.
What that means is that I now no longer have to specify which "choice" function I mean. I can just say
"choice," and so it loads it into the local namespace, that is, into my local vocabulary.

5:00:42

So I can just now say "choice." This might be advantageous in what cases do you think?

5:00:56 When might you want to import the name of the function explicitly like this, this as opposed to just
saying [Link] throughout your code when calling a function?

5:01:01 Any instincts here for this alternative import using from?

5:01:07 Um, hello, I'm Muhammad from Egypt. Maybe if we have a variable that its name is basically like
choice, if I have a variable called the choice, so I need to differentiate which trays I choose. So, I'm gonna
choose [Link].

Yeah, really good instincts by using the first approach by just importing random. You're making sure that
all of its contents are associated with are scoped to the random module so that you can have your own

90 / 96
choice function, you can have your own choice variable, you can use the same names as all of the functions
or variables that are stored inside of that file without them colliding, so to speak. And this is a good thing.
In older languages, it was the case that if you imported someone's library, you better hope that you're not
using the same functions or variables as they are because you might, in fact, have some kind of conflict.
Python and certain other languages allow you to scope the names of those functions and variables to the
file or the module that they come from, so that's a good thing.

But honestly, this is such a short program, or equivalently, maybe I'm using the choice function in so many
places, calling [Link], [Link], [Link], it's just making my code longer and longer
and longer marginally, so but it's just getting ugly and annoying. I can simply import choice, and now
tighten up my code a little bit.

So, as with so many decisions in the past, there's not necessarily one right approach or another, it depends,
but I think for those very reasons, sometimes it's better to do what we did the first time, which is only
import the module so as to retain the scope they're in.

Well, let me propose that we transition to another function that comes with Python's random module, and
that's this here from the documentation: randint. It's a bit hard to say, but it implies, get back a random int,
and if you read the documentation, it's a random int that's between A and B, inclusive. So, if you were to
pass in one for A and ten for B, you would get back a number between 1 and 10, inclusive, including the
one and including the 10 potentially each with a ten percent probability.

5:03:07 So how might I go about using a program like this? Well, let me come back to my [Link] file,
and why don't we go ahead and try generating a random number between one and ten? You might do this
frequently in the real world when you just want someone to pick a random number. You tell them as much
in the human response. Let's get the computer to do the same. Here, let me go ahead and delete my two
lines of code at the bottom, but keep my import random, and let's go ahead and define a variable this
time called number. Set it equal to the return value of [Link], and now pass in a value of 1 for A
and a value of 10 for B. Now, let's go ahead and print the number.

I'm going to go ahead in my terminal window and run python [Link] and hit enter. Four. Run python
[Link] and hit enter. Eight. Again, nine. Again, seven. Again, ten. Again, two. Again, and we can do this
all day long, and if we add all of those up, they should end up being with ten percent probability each.

Now, how might you use this information? Well, maybe we're playing a guessing game, or maybe we're
trying to randomize the behavior of some character in the game. You can imagine using very simple
building blocks like this, just kind of spicing up your program by getting it to do things a little less
predictably because you're choosing these values seemingly randomly, and you're deferring to Python to
actually do the generation of these numbers using its algorithms and its own math.

Well, what more could we do here? Let me propose that we introduce another function that comes from
this random library, yet another that you yourself don't have to implement: shuffle. If you read the
documentation for shuffle in the same random module, you'll see that it takes in a list, for instance, of
values and just shuffles them up, it randomizes them like a deck of cards. Here, you might shuffle them so
as to put them into a seemingly random order.

91 / 96
Well, how do I use this based on this function's name? Well, let me propose that we go back to VS Code
here, and let me go ahead and, this time, do the following:

5:05:03 Because I need to shuffle something like a deck of cards, let me go ahead and not just import
random, but let me give myself a variable called cards that's going to be of type list. And just so I have
something to shuffle, I don't need all 52 cards in a typical deck, I'm just going to shuffle three cards: a jack,
a queen, and a king. I could call those strings anything I want, but I just wanted a list of some values so as
to shuffle them up, that is, randomize the order they're in.

Well, how does this now work? If you read the documentation for [Link], you'll see that it shuffles
the argument in place. That is, unlike many of the functions we've seen, it doesn't return a value that
contains the shuffled cards. In this case, it actually shuffles the list it's given itself. So what this means for my
code is that I need to do something like this: [Link](cards), and then on a final line here, how
might I go about printing the cards? Well, I could do this and say print(cards), but if I do that, I'm actually
going to see Python syntax for lists, and it's just going to format in its own way using commas and the like. I
want to print these cards out one at a time just because I think it'll look a little better. So we can use some
of our syntax from loops and say something like this: for card in cards, go ahead and print out the current
card.

So, what's now happening here? On line three, I'm defining a list of three cards in this order: Jack, Queen,
King. I'm then shuffling those same cards on line four, and then on line five, I'm using a for loop for each of
the cards in that list and printing them out one at a time. And because I'm using print one line at a time,
let's see the results down here in my terminal window.

I'm going to run python [Link] and hit enter. Queen, King, Jack. Seemingly, shot because that's not
the order I defined earlier. Let's do it again. Queen, King, Jack. Okay, that happens to be the same, but let's
see. This could just be bad chance. There we go. Jack, Queen, King. Doesn't look like it's shuffled, but at
least we're getting back different orderings now. Again, Jack, Queen, King. Hmm, not so good. Jack, Queen,
King. Not so good. This is someone you probably want to play against with cards. Queen, Jack, King. There
we go.

5:07:14 But of course, we only have three cards here, so there are not that many permutations we might
see. And if we do this over time, we will see all of them. But if we had, of course, 13 or 52 cards, we'd see a
lot more permutations instead. So we have now these three ways to generate random information: one is a
simple coin toss if you want to start some kind of athletic event, one to pick a number between one and ten
if you want to decide something based on that, and now using shuffle, we can even take in a list of things
and shuffle them about so that we get some kind of random behavior.

Let me pause here and see if there are any questions yet on random or modules or any of these three
functions. Yeah, uh, can we increase or decrease the probability? Of course, if you want to, for example,
there is a 33 percent chance of probability, so is there any way to increase or decrease the probability? Can
you set these probabilities not using these same functions? Uh, can you set the probabilities?

You can absolutely implement some of your own functions or use more sophisticated functions that do
exist in this library and others to exercise more control. These are meant to be very user-friendly and simple

92 / 96
functions, certainly the ones we looked at, that give you equal probability for all of those. But absolutely,
you could skew things. Though hopefully, if you're implementing a gambling game or the like, you're not
actually making some cards more probable than others.

Allow me to turn back now to our implementation here of this randomness and consider how we might
leverage other types of functionality that aren't necessarily in this specific library here. Well, it turns out that
Python also comes with a statistics library, and this contains all sorts of functions for doing things more
statistical in nature, namely calculating means or medians or modes or other aspects of a data set that you
might want to analyze.

So, how might we use the statistics module in Python? Well, we might first just take a look at its
documentation, like any other module in Python, and we'll see within that library that there's a whole bunch
of functions.

5:09:11 And one of those functions is one that's quite simple: it's average, a function that allows you to
calculate the average of some numbers that you've passed in. Let me go ahead and open up a new file in
my terminal window, called [Link], and at the top of this file, I'm going to import a different library
this time, namely the statistics module in Python. And now, I'm going to go ahead and call a function that I
know comes in that module, namely mean, for the average of some values. I'm going to call
[Link], and I'm going to pass into this function, mean, a list of some values.

Let's suppose that I'm quickly trying to calculate what my current grade average is in school, and I did really
well on my first test, and I got a hundred percent, and on my second, I did well but not as well, and I got a
90. Ironically, I'm not very good with math, so I'd like to figure out what my average now is between those
two tests. Let me go ahead now and in this list, type in the number 100, comma, 90, thereby passing in a list
of two values. These are the numbers 100 and 90 inside the parentheses because, of course, this is now the
argument I'm passing to the function called mean, and this function mean is in the module called
statistics.

Well, it's not that interesting to just calculate the mean if I don't actually see what it is. So let me
additionally pass the return value of that mean function to the print function as usual. Let me now in my
terminal window in VS Code, type in python [Link] and hit enter. And voila, as you might expect, my
average is 95 percent.

So, the difference here is that I'm just using a different module that still comes with Python, but I need to
import it instead of, for instance, the random module. And this time, I know from the documentation that
there exists a function called mean.

Well, it turns out there's even more functionality that comes with Python and that comes with other
modules in Python. And there's this feature generally known as command-line arguments.

5:11:04 This is a feature not just of Python, but of languages more generally that allow you to provide input
not when prompted inside of a program, as happens whenever we call the Python function input, but
rather there's this feature, command-line arguments of programs, that allows you to provide arguments,

93 / 96
that is, input to the program, just when you're executing it at the command line. So, up until now, for
instance, recall that we've generally run python [Link], for instance, python [Link], and I've
never once really executed any words or phrases after the name of the file. But I could, in fact, when you're
running programs in a command-line environment like we are, you can provide any number of words or
numbers or phrases after the command that you're typing, and all of those will somehow be passed in as
inputs to the program itself. You don't have to prompt the user for one thing at a time by manually calling
that input function.

So, what does this mean in real terms? Well, let me go ahead back into VS Code here, and let me propose
that we consider how we might leverage a certain module. I'm going to go ahead and create a file called
[Link], and I'd like to use a new module this time that's going to give me access to values that have been
typed at that command line. But what's this module going to be? Well, this one's going to be called sys,
and sys, short for "system," contains a whole lot of functionality that's specific to the system itself and the
commands that you and I are typing. The documentation for this module is at this URL here, and it lists all
of the various functions and variables and the like that come with that module. But we're going to focus on
something a little more specific, namely this thing here.

It turns out in the sys module in Python, there is a variable that just magically exists for you, called argv. It
stands for "argument vector," which is a fancy way of describing the list of all of the words that the human
typed in at their prompt before they hit enter. All of those are seemingly magically provided to you via
Python in a variable called [Link].

5:13:13 This variable is a list, which means that the first element is going to be the first word that you type,
the second element is going to be the second word that you typed in, and so forth. And by way of this list,
then, you can figure out what words did the human actually type at the prompt and maybe use that to
influence the behavior of your own program.

So, what does this mean now in real terms? Well, in this new file called [Link], let me go ahead and
import sys. The sys module is going to give me access to [Link]. But how might I want to use it? Well,
let's do this: Instead of writing a "hello world" program that all of these times has just looked for the return
value of input to figure out what the user wants me to print, let's go ahead and just expect the user to tell
us when they run the Python program itself what their name is. And suppose this time I'd like to generate a
whole bunch of name tags, initially just one.

In the US here, it's very common to wear a sticker on your lapel that says "hello my name is David," so I
want to print out some text that resembles that. The idea being, maybe I could enhance this program
someday to even send that text straight to the printer and dynamically generate those name tags.

Well, let me go ahead now and do this. Let me go ahead and print out, as always, "hello," but I'll say a little
something more this time to make things more interesting: "hello my name is," and then after that, I
normally have been in the habit of calling input, storing the return value in a variable, and passing in the
name of that variable here. But I'm going to instead jump right to [Link][1], and that's it. I'm going to
have a program here that says "hello my name is" followed by whatever is in [Link][1]. And notice,
[Link] again is a list, and recall from our discussion of loops and in turn lists, we use this square bracket
notation to get at the various elements inside of a list.

94 / 96
Alright, let me go down now into my terminal window and run python [Link], but this time, rather than
just hit enter and wait for the program to prompt me for my name, let me proactively just tell this program
what my name is at the so-called command line.

5:15:15 Here we go, "David," separated with a space from the name of the file so that now when I execute
python [Link] David, I see on the screen, voila, "hello my name is David." So based on this
demonstration alone, I think we can infer exactly what's going on in [Link], even though it sounds
certainly at first glance, rather complicated. Let's look up at [Link][1], I'm going to bracket one here. So
clearly, [Link][1] is storing "d-a-v-i-d," but it's one in the past. When we looked at loops, recall that we
said that they were zero-indexed, that is, the first element is zero, the next element is one, this next element
is two, and so forth. And yet here I am treating it as though my name is at the start of the list, one.

Well, let me ask this question, what is [Link][0] probably? The very first element actually in that list. Oh
yeah, I think it's like in C, the name of the program. Indeed, it's indeed like in C and other languages, the
name of the program. If we consider what I typed, I certainly typed "python" because that's the name of my
interpreter, and we don't really need to know that because we're using Python itself. But after that, I did
type two things. I typed "[Link]" as I've done so many times anytime I want Python to interpret a
program I've written. And it turns out by convention, what Python does is it stores in [Link] the name of
the file that you're executing or interpreting, followed by any number of other words that you type. So all
this time, we could have been accessing the name of the program, which frankly isn't all that interesting,
but we can also now access words that are typed after that prompt as well.

But of course, if I don't type anything in, what might happen here? This might be naive of me to assume
that there's always going to be something at location one in [Link]. Let me go ahead and try this: python
[Link], and no, I'm not giving you my name because at this point, I might not even know that you want
my name to be typed. So let me hit enter now, and oh, we see now an error, a so-called exception in
Python. This one's a new one. This one's an index error that elaborates list...

5:17:34 This one's an index error that elaborates "list index out of range." And turns out, this is actually one
of the most common mistakes in programming, whether using a list in Python or arrays or vectors in other
languages, is to try to access some element that does not exist. You try to go too far to the left or you try to
go too far to the right in this object that is just a list of some values. So of course, the mistake here is that
I'm assuming there's going to be something at location one when really it's location zero that's the only one
that has a value. But fixing this is not going to amount to doing bracket zero because now if I go ahead and
rerun this program with no other words after [Link], it says, "hello my name is [Link]," which is fine if
we're making a name tag for the program, but that's not, of course, what my goal here is instead.

So if the fix is not just to change the one to a zero, how else might I handle this error? How else might I
handle this error, this index error that happens if the user just doesn't remember to or doesn't know to type
their actual name at the prompt? We could always put an exception into the program saying if there is
nothing at location one, we just come out to say, "Okay, we haven't got a parameter or something," but if
there is, you continue along with the program. Perfect, so if I might simplify, we can try to execute this line
of code, except if there's an error, we'll deal with it in some other way. Now, ideally, and once I'm a strong
enough programmer, I would have anticipated this and written the following code from the get-go. But
when you're learning, it's certainly reasonable to see an error, "Oh, I didn't realize I should detect that," and
then go back and improve your code. But of course, if you read the documentation and you ingrain some of
95 / 96
the lessons learned from the past, you'll get into the habit of trying and checking for some of these
exceptions yourself.

So, let me solve this in one possible way as you proposed here. Let's try to handle this exception as follows:
Let me go ahead now and instead of just blindly calling this print line, let me try to print out "hello my
name is such and such," except if there is an issue, specifically an index error, then...

96 / 96

You might also like