Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranî)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
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 Meen and it's
designed for students with or without
prior programming experience who'd like
to Learn Python
[Music]
[Music]
hello world my name is David Meen 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 Arts of programming this
course is specifically focused on
programming in Python itself at the
beginning of the course will'll be focus
on a topic in programming known as
functions and variables mechanisms via
which you can write code that solve
smaller problems but you can compose
those smaller Solutions into solutions
to larger problems still 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 we 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 the same thereafter we'll
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 we'll look thereafter at
something called Unit tests and 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 we'll then take a look at
something called file Io Io for input
and output the ability to not just store
information inside of a computer's
memory but rather save it persistently
to diss so to speak to files and folders
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 type something in as
you expect you can use regular
Expressions to extract data perhaps from
some data set you're trying to analyze
we'll then take a look ultimately at
objectoriented programming a paradigm a
way of writing code whereby you can
represent in code real world entities
and 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 and then at the very
end of the course will we equip you with
all the more tools for your toolkit an
additional uh 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 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 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 each
week via the course's lectures will we
introduce you to any number of Concepts
that will 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
solve to 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
this then is cs50 and this is cs50's
Introduction to programming with python
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men 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 let me go ahead here and
open up my computer and on it a program
called Visual Studio code or VSS 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 is a 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 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
hello.py as we'll soon see any program
that you write in Python generally has a
file name that ends inp to indicate to
the computer that it's indeed a program
written in Python now you'll see here at
the top of my screen I have a blinking
cursor a line one which is where the
very first line of my code is going to
and then just a tab that reminds me of
the name of this file hello.py and
without even knowing much python I'm
going to write my very first program
here as follows print open parenthesis
quote hello comma World close quote and
close parenthesis and you'll see that at
my keyboard some of my thoughts were
finished for me I only had to type one
parenthesis and the other one
automatically appeared and that's just a
feature that we'll see of tools like
this tool here now even if you've never
programmed before odds already you can
guess infer what this simple program is
going to do and it's only one line print
open parenthesis quote Hello World close
quote close parenthesis indeed when I
run this program ultimately it's just
going to say hello to the world and in
fact this is a very famous perhaps the
most canonical program that you can
write as your very first program in
Python or any other language and so
that's what I've done here but on my Mac
my PC even my phone I'm generally in the
habit like you of running programs by
double clicking an icon or just tapping
on the screen but I see no such icons
here and in fact that's because my
interface to at least my current Mac or
PC or some server in the cloud is again
only a CLI command line interface which
even though it might feel like it's a
step back from the menus and buttons and
icons that you and I take for granted
every day you'll find we think that it's
ultimately a much more powerful
interface and Incredibly popular to use
among programmers in the real world so
to run this program I'm going to have to
use a command and I'm going to move my
cursor back down to the bottom of the
screen here where previously I already
ran one command the command code which
has the effect of opening vs code in my
computer and then I passed in the name
of the file that I wanted to code up now
I have a chance to type a second command
and you'll see I see a second dollar
sign now the dollar sign here doesn't
indicate any kind of currency or money
it just is the symbol that's generally
used to indicate your prompt where the
command line interface wants you to put
those commands now the command I can run
here is going to be this I'm going to
run python of
hello.py now why is that well it turns
out that when I actually write code in a
language like python it's of course
stored in that file hello.py but I need
to interpret the code top to bottom left
to right so that the computer knows what
to do indeed at the end of the day even
if you don't really know much about
computers you've probably heard that
computers only understand zeros and one
the so-called binary system well if
that's the case then something that says
print and parenthe is and quote unquote
hello world is not surely zeros and ones
we have to somehow translate it into the
zeros and ones that the computer
understands now fortunately so long as
you've installed such a program in
advance there's a program as well as a
language called python so python is not
only a language in which we're going to
write code it's also a program Otherwise
Known As an interpreter that you install
for free on your own Mac or PC or some
server in the cloud and you can then run
that program that interpreter passing to
it as input the name of your file like
mine here hello.py and then that program
that interpreter will handle the process
of reading it top to bottom left to
right and translating it effectively
into those zeros and ones that the
computer can understand so let's do just
that let me go back to vs code here I
already typed out python of hello.py but
I didn't get hit enter and that's what's
now going to kick off this command and
hopefully if I didn't mess any of this
up I should see my very first program's
output to the screen and voila hello
world so if you two have typed exactly
that same code and have executed exactly
that same command you will have written
your very first program in this case in
Python well now let's take a step back
and consider what is it that we actually
just did and what is it we're looking
here on the screen well first and
foremost in most any programming
language you tend to have access to what
are called functions a function is like
an action or a verb that lets you do
something in the program and generally
speaking any language comes with some
predetermined set of functions some very
basic actions or verbs that the computer
will already know how to do for you that
the language really will know how to do
for you and you the programmer the human
can use those functions at will to get
the computer to do those things now the
program in question here hello.py is
using one function and you can perhaps
guess what it is that function is of
course going to be this function print
and that print function of course
doesn't print some pre-ordained string
of text that is to say it prints
whatever it is you want it to print and
here too do we have another piece of
terminology in the world of programming
namely arguments an argument is an input
to a function that somehow influences
Its Behavior the people who invented
python of course didn't necessarily know
what it is you and I are going to want
to print to the screen so they designed
this print function using these
parentheses with the ability to take as
input some string of text be it in
English or any other human language that
is what you want this function
ultimately to print onto the screen and
what is it that the program's ultimately
doing on the screen well it's printing
of course it's showing us hello world on
the screen and that's generally in
programming known as a side effect it
can be visual it can be audio in this
case it's something that appears on the
screen and functions therefore can
indeed have these side effects one of
the things they can do as this verb or
action is to display on the screen as a
side effect something like those World
words that we wanted hello world
so that's my first program and you know
I'm feeling pretty good everything
worked as planned I didn't make any
mistakes but honestly when you're
learning how to program and even once
you've learned how to program years
later you're going to make mistakes and
those mistakes of course are refer to a
term you might already know which is
that of a bug a bug is a mistake in a
program and they can take so many forms
and take comfort perhaps in knowing that
over the coming weeks you're going to
make so many mistakes you're going to
have so many bugs in your code just like
I did and just as I still do and those
bugs themselves are just mistakes that
are problems for you to solve and over
the weeks to come we're going to give
you a lot of tools both mental and
Technical via which you can solve those
problems but just don't get discouraged
if when writing your program for the
first time it doesn't even work that
first time it will with time with
practice and with experience so let me
deliberately now make a mistake that
there was a nonzero chance I might have
done accidentally already but I got
lucky let me go ahead and just suppose I
forgot to include something like the
closing parenthesis at the end of this
line of code you know the code is almost
correct it's like 99% of the way there
but now that I've pointed it out it's
pretty obvious that it's missing that
closed parenthesis but even little
seemingly Minor Details like that that
you and I as humans wouldn't really care
about and if you're sending an email or
a text message oh whatever it's just a
typo it's not that big a deal it is
going to be a big deal to the computer a
computer is going to take you literally
and if you don't finish your thought in
the the way the language expects it's
not going to necessarily run at all so
let's do this I'm going to go ahead here
and clear my screen down at the bottom
just so I can start fresh and I'm going
to go ahead and run this version of my
program after having made that change by
deleting the parenthesis I'm going to go
ahead and type python again of
hello.py and this time when I hit enter
I'm hoping I'm going to see hello world
but here we have an error on the screen
a so-called syntax error which refers to
my having made a mistake at my keyboard
and it this one fortunately is pretty
straightforward it indeed says that this
open parenthesis was never closed and so
that's probably pretty intuitive now
what I need to do I need of course to
close it unfortunately sometimes the
error messages we'll see in the coming
weeks are not going to be nearly that
userfriendly but there too again with
experience with practice will you get
better at debugging such programs let me
now make sure that I indeed fixed it
correctly let me go ahead run now
hello.py 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 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 mention 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 and so VSS code is an example of
just a more general purpose text editor
its purpose in life is to 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 too because you can also use vs
code nowadays uh for free in the cloud
how about one other question here on
programming with python or hello world
or syntax more generally I was trying to
ask
if is not possible to run the code
without using the terminal window I
think I heard is it not if it's possible
to run the program without the terminal
window are you 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 guey GUI
this is just one mechanism and perhaps I
think the the best one with which to
start writing code 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 hello.py and I'm going to add another
line of code at the very top that simply
says for instance uh what's your name
quote unquote 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 a
function input open pen close pen 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 promp the user for
input so I can actually simplify this
code before we even use it I'm going to
go ahead here and take that same string
from print put it as an argument to the
input function and get rid of the print
alt together 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 in my terminal
window I'm going to run python of
hello.py 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 all
right well I could fix this right I
could go up to line two and I could
change world to David and then back in
my terminal window here I can do python
of hello.py enter what's your name David
enter and there we go all right now I'm
up and running now my program is working
as intended of course this isn't really
working as intend Ed here 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 I'll see of course hello
Carter well obviously not because I've
hardcoded 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 is 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 a 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
and odds are most everyone's familiar
with variables from math class way back
when X and Y and Z and the like 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
variable 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 i
could just say this x equals 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
though 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
so in Python and 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 in a variable no
matter what I call it I can store that
input in that variable so is to reuse it
later so now sitting in the computer's
memory somewhere is a container
containing David quote unquote or Carter
quote unquote or whatever the human has
typed in but here it's easy to make a
mistake suppose I decide to try to print
that name and so I I kind of on a hunch
type in this hello comma name just kind
of plugging in the name of the variable
well let me go ahead here and run python
of
hello.py and hit enter that's going to
prompt me for my name and let me type in
my name daid 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 G to say
and yep what we're seeing in the chat is
well it's probably going to say
literally hello comma 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
well let me try this in a couple of
different ways let me try this as
follows let me go ahead and maybe undo
this because I've gotten pretty good
already at saying hello so let's let you
know let's draw that Line in the Sand
and just say all right 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 to 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 means literally print out n m 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
printing the contents of that variable
that is its so-called value all right
let's go ahead and do this here python
of hello.py enter what's your name David
and now crossing my finger still I see
hello comma David all right so it's not
the best program I'm 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 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 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
VSS 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 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 uh ask user for their name now I
don't have to use that language I don't
have to use that uh 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 why
well tomorrow morning when I wake up
having you know uh 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 codee's now doing what you
intended 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 is 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 is to
remind yourself and others what it is
your intent and your code is doing
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 uh programming of pseudo code
pseudo code 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 pseudo code 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 so
for instance if I wasn't sure today how
I wanted to go about writing this
program but I did know what I want to do
I could have started today by just
writing this in hello.py no code I could
have 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 pseudo
code then I can go in there and say all
right how do I ask the user for their
name uh well I can do input quote
unquote what what's your name question
mark and then on the left here I can
maybe put a variable and assign it to
that 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 uh and let me okay let me now
print the person's name so again pseudo
code is a nice way of structuring your
to-do list especially if you have no
idea how to write the code because it
breaks a bigger program down into small
bite-size tasks all right let me pause
here to see if there are now any
questions on comments pseudo code return
values or
variables any questions we can clear up
here yeah my question is uh does the
function input uh work for any type of
of information or only for Words 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
several line comment oh how do you do
many lines of comments if if I'm hearing
you correctly sure uh 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 tend to
have special meaning you can do three
double quotes like this and then
anything in between here is a comment
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 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 print out 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's
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 programming Python and
other languages there's so many ways
sometimes to solve the same problem and
here's one way to solve this problem let
me go in here and let me go ahead now
and say hello comma 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 of hello.py 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 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 of hello.py enter David
enter and there we go now we have
something that looks a little prettier
in terms of English grammar hello comma
space David 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
but before the double quote and that was
just for Aesthetics to 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's other ways we can do this 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 3 four five onward so let me go
ahead and pass in not just hello comma
space but that followed by name and this
is a little confusing potentially at
first glance because now I've got two
commas but it's important to note that
the first comma is inside of my
quotation marks which is uh simply an
English grammatical 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 the second argument is
the name variable itself so let's see
how this looks python of hello.py enter
what's your name David enter okay I've
kind of overcorrected 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 python of
hello.py type in my name David now it
looks grammatically like I might want
now which of these approaches is better
this approach uses a function print with
two arguments hello comma 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 what's inside of parentheses
first so if inside of parentheses you
have this string of text hello comma and
a space which I need to add back then
you have a plus 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 comma 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 I secretly 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's any questions on numbers of
arguments now to
functions can we use a function uh many
times to solve a certain problem which
we can encounter many times in our
code you can you can 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 plus sign can we give just
one variable and after Comm again 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 is a technical term in a
programming language and again it means
a a sequence of text a character a word
a whole paragraph even so the plus
operator is not just used as we'll see
for addition of numbers in Python like
we do on paper pencil but it also is
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 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's 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 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 stir so to
speak St for short for string as you may
know if you programmed in other
languages people who invent programming
languages like to be very uh 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 stirs
this is an actual type of data in a
program but we'll soon see that there's
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 comma
David all on the same line 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 used
print again to call uh 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 up at this URL here docs.
python.org is where all of Python's
official documentation lies if I poke
around I can find my way to more
specifically this URL here where I can
find all of the available functions in
Python that and the documentation
therefore 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 time or 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 as follows is this
the name of this function is of course
print then there's a parenthesis over
here and another Clos parenthesis way
over there everything inside of those
parentheses 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 in 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 they
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 so 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 text one string
like I did two strings like I did or
technically infinitely many if you you
really want though that code's not going
to look very good 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 single quote so
quote unquote space I don't know what
that is yet but I I 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 n
and the default value of that parameter
is apparently based on this equal sign
and these quotes back sln and what is
backs slash 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 back
sln means new line and it's a way
textually of indicating if and one 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
back slash n you don't literally see
backs slash n you see a new line you see
the cursor moving to the next line now
by that logic let's move backwards 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 it's the whole thing
is going to be ended with a new line now
just by knowing this and let me 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
the original problem was this I don't
like how hello comma 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 equals
quote unquote not back sln which is the
default automatically let's make it
quote unquote 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 and
clear it and I'm going to run python of
hello.py 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 five is going
to print out hello comma space but then
nothing at the end of it because I
changed it to be quote unquote 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 of. hi
what's your name David and now you see
literally really ugly output but you see
literally what's going on hello comma
space then three question marks and that
print statement and then you see d a ID
so not a good out outcome 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 comma and name
they were separated by a single space so
Pyon of hello.py D Aid 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 uh question mark question mark
question mark just to wrap our minds
around what's going on there let me now
do python of hello.py David enter and
you see two these two inputs hello comma
and the name are now separated in an
ugly Way by three question marks Mar s
because I've overridden the default
behavior of sep and 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 D 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 call uh use them by name this may
be aird question but I was wondering uh
what if someone wants to like add
actually qu quotation marks within the
quotation marks yeah I like how you
think this is what we would call a
corner case right just when we've made
right this is this is all sounding great
at least as 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 a lot of this and let me just say
something like
hello um maybe I'm being a little
sarcastic here hello friend you know in
that kind of tone well this is not going
to work actually because you are trying
to use quotes to be like friend in
finger quotes but you're also trying to
end the sentence and if I try running
this let's do this python if hello.py
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 I
can do this I can change my outermost
quotes to single quotes because recall a
moment get 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 of hello.py
there we go hello friend but there's
another way if you insist on using
double quotes as you might want to just
to be consistent you can also use that
backslash character again we saw the
backs slash 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 of hello.py
enter and now it's working as well so
escaping is a general technique that
allows us to do that too and 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 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 uh 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 right if
you do this you will literally see hello
comma 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 of hello.py 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 what you
do this is a little weird but this is
what the world chose if you put a f at
the beginning of the string right before
the first quote Mark that's a clue to
python that o this is a special string
let me format this in a special way for
you let me now rerun the program python
hello.py enter David enter and now we
see the goal this whole time hello comma
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 but let me propose that
we consider now yet other things we can
do with strings and it turns out that
even as we've been doing some relatively
simple operations here we've generally
been trusting that the user is going to
cooperate and that is to say that
they're going to actually type in what
we want them to type now now just
because they type A String though
doesn't mean it's going to look the way
we want you and I honestly as humans are
actually in the habit on websites and
apps of like accidentally hitting the
space bar a lot either at the beginning
of our input or at the end maybe because
the space bar tends to be so big it's
pretty common to get accidental spaces
before or after some users input you and
I are definitely in the habit of not
necessarily capitalizing words like we
should if we're sending text messages
we're probably being a little quick and
just sending everything in lowercase for
instance if that's your style if your
phone's not fixing it for you maybe in a
formal letter you would capitalize
things properly but you and I as humans
we can't really be trusted to type
things in a nice way necessarily when
using some piece of software be it an
app or website or something else but it
turns out that strings themselves come
with a lot of built-in functionality and
you can see all of that in Python's own
documentation here the string data type
that we've been talking about comes with
a lot of functionality built in that
means that we can manipulate the user's
input to do more than just join it with
something else like hello we can
actually clean it up or reformat it in a
way that hopefully looks a little better
for us so let me go back to my code here
and let me just demonstrate what might
happen if a user doesn't cooperate if I
go ahead here and run python of hello.py
enter let me just sloppily hit the space
bar a few too many times why I just
wasn't paying attention and I'm going to
type in my name da viid 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
something like this uh name equals name.
strip and what does this do remove Whit
space 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 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 and what do I mean by that well
if name is a string AKA stir well it
turns out according to the documentation
there's 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 white space 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 name. strip returns to me AKA a
return value it will return the same
thing that the user typed in but with no
more white space to the left or to the
white to 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 so
now now if I rerun this program python
of
hello.py enter I have Davi oh let's do
it again space space space space space
daav ID 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 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 uh
do this
name. capitalize so let me go ahead and
capitalize uh 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 of hello.py enter uh
space space space space space DAV ID
space space enter
okay now it's looking prettier right no
matter how the user typed in their name
even a little sloppily I'm now fixing
that but let's let's try something I'm
getting a little curious here how about
this uh space space space space space
David space maen 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's other functions in 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 come with strings called title that
do 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
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
was 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 repeat myself
than typing everything manually let me
go ahead and hit enter uh space space
space space space DAV ID mailin space
space all lowercase enter now it's 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 and
capital uh capitalize users name 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 daavid
space m n then strip off the white space
on the left and the right that is going
to return a value it's going to return
da ID space m n without any white space
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 if we want
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 all right let me pause
here and see if there's any questions on
these methods a method is a function
that's built in to a a type of value
like these functions are or on F strings
which we saw a moment ago yes hi thanks
David um so is there a way to remove the
spaces between the spaces that I might
have added 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's two other
functions that come with strings one's
called L strip the other's called R
strip that allow 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 Al together how
many functions can we combined like this
do stripe do title you have combined so
how many we can combine yeah a really
good question technically as many as you
want but at some point your codee's
going to start to look really really bad
right because the line of code's going
to get really really long it's
eventually going to maybe wrap around
again and again so at some point you
just kind of say like uhuh that's too
many and you start breaking it up into
multiple lines like I did maybe
reassigning the value to the variable as
needed and this is actually a good
question if I can pivot div off your
question I mean what do people think if
we could go ahead and put everyone's
hands down for a moment let me ask this
is the way I've done this now with strip
and title and input all in the same line
better than my previous approach in Zoom
you can use the yes icon or the no icon
if you think this version is better say
yes if you think this previous version
was better for instance this one here
where we had everything broken out say
no and then we'll see why in just a
moment I proposed earlier that
reasonable people can disagree and
that's absolutely the
case doing it one way or the other isn't
necessarily best at least if you can
justify it let me go back to the most
recent version
here all right so we're seeing a lot of
yeses and a lot of NOS why don't we go
ahead and and call on one of the yeses
if if we could someone who's voting yes
why do you think the current version of
this code is indeed better than the
previous longer version of the code I
think it's more readable so I can say
hey this is the name fun this is the
name variable it gets some input and
then remove the space and give it a
title and there you go you have a Hello
name yeah I think that's pretty
reasonable it's very readable at least
if you're in the habit as you are in
English of reading left to right it just
kind of flows very naturally as a result
the lines is not really that long it's
certainly fitting nicely onto the screen
so I think that's a good argument how
about a Counterpoint though someone who
voted no if we could call on someone who
thinks this is worse uh because it's not
avilable at all uh it seems like
uh it's a very long uh line so I think
it's better to separate yeah I 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 a 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 uh
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 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 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 substring 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 well we could actually
leverage 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 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 space Ma
and let me go ahead and call split and
pass in as the argument to split a
single white space thereby indicating
that I indeed want to split on that
character now it turns out split's 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 variable for instance first
comma last equals 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 man I can just say hello comma
first all right let's go ahead and clear
my terminal window run python of
hello.py and hit enter I won't bother
with any leading Whit space this time
but let me go ahead and type in David
space maen and crossing my fingers is as
usual hello David is what we now see all
right so we've seen so much so many
examples thus far involving strings but
certainly programs uh and programming
languages can manipulate other types of
data as well let's go ahead and
transition then to another very common
type of data in Python in programming
more generally namely integers otherwise
known in python as int int so just as
stir St Str is short for string so is
INT in Python short for integer well
what's in an integer well just like in
math it's a number like -2 Nega 1 0 1 2
and all the way toward negative Infinity
all the way toward positive Infinity but
there's no decimal point in an integer
it's just a number like -2 Nega 1 0 1
and two onward that's an INT of course
in the world of mathematics there's lots
of symbols that we use and we've seen
plus before although we used it for
different purpose but python supports
these symbols and more and python allows
you to add numbers together plus
subtract numbers uh multiply numbers
divide numbers and 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 so
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
you don't necessarily have to keep
writing code in a file like hello.py and
then running it in a terminal window one
of the features that many people like
about python is that it supports this a
so-called interactive mode like you can
start writing python code and
immediately execute each of those lines
interactively if especially if you don't
care about saving all of your lines of
code you just want to execute code and
get back some answers so for instance
let me go back to VSS code here and let
me close hello pi and let me click on
the Little Triangle over here in my
terminal window just to make it much
bigger just temporarily for a moment so
I'm not creating any piy file now I'm
just going to run python by itself at my
prompt and you'll see when I do this I
get some cryptic looking output and the
date and time at which the program was
last updated and so forth but I
ultimately get three triple uh brackets
like this this is the interactive mode
for python so I'm running the python
interpreter and anytime I type A Comm 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 so what might I
do in interactive mode well I could do
something like 1 + one enter that's
actually code right you might not think
of it as code but if you know a bit of
arithmetic and you know uh numbers and
you know plus that's valid python code
and you can use Python really as a fancy
calculator but I could do other things
too if I want to print to myself hello
comma world I can also print out that
line of code there too hello world so
it's interactive in the sense that the
moment you execute a line of code boom
you see the result we're generally not
going to do that because at least when
teaching the language we tend to want to
do things incrementally and we want you
to be able to see where it is we came
from and we want to be able to try
things again in again especially if we
make mistakes but know that this is
indeed a feature of python this
so-called interactive mode but 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 our own little calculator
so let me go ahead and open up vs code
again and I'm going to shrink down my
terminal window and I'm going to create
a new file called calculator. piy so to
do that recall I can type code down here
here and the name of the file I want to
create Pi enter that gives me a new tab
up top so I have already closed hello.py
I'm now in calculator. piy and let's
just make a simple calculator that does
some addition for me but I'm going to do
it in a file so that we can iterate on
this and make changes For Better or For
Worse over time let me go ahead and
first declare a couple 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 now this program admittedly not
very exciting or interesting in fact
it's a little less interesting than
printing stuff on the screen like before
with strings but we'll build on this and
see what other features exist in Python
that we can leverage so hopefully if
python knows its math as well as I do
when I run python of calculator. piy I
should see hopefully that 1 + 2 equals
indeed three all right so not that
surprising and not that that interesting
and honestly this isn't the most useful
program because it's always going to
calculate 1 + 2 equal 3 let's at least
make this program say a little more
interactive right we already know from
previous examples how we can get input
from the user let's bring back that
input function and let's do this let me
go ahead now and 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 is of asking the user
for x and 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 why all right at this point I
think I'm going to leave the rest of the
code the same Z equals X Plus Y and then
print Z but what's nice now is that I
think I have a nice interactive
calculator right now it's not going to
do 1 plus two 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 all right
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 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 on jalli if I'm saying it
right I think the issue is is that it's
concatenating strings because you use
the plus operator instead of adding
perfect 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 types 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 re uh
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
whatever the integer version of X is
plus whatever the integer version of 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 for calculator I can actually
hit tab to finish my thought so
autocomplete is possible in a terminal
window like this type the first letter
or 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 X X1
what's X2 and there we go now we have a
general purpose calculator that's going
to support not just uh 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 c z 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
uh 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 here doing something that's pretty
interesting now even though it's a bit
of new syntax notice that you can Nest
function 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 your
teacher probably taught you to focus on
what's inside the innermost parenthesis
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 parenthesis
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 quote unquote one
becomes the input to the int function
and 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 + 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 of calculator.
piy enter one and two and we're still
getting three not 12 or not 12 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 I'll undo all of
this as we vote instead looked like
this all right and let me go back to now
the newest version let's take a hand of
the is someone who thinks this latest
version is better I think this way is
better because it uh allows us to
immediately see what the X and Y
variables are with um integers and so we
know what to expect from them and also
the print argument is more U intuitive
we avoid too much clutter uh in the
codes I think those are all good reasons
it's nice and succinct the lines of code
are not very long
uh I don't need to know what Z is
because it doesn't exist it just see
print X Plus y I like that 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 uh I think the earlier version
is better because when uh I mean if user
inputs something else other than in
let's say I mean let's say the type one
and two like so it be it will be easier
to debug this version or the this
version here or the old version the old
version okay that's fair and in fact I'm
I'm being very careful today as best I
can not to mess up I have thus far only
inputed integers when I'm expecting
integers and R is actually pointing 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
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
h 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 tradeoffs
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 you might be tempted to
try to like combine an entire program
into one long line for instance let me
do right just that that don't
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 Al
together 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
syntactical 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 like
visceral reaction you should have
sometimes when code starts getting a
little too complicated a little too
clever perhaps for its own
good all right 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
1 0 and one a 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 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 VSS 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 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 of calculator. Pi
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 so that wouldn't have
worked before if I were only expecting
integers from the user but now that I'm
support expecting floating Point values
and accommodating it I can actually now
do floating Point arithmetic as well 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 out that here too python comes
with some functionality built in and in
fact if we return to this URL from
earlier where in 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 at 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 it's available parameters
that is inputs that we can provide when
using this function but this is a little
cryptic too just like Prince 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 times there's no star
there's no star objects like there was
for print the round function takes just
one number as its first argument period
that's it positional parameter but
notice this syntax and this is a
convention in programming or technology
more generally generally speaking when
you see square brackets in documentation
like this this means that you're about
to see something optional and so what
this means is that if you want to
specify more precisely the number of
digits that you want the round function
to round to you can specify it here by
adding a comma and then that number so
if we read the documentation if you
don't specify a number of digits you
just specify the number to Round it
rounds to the nearest integer but
suppose you want to round to the 10's
place or the hundreds place that is one
or two digits after the decimal point
you could additionally pass in comma one
or comma 2 to be more precise so that's
what the documentation there is saying
let's see if we can't then translate
this to some actual code for us so if I
go back now to vs code and I consider
that I want to go ahead and round X and
Y I can do this in a couple of ways I
could do round X+ y but uh you know I'd
actually kind of prefer to break this
now out into two lines 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 + 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 of these chunks
of code all right let me go down to my
terminal window now and run python of
calculator. Pi 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 five all right
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 of calculator. Pi again and
let me just add
999 + 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
1,000 whether or not we round so that's
just arithmetic with integers here but
in uh the us we tend to format long
numbers by putting commas uh 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 but for me I'm using the uh us
approach here which is periods for
decimal points and commas for separators
what if I wanted this to be outputed as
1 comma
0000 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 comma 00 comma 00 0
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 this let me print out the value of Z
but wait a minute I can't just say quote
unquote 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 two 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 th so I didn't make anything
worse but notice 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 of
calculator.
9991 and now notice that the number has
been automatically formatted for me if I
were in a different country or local I
could abs 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 all right let me pause here to
see if there's any questions now on
floats on rounding or on this use of f
strings yes so I have a question so when
using floats um is it like a cap to how
many decimal points you can have
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 uh
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 Flo 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 uh a little
different from this just doing x ided 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 well just some
simple division so python of calculat Pi
let's do something like 2 / 3 and of
course I get 66666 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 a uh 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 now
in Python but there is a bound on just
how precise prise a floating point value
can be all right 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 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 parenthesis I
don't want to pass in just one argument
I want to pass in 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 of
calculator. Pi I'll do the same thing
two and then three 67 so here too we see
a way of rounding now not just to a
nearest integer but to a nearest number
of digits but there's another way to do
this here and in fact this evokes our
our uh F 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 quote unquote 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 I'm going to use a
different sequence uh of characters I'm
G to say 0 2f and this too 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
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 so let me run this version of the
calculator type in two and then three we
get the exact same thing but again this
is just consistent with my claim that in
program 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 you could imagine
though it being useful to use a function
sometime 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
2 and then writing it like this let's
transition now from focusing on string
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
well let me propose that we do this let
me go back to VSS code here and let me
propose that we go back to hello.py I'm
going to reopen hello.py 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 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
now the authors of python years ago
didn't think that we 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
question mark and 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
hello.py I think the first Line's 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 Clos 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
name error 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 defa defa for
Define so here too just as stir 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 now 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 open
parenthesis close parenthesis colon what
this means now is that python is going
to treat every line of code that I IND
underneath this one as the meaning of
this new function hello So Def is
important as is the space I get to
choose the name of the function and I'm
choosing to call it hello the
parentheses with nothing inside means
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 quote unquote hello
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 VSS 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 converted automatically to four
spaces 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
cuz 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 of hello.py 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 I think
we can probably do better than this by
improving things further why don't we
consider though how we might say
parameterize the 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 and up 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
say that the name of of my parameter
will be the word two why because I want
my function to sound like the verb it
represents hello but who do you want to
say hello to well I'm going to call my
parameter for this function to just CU
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 like 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's
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
inste instead say hello parentheses 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 two 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 ARG 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 that
same value is now called two so name is
essentially copied to another variable
called two 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 uh
straight let me go ahead and run python
of hello.py 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 what if you
wanted your hello function to say hello
to someone specific but you know 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 quote unquote
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 still just defining a
function called hello it takes a
parameter called two but I'm assigning
it with the equal sign a default value
of quote unquote 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
on line five I'm going to very simply
call hello 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 of
hello.py 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 but let
me now make this point too one of the
whole points of defining your own
function 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 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
well just in 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 oh hello is a
function why 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 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
hello.py notice that as soon as I run
The Interpreter python of hello.py I see
a name error name hello is not defined
again did you mean help 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 I have to
Define any functions I want at the very
top of my file but that too could get me
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 up here up here as opposed to like
writing your code logically top to
bottom 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 lines further down I'll
actually Define my hello function
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 of hello.py enter
nothing whatsoever happens 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 that is used either of them yes
I'm using hello in side 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 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 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 because suppose I
had done something a little bit
differently suppose that I hadn't
defined hello is taking an argument so I
just remove mention of two and its
default Value 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 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 in name the variable
into which I got the user's input but
the catch is that name exists now only
in Maine and so watch what happens when
I try to run this version of the program
with python hello.py I hit enter I'm
prompted for my name DAV ID enter and ah
a name error name name quote unquote is
not defined 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 in so far as I Define this variable
name in my main function I can only use
that variable in my name 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 and now in the hello
function it technically has a different
name it's called two 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 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
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 in
fact let me go back to VSS code here and
I think we'll return our attention to
calculator. Pi and see if we can't
Implement one other version of calculate
calculator. pi that actually has our own
function that even returns a value so
I'm going to go ahead and open up uh
calculator. pi 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 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's input after asking
them what's X so again a line of code
quite like we've done before 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 two so 2 squar would be 4 3
squar would be 9 4 squar 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 let me go ahead
and say that uh printing how about uh
X2 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 INT and stores
it in a variable called X on line three
I then say x^2 is and then I pass a
second argument to the print function
whatever the return value is of a square
function but Square doesn't exist and
I'll show you this here if I now call
Main at the bottom and I run python of
calculator.
Pi I'll see that X is two and then I see
a whole bunch of Errors a name error
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
this one's going to take in a number and
I'm going to call it generically n as
many a programmer would just to
represent any old number and then what
do I want to do in order to square n
well a numbered 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 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 calculator. Pi enter X sh say
shall be 2 x^2 is 4 let me go ahead now
and say x is now three X2 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 so ultimately what we
have we done here we first introduced
functions these or verbs many of which
come built into python that you can just
use in your own code we then introduced
variables via which you can 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
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men and this week we focus on
conditionals conditionals or conditional
statements in Python and in other
languages are this ability ility 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
or this other line of code instead they
allow you to take the proverbial Forks
in the road within your own code
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 example 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 repres
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
represents equality comparing the thing
on the left and the right one equal sign
as always represents assignment copying
the thing from the right to the left
lastly this last symbol represents not
equal to so the exclamation point or
Bang uh followed by an equal sign means
not equal to some value next to it 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 lines 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 VSS code
and let's go ahead and create a program
for called compare. 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
code of compare. py 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 suppose we want to compare for
the sake of discussion just a couple of
integers but we'd like those integers to
come from the user so that we can make
uh 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 question mark 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 uh converting that
ultimately to an INT as well so at this
am 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 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 quote unquote X
is less than y so this isn't a very
interesting program yet I'm literally
just stating the obvious based on the
math but it's allowing me to 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 bull is
simply a question that has a yes or no
answer or technically a true or false
answer and that's nice because if
there's 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 a uh three conditions if you will
one question asking X less than y one
asking X greater than y one asking xals
equals y let's run the code well down
here in my terminal window I'm going to
run python of pair. pi 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 well let's take
a look perhaps at this same code uh
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 a flowchart 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 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 an 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 one is less than two so that's
why my program printed out quote unquote
X is less than y but recall the code 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 X
greater than y that too has a true or
false answer so we go one way or the
other but if x is 1 and Y is 2 then no
the answer is false one is not greater
than y so 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 print out on the screen now
there was still a third question and
this flowchart captures that as well the
third Diamond asks x equals equals y now
that to has a false answer in this case
because one 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 so 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 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 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 welld designed
too
thoughts on in what way this program is
arguably not welld
designed even though it's
correct let's see here uh khed 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 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 L if and this
too is kind of a succinct one it's a
conjunction of else if in English which
allows us to ask a question that takes
into count whether or not a previous
question had a true or false answer well
what do I mean by that well let me go
back to my code here and let me propose
that we now improve upon this here by
asking ourselves ultimately how can we
ask fewer questions and 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 if I'm
going to say if x less than y l if x
greater than y l if x equals equals y so
I'm going to implicitly just like an
English take into account that I'm only
going to keep a asking myself these
questions if I haven't yet gotten a true
response think about the logic here the
English if x is less than y on line four
print out 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 and I think the
behavior is going to be the same python
of compare. Pi 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 that 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 in so far as I was asking
three questions no matter what even if I
already figur 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 arrows 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 long longer
Arrow the down Mark true we print out
quote unquote 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 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 two for x
and one 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 uh one uh two is
greater than one 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 now X less
than y is an answer of false because no
two is not less than one so we follow
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
quote unquote 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 asked two
questions but then boom we're done only
if x happens to equal y do we actually
find our elves logically getting all the
way down to this final L if in my code
and pictorially only if x is equal to Y
do 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 or 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 uh AR we supposed to put an else at
the end ah a good question and yes so
that's going to be my 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 allow ows us to be even
better at expressing this logic to
design this program even better and
that's going to solve a particular
problem so if I take us back to our code
here notice that what I've highlighted
earlier L ifx equals equals 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 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 um
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 hope propos
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 catchall so to speak a final
line of code that says else just assume
that X is equal to Y therefore printing
it as well so 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 of compare. piy let's do for
instance one and two 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 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 uh building blocks
inside of it there's fewer arrows and
there's fewer nodes in this picture
let's start at the top now start leads
us to the first question still 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 X is
greater than y true or false if it is
great we can print X as 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
comple it 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 uh capability
into 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
or not it's greater than or equal to and
caring about the precise answer let's
take a 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
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 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 conclude X is not equal to y so if
we instead want to make sure that it is
equal to we can just use uh hopes else
using print quote unquote X is equal to
Y and again why is this well 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 of compare. Pi what's X One
what's Y 2 okay X is not equal to Y
let's do it again but two for x one for
Y X is not equal to Y and one third time
how about X is 1 and Y is One X is now
equal to Y now if we want to compare
that visually too 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 pictoral
representation thereof what's the first
question well if x is less than y well
then we follow the true arrow and we say
quote unquote 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 one 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 lastly we have the
following 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 uh 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 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 you print x
equal to Y else X is not equal to Y
perfect recall one of the other symbols
we saw on 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 why 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 and
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 got to go left you 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 X 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 uh 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 let me go ahead now and reverse these
two here and move
the second one first and the first one
second 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 the not
equal to equal equal 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 flowcharts capturing the
relative simplification of each of those
programs too all right let me go ahead
and pause here to see if there's any
questions now on any of these versions
of
code yeah I have a couple of questions
uh what if indentation is not
used uh 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 uh 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 and I think did you have
one other question uh yeah uh is the
colon
necessary is the colon necessary yes the
colon 2 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 canote 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 Al together in VSS code
whereby I'll go ahead now and create a
new program say called grade. Pi 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 like that I'm going to go
ahead and run code of grade. py to give
myself a new file and I'm going to go
ahead and start by just getting the user
score again on some assignment or test
or the like and I'm going to store it in
a variable called score equal 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 or
hopefully much higher than that like 997
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 score
well in the US 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 a 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 exess 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
score is greater than or equal to 90 and
the student 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 in a because they're in the 90s
above grades range L if the score is
greater than or equal to 80 and the
score is less than or equal to say
89 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 in
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 L if
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 l if 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 uh an F so we're
skipping e Al together and we're going
to give an f instead for the grade so
that's the catchall 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 a c or a d else it's
going to ass assume that you got an F
well let's try just a few of these here
let's run python of grade. Pi my score
is let's let's start strong 100 all
right 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
the next time that's now say 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 submited at all that's a an
F Al together all right so 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 now or
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 is 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 well python
allows you to Nest these things like
this and chain them together and just
like you would on paper pencil the real
world you can encode in Python do this
which is just a little cleaner right
it's tightening up the code a little bit
it's fewer keystrokes it's faster to
type 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 still
well what what more could I do here next
well you know what each time I'm
deciding these grades I don't think I
have to ask two questions I 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 if we know the input
for the moment is going to be within
zero 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 L if the
score is greater than or equal to 80 the
student gets a b l if score is greater
than or equal to 70 they get a c l if
the score is greater than or equal to 60
they get a d else they get an F so 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 A8
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 L if logic
we've already checked is the student
score greater than 90 and if it's not
then we're asking the question well 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 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 uh what if we don't use l if at all
what if we uh write the code in F yeah
so that's a good question because it's
actually going to have an unintended
effect here 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
if now our cleverness here of using
broader strokes and not using in upper
and lower bound ranges is going to come
back to be a downside let me go ahead
and run python of grade. Pi and suppose
my score is uh 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 logic 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 and even if your
grade is above a 90 it's also logically
above an 80 above a 70 above a 60 and if
i' kept it in there I would have failed
as well with an F really good question
other questions here on this form of
logic like it 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
El oh I I I like your enthusiasm for
simplifying things further I'm going to
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 uh and L if and and and the
like 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
uh 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 turns out it
can be useful in other applications too
to I just ask the question is a given
number even or odd maybe that the user
typed in and let me go ahead and write a
new program called parity Pi via code
parody. Pi 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 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 well
if you take a number like 1 divid 3 3
does not go into one eat cleanly so you
have a remainder of one two divided
three has a remainder of two three
divided by 3 has a remainder of zero
because it divides cleanly four divided
3 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 five divided
by three 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 I 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 well 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
question mark and 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 0 2 4 6 8 10 12 12 14 16 those are
all even numbers but what does that
really mean Elena if I'm saying that
right uh even numbers that can divide it
exactly by two for example 2 4 6 8 and
10 and 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 percent 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 ided
by 2 has a remainder of zero as Elena
proposes let's go ahead and print out
something like quote unquote 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 quote unquote odd
instead and let's go ahead and now run
python of parody. piy 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 thing 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 but what more could
we do here how could we improve upon
this 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 going to
eventually 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 question mark 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
passing in X then go ahead and print
quote unquote even so if this magical
function called is even returns true as
its return value I'm going to print out
that it's even else 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 call 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 percent 2 equals
equals z just like before 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 stirs or strings ins or integers
Floats or floating Point values all of
which are different types of data in
python python also has a fourth data
type called bull for a Boolean value and
even though this is just adding to our
list the nice thing about bulls is that
they can only be true or false an INT
can be any number of infinite possible
values a bull can only be true or false
and it must be capital T and capital F
if you're writing itself so if I go back
now to my code and I consider exactly
what I want to return here well if x if
n% 2 equals equal Z that is if n / two
has a remainder of zero well I think
it's even to Elena your 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 and we returned false
instead 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 of parody. Pi
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 X how about three and
it's odd 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 less than y or y greater
than x or the like it's going to be a
function call I'm using a function as my
Boolean expression but that's okay
because I know because I wrote it that
that 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's any questions now on
how I've implemented is
even using this bull hello hi David
first of all thank you for this
wonderful class uh did before yesterday
and today uh I have just one query like
bases on my background of java uh there
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 uh short answer no
those who are unfamiliar with Java or
other languages or C or C++ there's
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 bulls
and these is evens so I actually had a
question about um defining a function
okay if that's okay sure so if you
define one are you like within your code
like you made it up are you allowed to
use the dot operator like we did name.
strip and use it like that
good question if you've created your own
function can you use other functions
like strip ortitle or Capital eyes that
we've seen in the past um 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 bull
bulls 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 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
there's 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's 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 and
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 Python you can actually
collapse this into just just one more
elegant line if you will instead of
asking if n / 2 has a remainder of zero
return true else return false let me
delete all of that and just say this
return true if n / two has a remainder
of zero else return false 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 on line that very same
thought and one of the reasons why
python is popular is that it does tend
to read rather like English it's not
quite as user friendly as most English
or most human languages but notice now
the line does rather say what you mean
return true if n / two has a remainder
of zero else false I mean that's pretty
darn close to something you might say
logically in English be it about even an
odd or really anything else so that
program is going to work exactly the
same python of parity. Pi let me type in
two it's still even let me type in three
it's still odd but I can refine this
even further and again consistent with
this idea of not just writing correct
code but writing better and better code
but still keeping it readable I can do
one even better than this notice this
value here is my Boolean expression and
it is going to evaluate to true or false
is n / two having a remainder of zero or
not like that is by definition a Boolean
expression it has a yes no answer a true
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 readable version of this code
would be to delete this whole line
pythonic though it is and just return n
modulo 2 equals equals 0 if it helps let
me add parentheses temporarily because
what's going to happen in parentheses
will happen first n / by two either does
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 order of
operations you don't even need the
parentheses so now this is perhaps the
most elegant way to implement this 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 just as
correct to have an if and then an 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 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 this 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 parody. py and let me go ahead and
create a new file called house. py and
in house dopy I think what we're going
to do is try to implement a program that
prompts the user for their name and then
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 question
mark and then after that I'm just going
to use a traditional if L if else
construct to decide what house this
person is in so let me say if name
equals equals say Harry as in Harry
Potter well let's go ahead and print out
Harry's house which is Gryffindor in the
World of Harry Potter L if the name is
instead Hermione then go ahead and print
out also quote unquote Gryffindor as
she's in the same house too L if name
equals equals Ron let's go ahead and
similarly print out Gryffindor quote
unquote and let's make this a little
more interesting now L if name equals
quote unquote how about Draco Draco
Malfoy in the books Let's go ahead and
print out quote unquote Slytherin and
just in case someone else's name gets
inputed for now let's just suppose that
we don't recognize them and say by
default else print out quote unquote who
question mark just to convey that we
don't actually have a hard-coded
response to that particular name let me
go ahead now and run this as python of
house. py enter 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 of Housey let's type in Draco
this time Slytherin and now let's type
in an unrecognized name let's go ahead
and rerun python of house. py and let's
go ahead and type in Padma enter and who
because we haven't actually hardcoded
with an L if condition in this case uh
what house Padma is meant to be in all
right well it turns out there's 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 so
let me go ahead and do this let me go up
here and instead do something like this
let's get rid of these two blocks of L
ifs leaving just Harry's for a moment
and let's use that or keyword again and
say or name equals equals quote unquote
Hermione or name equals quote unquote
Ron thereby consolidating all three
cases if you will into just one if
statement then we still have a separate
L if for Draco because he's not in fact
in Gryffindor and then the final El to
catch anyone else all right let me go
ahead now and run this version of the
program python of house.i I'll type in
hermion this time she too is still in
Gryffindor let me try it with Ron and
that too still seems to be correct well
it turns out there's another approach
alog together 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 and
Hermione and Ron but a whole bunch of
other names as well for Gryffindor for
Slytherin and for all of the other
Hogwart toes so you can imagine that
code is 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 house dopy and let me propose that I
get rid of my current if L if 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 and then I'm going to go ahead
and include a colon and then 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
and I'm going to put Harry in quotes
because it's a string or a stir and I'm
going to have another colon at the end
of this line and indented 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 quote unquote
Hermione and similarly I'm going to have
under that indented print quote unquote
Gryffindor close quote now I'm going to
have another case for Ron also in quotes
with a colon now print quote unquote
Gryffindor and now I'm going to have a
other case for let's say Draco this one
gets a little more interesting because
Draco of course now is in Slytherin and
then I'm going to go ahead and leave it
as that for now so let me go ahead and
save this file and go back down to my
terminal window running python of house.
py enter and 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 now let's try
another name that we haven't uh 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 catchall
that handles anyone whose name is not
explicitly specified 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 context
in Python but for here it's meant to say
whatever case has not yet been handled
go ahead and print out as we did before
for instance quote unquote who with a
question mark at the end now let's go
ahead and rerun this python of house.i
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 in the same
line and the same if statement but here
we have now three case statements again
for all three of those well we can
tighten these 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
hermion 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 hermy then
another single bar and do quote unquote
Ron 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
house.i let's make sure that Harry is
still in Gryffindor let's make sure that
hermion is still in Gryffindor let's
make sure that Ron is still in
Gryffindor and indeed all three of them
are 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 tighten
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 ell if
and ell if and ell if all over the place
but ultimately this would be an equally
correct approach to that same problem
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 L if 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 catchall at the end
of the match so just by adding in some
of these new keywords here like if and L
if and else we have now the ability to
ask questions about values we have the
ability to analyze input from users and
ultimately make decisions about it and
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
[Music]
[Music]
again all right this is cs50's
Introduction to programming with python
my name is David men and this week we
focus on Loops this ability in python
and a lot of other programming languages
to do something again and again a cycle
of sorts and let's see if we can't begin
by motivating exactly why we have this
ability to do things cyclically using
these Loops I'm going to go ahead here
and open up VSS code and in my terminal
window let's go ahead and create uh via
code cat. py a Python program that meows
like a cat and 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
prints we're going to have this cat not
make audible sounds but just print meow
meow meow on the screen three times 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 and now let me go
down to my terminal window let me run
python of cat. py enter and meow meow
meow all right 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 of
the computer let me propose that we
consider this flowchart so as before we
have this flowchart that starts with a
of this oval which just means start
reading here and then notice it goes via
arrows to a 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 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 okay so I mean repeating the same
action like three times or 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 uh 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 want to 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 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 yeah
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 we can do
better than that if we think about a
little harder what we how we go about
structuring this program and we can do
that if we augment our vocabulary just a
little bit 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 50 times as
many times as we want but while rather
leaves to us the 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 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 and if the answer is true keep
going if the answer is false stop 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 three 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 zero 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 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 cat dopy
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 it might lose control of my
computer
somehow any thoughts uh yeah teimo hi uh
I think it's going to continue uh to
print out Mel since I is always equal to
three and the W 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 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 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 U'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 and 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
um fortunately if you ever do 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 like reboot or turn off the
computer you can just hit contr C in
your terminal window and that will
likely fix it all right 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
uh uh 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 9 2's 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 caty
and I indeed get three meows 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 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
always represent questions and the
answer is going to be true or false does
I not equal zero well it doesn't it
equals three so if I follow the true
line I meow and then I follow this arrow
and I update I to equal IUS one 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 2 to 1 well does
one not equal zero well obviously it is
not zero so we meow again we decrement I
again I is now zero does 0 not equal
zero no it equals zero so the answer is
false and we stop 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 and 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 y 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 1 instead
of three and here let me just change my
logic rather than checking for not equal
to zero like maybe you don't like
thinking 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 how do I want
to change line four to be
consistent with counting from one up to
and
through
three I would be plus one every time you
meow 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 oursel 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 IAL I + 1 and
now notice just for Clarity 2 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 this less than instead
of less than or equal to now I'm
starting at zero but I'm going up two
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 two but not
through the value that you care about
ultimately three in this case here 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 + 1 and this is
because it's such a popular thing to do
in code you can instead just say i+
equals 1 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 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 it's just a
convention those of you who have
programmed in C C++ pyth uh not python C
C++ Java Java Script might have seen
plus plus before or minus minus sorry
python doesn't have it so you cannot use
that this is a succinct as your line of
code might
get all right let me pause here to see
then if there's any questions about
these implementations of while
Loops um can we use stuff like four
Loops which um have a certain I value
initialized to it at at the start and it
runs from the particular condition you
put into the um into the thing and
increment it as as you go along 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
come to that in just a moment other
questions on Loops using while here
so I had a question about the flowcharts
okay uh there were c yeah there were
certain symbols for the certain kind of
the statements uh sir they are they
certainly used for that kind of
statement that they are
put they are so I deliber use anyone I
deliberately use certain types of
symbols certain shapes here uh whereby
in 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 use diamonds to
represent uh questions that you might
ask uh conditions as we've seen um 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 PR best
practices 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 I not
equal to zero let me go ahead and just
change this code now to represent the
next version we did which recall changed
our logic to start counting from one it
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
two 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 flowcharts 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 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 our 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 ID 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 stirs or strings ins or integers
Floats or floating point value use bulls
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 well
let me propose that we go back to our
VSS 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 the following list of items 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 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 short
order 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 like 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
can kind of in your mind's eye maybe see
the gears turning as all of these
variables are uh 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 will automatically update I to
equal 1 then meow will be printed then
python will automatically update I to B2
and meow will be printed and because
that's it for the values in that list
python will stop and it will only me
meow a total of three times what is the
list the list in this program is exactly
that 0 comma 1 comma 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 so let me go ahead and run
this python of cat. piy and it works
just the same but it's only two lines
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's 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 okay I think that because like we
can we are saying 0 one two which is
three times 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 going to write out one Z
through a million or 0 through 9 uh you
know
999,000 uh
999,999 like no you're not going to
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 ify 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
to a range of values it expects as input
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 to two and
so forth but they will go up to but not
through the number you specify so by
specifying range three you're
essentially being handed back one two
three values and by default those values
are zero one and two and that's it 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 I don't have to
literally type zero comma one comma 2
comma 3 comma four all the way up to
999,999 I just do this so that's to be a
better way long term so that's indeed
one Improvement we can indeed make here
still using a for Loop but now using
this range function 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 and 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 Pres 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 it doesn't
change the correctness of the program
but it signals to yourself later it
signals to colleagues or teachers 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 so
just a minor uh Improvement or change
there 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 whereby if I
want the cat to meow three times what if
I actually do this print open
parenthesis quote unquote meow times
three all right 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 want it and you
will get back exactly that result now
I've kind of made a mistake here so
let's see what this does it's not quite
as beautiful as this code might look to
to to you to some of you to me let me
run python of cat dopy enter 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 literally
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 and 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 uh we can use
a escape sequence which should did back
slash n amazing yes think back to back
sln 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 back slash
n there inside of my quotes So that at
the end of every Meo W there's a new
line let's see how this looks Let Me
Clear My screen and run python of
caty 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 uh make end
equal to column uh column not back n
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 lets you control what the
line ending is by default it's back
slash 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 comma n equals quote unquote so that
it's no longer the default back sln it's
instead now going to be uh nothing
whatsoever that should eliminate then
hopefully that additional uh blank line
so let me run this one last time here
python of caty enter 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 back sln I've got time
three I've got n equals quote unquote 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 welld 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 all
right well let me propose that things
get more interesting still if we're not
just swing 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 equals int of input uh what's n
question mark well I want to check like
I could say if n is less than Z like if
it's negative well I could do this well
then ask again int input what's n
question mark 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 equals right 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 written so we can do this
I think better maybe with a loop 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 that
it's all negative or just something like
that you just immediately say while true
you deliberately and a little
dangerously but a very conv
intentionally 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 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 in
by prompting the user for input like
what's n question mark 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 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 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 it's 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 and until they give
us an integer that is greater than zero
and then break out of this Loop and 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 1 through four
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
is it greater than zero or is it zero is
it negative none of which makes sense
for a meowing cat like 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
indented twice has the effect of
breaking out of the most recently begun
while loop 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 line six and seven so if I
run this now python of cat. Pi enter
well what's n let's start with three
where we begin meow meow meow well this
time let me go ahead and increase the
size of my terminal window just
temporarily let me run python of cat.
let me do it 10 times meow 10 times now
appears on the screen and 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 here and let me propose
actually now that we practice a little
more what we've been preaching
especially when it comes to say
especially when it comes to say 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 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 so my meow function
should take as input a parameter called
n or anything I want and this part's
pretty easy now how do you meow in times
well for underscore in the range of 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 and now as
before let me go down here and let me
make sure I call Main and if I now run
this code python of
cat. meow meow meow it's always going to
do three because I've hardcoded the
three well let's make one Improvement
here let me go ahead now and maybe do
this uh let me ask the user for a number
so let's say something like this number
equals get number all right
unfortunately there is no function in
Python called get number that gets a
positive number from the user but I can
invent that so Define get number open
paren close per n and then 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 question mark and then if n is
what I want it's 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 so I can actually do
this instead and this two 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
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
the last thing I'm going to do here now
is change that three 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 of
cat. py enter what's N I can type in
three I get my three meows or if I only
want one I now get one meow instead all
right 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 data sets 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 um the world of
Hogwarts and let me go ahead and code up
a file called Hogwarts and let's see if
we can't have a list of students at
Hogwarts here so I have a new tab called
hogw Works sty and let me go ahead and
propose that I just Define in this
program a list of students whose names I
know in advance so I'm not going to get
user input for now I'm just going to
know from the GetGo that the three
students I want to consider are these a
variable is going to be called students
it's going to equal as I've done in the
past a square bracket which means hey
here comes a list and those values are
going to be Hermione in quotes because
it's a string uh Harry in quotes cuz
it's a string and then WR in quotes
because it's a string as well so this is
a list of length three it's similar in
spirit to my list of length three
earlier but that had three ins 012 now I
have a list of three strings instead and
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
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 and the
way you do this in Python is you use
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 and 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 shall we say 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 so let me
print out all three students so let me
print out students bracket zero then
students bracket one then lastly let me
print students bracket 2 and this is my
third and final line and of course if I
run this code it probably does what you
would guess if I run python of Hogwarts
stpy there's Hermione Harry and Rob each
on their own lines there 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's some
new students at Hogwarts we can use a
loop to do something automatically
without having to manually type out zero
and then one and two well here's another
feature of python you can use a for Loop
not just to count from zero to 1 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 colon and then indented
underneath that I can say print student
now it doesn't matter if I have three
students or four or 400 this two lines
of code this Loop will print all of
those students for me one at a time so
if I now run python of Hogwarts 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
underscore 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 underscore and you're using the
variable underscore now you're helping
no one now you're confusing the reader
yourself in the down the line you should
call your variables what they are so an
very appropriate name though I'm sure
you could come up with others would be
student and here you could say you would
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 let me pause here to
see if there's now 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 uh so is it not
necessary to initiate student in this
case or we can just declare a variable
in the loop good question you 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 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 H okay sure uh can can
this follow work with either hash tables
or different kind of fight tables or
arrays uh indeed so we're getting ahead
of ourselves there but there are yet
other types of data in Python and indeed
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 more on those soon in fact let
me transition here to show just another
way of solving the same problem because
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 and 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 well 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 Rob 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 zero and ends at two
previously when I wanted to do that I
needed range but this two 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 length or Len 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 0o 1
and two so I think I can Nest my
functions like this if I first get the
length of the student list that's going
to be three then I pass that return
value as the argument to range that's
going to give me back a range of value
zero then one than two and what that's
going to allow me to do then in code if
I want is not just this I could do print
now students bracket I and this is now
where the syntax we're seeing is getting
very expressive new and perhaps
unfamiliar but if I can do Open Bracket
zero close bracket or Open Bracket one
close bracket or Open Bracket 2 close
bracket turns out I can actually put a
variable in there and I can express any
number inside of those brackets so it's
to print these all out dynamically in a
loop let me do this python of Hogwarts
enter there's Hermione Harry and Ron and
now if I'm just curious I 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 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 hermion is the top student but
she's in zero 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 eye up here and
now we see sort of a top three list of
students hermion 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 all any
questions now on on these
lists any questions now on these
lists this length these ranges or
otherwise my question is uh for I in
range can you explain this once more uh
sure
still so let me rewind in time we
started off doing this for I in
012 and then we print it 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 we 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
lengths 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 all right 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
ins not just floating Point values not
just bulls not just list 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 an 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 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 like ultimately let me create
another variable called houses set it
equal to uh Gryffindor corresponding to
herm's house uh Gryffindor corresponding
to Harry's house and Gryffindor
corresponding to Ron's house and let's
add Draco in there so we now have four
instead of three students just so we
have a little variety and he was in uh
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 uh value in
houses whoever is second in students
lives in the second house whoever 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 Patronis this uh 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 so let me
create a variable called students and
let me go ahead and set it equal to open
curly brace and Clos 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 going to this is
going to 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 something and my values
on the right my other something 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 uh Draco who lives of course
in 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
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 herm'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 zero 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
them so if you want to print out herm's
house the key you care about is quote
unquote Hermione and what this syntax
here will do notice it's not a number
zero or one or two it's literally herm's
name this is like going to the Chart
earlier and saying all right give me uh
Hermione is my key Gryffindor is the
value that's what we're doing here
syntactically we're looking up hermion
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 bracket quote unquote Harry
should give me Harry's house print
students Open Bracket Ron that should
give me Ron's house and then lastly if I
do this with students bracket Draco that
should give me draco's house now it's a
little manual still I'm bet we can
improve this but let me run python on
Hogwarts sty 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 Di
ions associating like we would on paper
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 uh 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 of Hogwarts upy and hit enter
notice what should I see 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
we we will only see Keys perfect so good
intuition it could have gone both ways
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
students 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 hermion
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 of
Hogwarts 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 herm'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 uh for student in
students does uh if I'm just correct me
if if I'm right does that mean it
Imports the list of students and uses
the indexes in other words herione Harry
and Ron as the indexes in the actual um
the list of students correct 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
bottom you get to choose what the
variable 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 herm'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
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 Loop over a list but
rather than iterate over the numeric
location 012 it iterates over the
boldfaced keys in this representation
here graphically and allow me to give us
one other example on Hogwarts before we
look at one other familiar uh 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 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 one thing with the student but
multiple things as well their name their
house and their petronus in this case
well what might code like this look like
well let me go back to Hogwarts toy 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 four 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
s 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 the same student's
going to have a third key called
petronis and the value of that is going
to be I had to look it up in 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 petronis
what are the definitions of those words
for Hermione Hermione griffindor and
Otter respectively for Harry the
definitions are going to be different in
this new dictionary let me give myself
another pair of curly braces and say
this name quote unquote colon Harry uh
house here is again going to be
Gryffindor and this one I I knew his
Patronis 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 had to look this one
up Ron's petronis 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 dra
interestingly enough at least according
to the internet has no Patronus 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 uh
Draco has no Patronis 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
two the syntax is our clue because this
line two 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 I kept it all together here
this time but how many keys does this
first dictionary have put another way in
her mayane physical dictionary how many
words are in that dictionary three the
words are name house and petronis what
are the three definitions or values of
those words in herm's dictionary
Hermione Gryffindor and Otter
respectively and the same story goes for
Harry then for Ron 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 and 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 four
student and students is just going to
iterate over every student in the list 1
2 3 4 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 to
prints arguments student Open Bracket uh
House close bracket all right let's go
ahead and run this python of Hogwarts
dopy 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 in 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
Patronis so if we want to print out that
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 so if
I run this program one final time now I
see all of the data in this here
dictionary so 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 and 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 name in a house but a Patronis
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 so how do I know uh where to
look that student from like 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 that is 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 and 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
will 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 yester here at least
for me where in one of my favorite games
growing up was this one here on the
original Nintendo and 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
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 pth 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 mario. using code in the
terminal window and 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 mario. 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 uh The 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 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 of three let's now
print out just one of these at a time
but the fact that I've now used a three
to 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 two 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 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 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 uh 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 uh
generically speaking a parameter called
height I could call it n or H but I'll
be a little more explicit now with
height 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 of 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 of Mario up high 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 reimplement
now print column in different ways
especially if I am 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 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 so 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 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
of myoy 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 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 mar Mario encounters these
bricks in the sky that if he jumps up
underneath they become coins and so he
he gains to a 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 VSS code here and let me propose
that within VSS code here just like
before we try to abstract this away so
let me go ahead and get rid of this
version cuz 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 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 mario. 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 uh
a building block toward having now a
reusable function like print row and why
am I doing all this like why are we over
engine engering 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 3X3 grid a 3X3
square of sorts well how can we go about
solving this here problem well 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
H like this if I 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 moment that there is already a
function called print Square that's
going to be width three and height three
as well but 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 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 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 and 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 so 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 3X3 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 so 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 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 what
do I want to do on each of the rows well
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 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 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 two 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 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
square for each uh brick in row
print brick and here is where comments
and more generally pseudo code can
really help explain to yourself and
others what your lines of code are doing
on line eight I'm iterating from I
equals 0 on up to side so
012 on line 11 I'm doing the exact same
thing but using J from 012 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 two 3 1 2 3 1 2 3
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 and at the
end of it so print it 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
notice that this Loop here is just
iterating for each brick in 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
and we've not done this before but when
you call print with no arguments all you
get is that automatic line ending the
back slash end where the cursor moves to
the next line so if I now roll go back
to my terminal window and run mario. I
think I should get a 3X3 square and it
doesn't quite look like a square on my
screen because these hashes are a little
taller they are wide but it is in fact
3x3 but let me propose as we've always
done here how we might tighten up this
code further just for clarity 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 what if we do this
trick again what if we print out 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 Mario 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 and let me propose that
this print row function it simply take
in that width and print 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 well 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 Al together
and how does print row work well it
could use a for Loop it could use this
string multiplication trick 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 via which you can troubleshoot
those same problems
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men 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 so what are some
of the things that can go wrong so I'm
going to go ahead and open up VSS code
on my computer here and in the terminal
window I'm going to go ahead and run
code of hello.py that's going to of
course open up a brand new tab for me
hello.py 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 ah head and say print
quote hello comma 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 well let me go
ahead and somewhat optimistically go
down to my terminal window now and run
python of hello.py and hit enter and
that's the first of my errors my gosh
I've only written one line of code and I
seem to have more lines of error errors
on the screen but the Salient point is
this bottommost thing here notice where
it says syntax error a syntax error 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 ay 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
string of course is a sequence of text
like we've discussed before or stir 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 quote 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 of hello.py now I'm saying
hello to the world so the catch withd
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
Geto 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 but there's 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 to type into your
program and so you better be ready
defensively to accommodate things that
they type or even mistype so for
instance let's go back over here to vs
code and let me propose that we take a
look at a a new file Al together I'm
going to close hello.py and I'm going to
write code of say number. piy so let's
play around with some numbers in Python
and the first thing I'm going to go
ahead here and do with number. py after
opening the this new tab is I think I'm
going to go ahead and print uh 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 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 quote unquote
what's X question mark 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 INT 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 in and that will store in X
ultimately an integer not a string that
looks like an integer all right let me
go ahead now and just quite simply print
out what this is I'm going to go ahead
and print out uh quote unquote 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 I'm going to go ahead
in my terminal window and run python of
number. Pi I hit enter and so far so
good all is well and being prompted for
X let me go ahead and type in a number
like 50 all right that seems to work
program seems to be
correct or is
it 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 any
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 what
what is an
inter we code in in a integrated
ID we can't code in a interpreter so I'm
not calling an integer I'm still having
trouble hearing you but what I think I
heard is that if the 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 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 of number.
piy 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 all right Z seems to work my code
still prints out that X is Zer what
might be another Corner case to consider
well let me go ahead and try a negative
number that too is pretty different in
spirit from 50 negative 1 okay that
works too well let me try it one more
time I've tried positive numbers
negative numbers zero let me try
something like a cat so literally C A
typing in a string that doesn't even
look like a number and yet let's see now
what happens when I hit enter all right
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 a 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
so what does this refer to a value error
well let's see what the explanation is
invalid literal for INT with base 10
quote unquote cat now this to is a bit
of a mouthful and unfortunately in
python and a lot of programming
languages the error messages are written
for pretty comfortable program 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 so 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 uh 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 quote unquote to the int
function 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 an
integer or please don't type cap please
don't type strings of course the user
might still not oblig 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 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 now how do we go about
doing that in Python well it turns out
whether you want to catch a value error
or other types of errors as well though
not syntax error 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 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 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 codes 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 accept
value error and notice it's important
that I've capitalized the V and I've
capitalized the E these uh 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
quote unquote 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 value error
line five because it's indented is what
is going to get executed in cases of
those errors let me go ahead now back to
my terminal window and run python of
hello of python of number. piy 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 X is not an integer
I'm not seeing some scary error message
that I of a user am have 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 let me
pause here and see are there any
questions now on what we've just done by
introducing try and accept to handle
this value error is value error the only
type of error you can get or the other
types is value error the only thing you
can catch there are other errors as well
and we'll a few of them today and
there's many many more honestly that if
you continue programming and programming
in Python you're going to see a lot of
them over the the weeks the months the
years to come 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 to use the accept log you
need to know the type of error right
like here you knew it was a value error
what what if you can't anticipate this
particular type of the 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 there is a way in Python
where you can say except if anything
goes wrong and you can literally omit
value error 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 it 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 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 some of the times 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
but this isn't necessarily the best way
to implement this code why 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 but
in the interest of PR uh 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 value error
whether X is an INT or a string or a
float or anything 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 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
a value error but I fear I've introduced
a new mistake well let's see what is now
in correct let me go ahead and again run
python of number. 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 C A again
enter now I have a name error so now
it's yet another type of error in my
code that I've introduced here and what
is this name error mean well just as a
value error refers to that the value of
some variable the value that someone has
typed in is incorrect name error 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 is it
complaining about well the name error is
what I see down here and it's telling me
name quote unquote 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
tri block so good terminology scope
refers to the portion of code in which a
variable exists that to though isn't
quite right in Python that would be true
in cc++ in 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 hand why is X somehow
still not defined
um yeah so is it because it's loo
variable meaning that like it doesn't
Define outside of scope CU like what
people have mentioned it's it as it
promps it input in try right but outside
of it it's undefined so still good
instincts in good terminology too
there's this notion of local variables
which tend to exist inside of functions
for instance Global variables which tend
to exist in entire files in this case
too though that's not quite the case
What's Happening Here boils down to
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 airing and indeed if you think
back earlier when we had the value error
it was in fact the int function that did
not like quote unquote 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 value error and in this
case we're catching the value error but
because the value error 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 equals dot dot dot
on line two the portion of that line to
the left of the equal sign isn't getting
evaluated ultimately because the value
error is happening too soon 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
value error 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 accept syntax
that python supports which is that it
also supports the keyword Els now we've
seen Els before if you think back to our
discussion of conditionals we saw if we
saw L if we saw Els 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 TR accept feature of py
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 value
error however if you try and this code
succeeds then there is no exception to
to handle so you're then going to
execute this line here so it's a little
confusing perhaps in that we're now
using Els both for conditionals if L if
L if L if Els and we're also using Els
with these Tri accept 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 number. piy 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
successfully 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 number. piy let's
type in cat or again any other word and
hit enter now we don't see what x is
rather we see quote unquote X is not an
integer which is what's being handled in
my except Clause all right let me pause
here because that's a lot of new syntax
and see here if there's any questions on
try on accept on else name error or
value error can you please repeat try
function repeat the name error what's
the problem with the name error yes yes
yeah so let's let's just rewind a couple
of lines here before I fix this problem
by now getting rid of the Els a moment
ago we had code that looked like this
whereby I was getting a name error
python of number. piy enter typing in
cat 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 inputed 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 to an integer at all
so the int function is raising a value
error 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 Els statement that makes
sure that these things are mutually
exclusive I only execute the Els if I
tried and succeeded up above well let me
propose that we 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 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
userfriendly if I just prompt or
reprompt the user again and again 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 a
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
triac C code indented underneath this
Loop so that I'm trying to get an X if I
have a value error 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 codee 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 me what I want
which is an integer and once they do
once there's no value error happening
then I break out of the loop and line
nine executes as I would hope so let me
go ahead and try executing this version
python of number. piy 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 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
value error there is no value error
because if I typed in a number there's
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
accept 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 number. piy 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 well 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 50
enter now I'm out of the loop and I'm
printing out what x actually is all
right let me pause here and see if there
are any questions the logic is almost
the same but what is different now is
I'm in a loop and I'm using the keyword
break in Python to deliberately break
out of the loop when I'm ready to once
the user has cooperated do we really
need to break can't we just print or
what what keeps us from just printing uh
good question so let me try that
couldn't I just print well let's see
what happens if I do that let me move
this print line at the end in into my
Loop here thereby shortening the program
and in general that's been a good thing
python of number. piy enter 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
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 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 he uh can I use break uh all in
exception except in else for example in
another uh print and when you use print
in the else you can use print together
with break or something like this yeah
you so 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 L
if or an else you can do it inside of a
try accept 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 Els if I wanted
to I could actually do this I could get
rid of my elt and I could go back to
line three add another line that's
indented line four and break out here
now why is this logically okay well well
consider what I'm now trying to do I'm
trying to execute line three and
converting 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 going to 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 number. Pi 50 enter it worked I broke
out of the loop now which way is better
honestly I think it could go either way
at this point this program is 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 El
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 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 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 in
so now I have a function called get int
that tries to do the following try to
get an in 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 a print something on the screen
like a side effect but is to hand back a
value to hand you back 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 equals get
int and then on the next line I'm going
to do that print from before quote
unquote 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 well let's see
how this works let me go ahead and run
python of number. Pi 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 this time X is not an integer and
I'm being prompted dog and I'm being
prompted bird and I'm being prompted
fine 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 an 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
but 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 it's 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
and 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 it will also
return a value for you so it's doing two
things for once if you will but can I
make this even more compacts if if 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 function when you're trying uh at
you take you take the input X and then
done X good we can just return x a
little higher up and let me correct
folks as we go it's not a tri function
it would be a tri statement technically
a function typically has a parenthesis
and another one in this case it's just a
statement 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 could return int
input quote unquote 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 uh 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 well let me
propose too 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 silent ently ignore it like if
you're talking in a gr full of people
and you're 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 here 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 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 repr prompting
the user so now the effect looks a
little something like this python of
number. piy 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 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 accept else or
pass okay yeah know I was just kind of
curious I guess about uh the idea of
when you were indenting with uh the get
in function for example um because I'm
noticing you know obviously going
through it with the whole logic and
breakdown the entire uh the entire
function you know while true do this but
I'm just kind of curious on elaborating
with the indentations for the uh code
more yeah 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
a line of code 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 uh uh told the computer to do so so
concretely what does this mean on line
six here we're defining a function
called get int that takes no arguments
colon 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 frankly I think
the designers got tired of seeing really
ugly code in languages like C and C++
and Java uh that uh don't necessarily
enforce uh indentation to this extent so
now it's baked into the language and my
chronology might be a little off there
but there's been many languages that are
looser than python when it comes to
indentation the indentation is
Meaningful on line 72 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 12 there's eight there's 12
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
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 value
error 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 yeah thanks um two
question uh question one um uh once you
say pass can the caller still um learn
anything about this error um through a
system variable or whatever and question
two problem set zero referenced some
string Methods including is numeric is
it any different
to um go via isomeric here 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
Maine or other callers don't know that
anything technically went wrong on the
second question is numeric 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 would generally say that the
pythonic way of doing things is often
For Better or For Worse to try things
hope they work but if they don't handle
the exception so other languages are
more in favor of checking if if if if L
if else and 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 a 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 one additional step to improve
the implementation of this get in
function let me propose that we not
hardc 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 call
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 call E is just the function
being called 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 in function
well then main should probably tell the
get in 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 all right 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 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 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
what's 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. piy enter
what's x 50 still seems to work let's
run it again let's type in cat 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 sometimes there's
syntax errors which you got to just fix
if you even want to run your program at
all but they 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 except
and we'll see you next
[Music]
[Music]
time all right this is cs50's
Introduction to programming with python
my name is David Meen and this is our
week on libraries 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
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
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 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 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 so somewhere
on the computer's hard drive once you've
installed python there is also it turns
out a file probably called random. py
that someone else wrote probably long
ago but that you have access to and in
that random. piy file there's probably
one or more functions that you yourself
can use in order to do things randomly
that is to say how could you flip a coin
in a program in Python how could you
pick a 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
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 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 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
uh this uh summary of a function called
choice 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 random. choice is how
you would technically call this function
though we'll see alternatives to that in
parenthesis 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 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 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 code called generate. piy because I
want to start generating a 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
specific module now suppose I want to
flip a coin well I can do random. Choice
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 list to iterate over students at
Hogwarts let's go ahead now and list
iterate over just a list of two sides of
a coin heads quote unquote or tails 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 lower case 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's square brackets
to the right and the left which
indicates that this is indeed a list
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 ped
functions I have to specify what module
this function is in at least for now and
so I do random. choice to call this
specific function all right well it's
one thing to flip a coin picking between
those with 50% probability and that's
what random. choice does it takes in a
list and it returns to 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 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 all right let me go ahead
now and run this program in my terminal
window python of generate. P enter and
it looks like the first coin toss was
the heads let's go ahead and run it
again and it looks like it was heads
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 now if
we did this in 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 Al Lo 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 so not
just the function called random. choice
but a few other functions as well so
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 in a downside of
that is that I have to type in random.
choice random. this random. that 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 let me replace this
first line here with from random import
choice and what this does effectively is
it loads the functions name Choice into
my current name space into the scope of
the file I'm working in what that means
is that I now know 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 if you will so I can
just now say choice this might be
advantageous in what cases do you think
when might you want to import the name
of the function explicitly like this as
opposed to just saying random. choice
random. choice throughout your code when
calling a function any instincts here
for this alternative import using from
um hello I'm Mohammed from Egypt and
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 choice I choose
so I'm gonna choose random DOTA Choice
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 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
random. choice random. choice random.
choice it's just making my code longer
and longer and longer marginally so but
it 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 therein well let me propose that
we transition to to another function
that comes with Python's random module
and that's this here from the
documentation Rand int 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 10 for B you would get back a
number between one and 10 inclusive
including the one and including the 10
potentially each with a 10% probability
so how might I go about using a program
like this well let me come back to my
generate. piy file and why don't we go
ahead and try generating a random number
between 1 and 10 you might do this
frequently in the real world when you
just want someone to pick a random
number you tell them as much and the
human responds 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 random. randint and
now pass in a a value of one and B a
value of 10 and now let's go ahead and
print the number I'm going to go ahead
in my terminal window and run python of
generate. Pi and hit enter
four python of generate. Pi and hit
enter eight again nine again s again 10
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 10%
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 uh using its own 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 have 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 a deck
of cards here you might shuffle them so
it's to put them into seemingly random
order 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 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 therein well how does this now
work if you read the documentation for
random. Shuffle you'll see that it
shuffles the argument in place that is
unlike many of the functions we've seen
it doesn't return to 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
random. Shuffle and pass in the variable
containing those cards and then on a
final line here how might I go about
printing the cards well I could do this
and I could 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 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 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 print it
out one at a time and because I'm using
print one line at a time well let's see
the results down here in my terminal
window I'm going to run python of
generate. and hit enter queen king Jack
seemingly shuffled cuz that's not the
order I defined earlier let's do it
again queen king Jack H 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 hm not so good Jack queen
king not so good this is someone you you
probably want to play against with cards
Queen Jack King there we go but of
course we only have three cards here so
there's 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 simple coin toss if
you want to start some kind of athletic
event one pick a number between one and
10 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's any questions
yet on random on modules or any of these
three
functions yeah uh can we increase or
decrease the
probability uh of
costs if you want to for example there
is three there is a 33% chance of
probability so is there any chance to
increase or decrease the probability can
you set these probabilities not using
these same functions uh can you set the
probabilities but 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 userfriendly and simple
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 uh
aspects of a data set that you might
want to analyze so how might we use the
statistics module on python well we
might first just take a look at its
documentation like any other module on
Python and we'll see Within that library
that there's a whole bunch of functions
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 nvs code in my
terminal window open up a new file
called average. piy 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 and
I'm going to call Stat statistics. mean
and I'm going to pass into this function
mean a list of some values and 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 100% And on my
second I did well but not as well and I
got a 90 and ironically I'm not very
good with math so I'd like to figure out
what my average now is between those two
tests so let me go ahead now and in this
list type in the number 100 comma 90
thereby passing in a list of two values
to ins one 190 and in outside of those
are 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 and vs code Type in
Python of average. piy and hit enter and
voila as you might expect my average is
95% 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 instead 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 commandline
arguments 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 that is
input to the program just when you're
executing it at the command line so up
until now for instance Rec call that
we've generally run python of something.
py for instance python of hello.py 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-like
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 VSS 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 uh
name. pi 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 CIS and CIS 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 CIS 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 cis.org V this variable is a list
which means that the first element is
going to be the first word that you
typed the second element is going to be
the second word that you typed and so
forth and by way of this list then can
you 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 tab
called name. piy let me go ahead and
import CIS within that CIS module is
going to give me access to cy. RV 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 and 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 quote
unquote 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 this sis. RV bracket1 and that's it
I'm going to have a program here that
says hello my name is followed by
whatever is in sis. arv bracket one and
notice sis. argv 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 all right let me go
down now into my terminal window and run
python of name. py 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 prr program
what my name is at the so-called command
line here we go David separated with a
space from the name of the file so that
now when I execute python name. py 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 cy. RGV even though
it sounds certainly at first glance uh
rather complicated here let's look up at
cy. Arvy I'm going to bracket one here
so clearly cy. RV bracket one is storing
David 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
the 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
probably insist. arv of zero what is
probably insist. Arvy of zero the very
first element actually in that list oh
yeah uh I think uh it's like in C uh the
name of program indeed it's indeed like
in C and other language is the name of
the program well if we consider what it
was 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 name. 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 cy. arv 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 cy. RV let me go ahead and try
this python name. pi 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 uhoh 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 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 uh 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 name. it says
hello my name is name. 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 um
if there's nothing at location one we
just come out the say okay we haven't
got a parameter or something but if
there is we 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 you ingrain some of 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 what do
I want to go ahead and do I'm going to
say something like two few arguments I
could be more explanatory than that but
for now I'm just going to explain to the
user that they gave me too few arguments
too few words at the prompt so now it's
still not going to work in quite the way
I want I'm still not going to be able to
generate their name tag but at least
they're not going to see some cryptic
error message and think that they
themselves broke the program let me go
ahead now and run python of.pi enter and
too few ARG ments okay let me go ahead
now and do python of name. and type in
my name David and now we're back in
business and I see that my name is on
the screen too but strictly speaking I
don't have to try to do this I could
actually be a little more defensive in
writing this code and maybe I could
check whether or not the user has indeed
provided a name or multiple names at the
prompt so as to give them more refined
error messages as well so how might I do
this well let me go and and undo the
exception handling I've added and why
don't I instead more modestly try to do
this let me go ahead and introduce a
conditional here if the length of cy.
argv is less than two or equivalently
equal to just one value but I'll just
stick with less than two for now then go
ahead and print out two few arguments so
I want ultimately two arguments I want
the name of the program at location zero
and I want the name of the human at
location one so that's a total of two
arguments so if I have fewer than two
arguments let's tell the user with this
print line L if the length of cy. RGV is
say greater than two like they typed in
too many words at the prompt well let's
tell them print quote unquote too many
arguments else if they did get it right
and they gave me exactly two arguments
else let's go ahead and print what I
actually care about all right let me go
down to my terminal window here and run
python of name. and voila uh oh a
completely different type of error this
one a syntax error which we've seen in
the past now a syntax error recall is
May aopa like I messed up here and I
wrote invalid syntax and so no amount of
conditionals or exception handling is
really going to catch this one I need to
go back and just get my program to work
because it's not running at all well let
me go up here and see line four is the
issue and indeed it looks like I have an
unterminated string here I need to go
ahead and now add this double quote so
let me go ahead now when with that red
herring gone let me rerun python of
name. piy and hit enter and now we see
too few arguments okay maybe it wants my
full name let me go ahead now and run
python of name. py David maen typing in
both words after the name of the file
and hit enter and now of course it's too
many arguments fine now I'll oblige and
do python of name. py and just David and
there we have it my name tag printed on
the screen so strictly speaking we don't
have to handle exceptions if we can be a
little smarter about it and just check
for the things that we're worried about
especially if we want to give the user
more refined advice we don't want to
just tell them no something went wrong
or we don't want to pass we want to tell
them no that's too few or no that's too
many we have conditionals in our
vocabulary already via which we can now
Express that well let me pause here and
see if there's any questions now on how
we handled the error before with the
index error or how now we're just
proactively avoiding all index errors Al
together by just checking first first is
it too few is it tooo many or is it
exactly what we want hi thank you um so
I was wondering you you touched upon
kind of using your full name um could we
could we then um is there a way going
forwards that perhaps we uh have people
that want their full names and want
their just their first name that we
separate that into like oh this person
has full name this person has just the
one
name absolutely and allow me to is uh
allow me to propose we come back to that
support for multiple names um but indeed
we could do that and I should note too
though we can support full names right
now if I do this instead of typing in
David space mailin which is problematic
because again by definition of how argv
Works each word ends up in a specific
location in the list but if I add quotes
single quotes or double quotes at the
command line now python will view this
as two total things the name of the file
and this full name name and now when I
hit enter I don't see the quotes the
whole thing is passed in as my full name
and if I want to adapt this further for
multiple people we'll be able to do that
as well other questions now on this
version with if L if else or on accept
before hi I want to I want to ask you uh
can we use multiple else statements can
you use multiple El's statements no else
is the last catchall statement that you
can have you can have multiple L if
statements in the middle but not
multiple
elses all right all right well let's
turn our attention back now to this code
and see if we can't refine it a bit more
by adding in some additional
functionality that we get with modules
like the CIS module one of the things I
don't love about this version of the
code even though arguably it is now
correct is that the essence of my
program which is just to print out the
name tag is kind of relegated to this
else clause and that's fine logically
it's correct but generally speaking
there's something nice about keeping all
of your error handling separate from the
code that you really care about having
all of these ifs L ifs perhaps at the
top of your code that are checking to
make sure that all of the data is as
expected but then it would be nice if
only for design sake not to sort of hide
in this El statement the actual code
that you care about I would prefer for
instance to do something logically like
this I could check for errors up top and
then down here print the name tags it
would be nice if those are sort of
distinct blocks of code all of which are
here left aligned but there's a problem
with what I've just done here logically
what bug did I just introduce by getting
rid of the Els and introducing line 10
on its own with no indentation outside
of the conditional what bug have I just
introduced what mistake to be
clear um name error ironically it's a
name error but not a name error
exception it's an error with my name
but I think you're Frozen for me it's
going to raise an exception because even
though I'm checking the length of
cis.org V up top and even though I'm
checking it again for being greater than
two not just less than two but greater
I'm still then blindly and incorrectly
assuming it's now going to exist so just
to be clear if I run python of name. and
I don't type any arguments I've got too
few I think I'm going to see that I have
have too few but I'm also going to see
that same exception at the very top of
my terminal Windows output there's my
error message to few arguments but again
on line 10 I blindly proceed to still
index into my list at location one which
does not exist so it turns out there's a
better way to handle errors like this
especially if you're writing a program
in Python that's just meant to run
briefly and then exit anyway but maybe
we could start to exit prematurely if
the program itself just can't proceed if
the user has not given us the data we
want perhaps we should just exit the
program earlier than we might otherwise
so let me go ahead and do this let me go
ahead and remove my comments so as to
focus only on the code here and let me
propose that instead of just printing
quote unquote twoo few arguments I'm
going to use one other function that
comes with the CIS module I'm going to
go ahead and call cy. exit and as the
name suggests it's going to do exactly
that with the system's help it's going
to exit my program then and there on
line 4 why is that okay well if you gave
me too few arguments I have nothing more
to say to you the user I might as well
exit a bit prematurely and I can do this
as well on line six let's go ahead and
not just print that but sis. exit quote
unquote too many arguments print out
that message and just exit right there
now I can trust that by the time I get
to line eight every error condition has
been checked for and so it's safe for me
to assume that there is in fact and a
item at location one in cy. argv so let
me go ahead now and run this python of
name. py enter too few arguments but I'm
back at my prompt nothing more has
happened let me run it again python
of.pie David maen with no quotes enter
too many arguments is now printed here
finally python of name. py just David
enter hello my name is David so we have
then insist two forms of functionality
now we have access to this variable sis.
arv this argument Vector that gives me
all of the words that were typed at the
prompt including the program's own file
name and it turns out if we read further
in the documentation there's an exit
function that can take different types
of inputs but if I pass it a string like
this it will indeed print that string
for me and then exit from my program
then and there questions now on exiting
from programs like this to be clear all
of this time once python gets to the
bottom of your file it's going exit
anyway so I'm using cy. exit now just to
make sure that I exit earlier than
otherwise um my question is about the
cis.org
arv so is that capable of accepting or
taking multiple elements at once let's
say for example uh python name thatp
David Malon I'm a male uh 20 years old
and if let's say I only want to access
your name which is at the first index
and then your your your age is pro say
at the sixth index can I say sis. RV one
and another one for six to access what I
just want is that possible for CIS RB uh
short answer yes I think if I understand
your question correctly whereby you're
proposing to have many words at the end
of the command and you want to access
those individual words absolutely at
some point it gets a little fragile I
would say if you're typing so many words
at the prompt that the order really
matters and so it turns out there's a
lot of programs and there's
functionality in Python that can allow
you to provide those values like name or
age or any number of other fields in any
order you want but pass in a bit more
information textually that tells the
program how you want to use it so in
short what you're describing is possible
and let me do a small incarnation of it
as follows let me propose that we go
back to my code here and let's propose
that we actually now want to support
multiple values at the prompt so there's
going to be no such thing as too many
arguments suppose that I want to
generate name tags not just for David
but for David for Carter for Rong Shin
for others in the group who all want
their name tags as well so I'm going to
go ahead and do this I'm going to get
rid of my L if condition because I don't
want to limit the maximum number of
words that are typed at the prompt
anymore I instead want to iterate over
every name at the prompt so I'm going to
say this for Argin sis. argv go ahead
and print out this time ARG so what am I
doing here well even though the syntax
is a little different the idea is the
same as before when we've had Loops I'm
using a for Loop to iterate over a list
the list in question here is cy. argv
ARG is a variable that I'm creating on
the Fly the for Loop is going to make
sure that the first time through this
Loop AR is set to the first word on the
command line the second time through the
loop Python's going to make sure that
ARG is now set to the second thing on
the command line and so forth that's
just how a for Loop works it updates the
variable for us I don't have to call it
ARG I could call it name so long as I
change it to name in both places but ARG
is reasonable if I'm iterating over
arguments more generally if I now run
this program though unfortunately
there's a little bit of a bug even if I
type in David and Carter and wrong Shin
I'm not going to get just just three
name
tags in your mind does anyone see the
bug I'm about to trip over it's not a
huge deal if I've got enough name tags
to go around but I'm going to be wasting
one because this is going to print not
three but four name tags whereby the
first contains the name of the program
itself maybe not a big deal maybe that's
the sticker we don't bother handing out
but it's wasteful and it it does look
wrong so how could we get access to not
all four elements of argv but just a a
slice of Arvy and this is actually a
technical term in Python and some other
languages to take a slice of a list
means to take a subset of it maybe from
the beginning maybe the middle maybe the
end but a slice is a subset of a data
structure like a list well how do I
actually do this in code well in Python
it's actually very easy to take a slice
of a list that is a subset thereof you
can simply do this at the end of the
list name cy. Arvy in this case you can
use square brackets and then in those
square brackets you can specify the
start and the end of the list that you
want to retain I want to start at
element one not zero I want to start at
element one and I want to just go to the
end so I'm actually going to Omit a
second number altogether it's not
necessary to have a second number but I
do need that colon because this is going
to give me a slice of the list it's
going to give me a slice of the list
that starts at location one not zero and
the colon and then a blank just means
it's going to give me everything else so
this is equivalently going to slice off
the first element of the list and give
me a new list that contains just those
three human names not the name of the
file itself let me try running this
again I'm going to run python of name.
py David Carter wrong Shin this time
hopefully I'm going to get three and
only three name tags hitting enter and
indeed I've done now just this so again
using some relatively simple syntax in
Python we can use square brackets not
just to go to specific elements like
bracket zero or or bracket one we can
also get subsets of the list slices of
the list by doing bracket something
colon Something where each of those
somethings is a number the beginning or
the end and they're optional depending
on whether you want all of them or just
some any questions now on this version
which adds the loop and these slices
with that new
syntax can we slice starting from the
end of the argument argument Vector you
can you can slice something from the end
of the argument vector and this might uh
this might blow one's mind a little bit
let me go ahead and do this uh let's see
let me go ahead and do negative one at
the end using a negative number here and
running the same command we've just
uninvited wrong Shin from receiving a
name tag here so if you use a negative
number it has the effect of counting to
the uh in the other direction from the
end of the list a good question there
other questions now on slices on looping
over cis.org
V hi uh so I remember very early on uh
when we were talking about uh only
having two decimal places in uh in an um
float value um does this is is that in
the same vein like um because we use the
the colon
2f uh so that's is that the same thing
then uh why would the F be included then
in the point 2f as opposed to here when
you just have the
numbers a really good question and it's
just the short answer is that context
matters so there's only so many keyo
keys on our keyboard and so we sometimes
use the same symbols for different
things so what you're alluding to is the
format code in in F string for actually
formatting a number using a colon using
a period using a number using the letter
F and so forth and that is very specific
to the F string feature of python this
case has nothing to do with any of that
syntax per se this is just using a colon
in a different context to solve this
problem to implement a slice the authors
of python could have chosen another
symbol but honestly looking down at my
keyboard here we don't have that many to
choose from that are easy to type so
sometimes they have different meanings a
good question as well allow me to
propose now that we take things further
and move away from using only those
modules those libraries that python
comes with to talk about more generally
packages that exist one of the reasons
that python is so popular and Powerful
these days is that there's a lot of
third-party libraries out there as well
otherwise known as packages strictly
speaking python itself has a term of art
called a package which is a module
essentially that's implemented in a
folder not just a file but a folder but
more generally a package is a
third-party library that you that I can
install on our own Mac or PC or our
Cloud Server and gain access to even
more functionality that other people
have implemented for us now one of the
locations you can get all of these
packages is called the pii uh website
the python package index which lives at
this URL here and this is a website that
is searchable via the command line as
well as via the web that allows you to
download and install all sorts of
packages even cs50 has some of its own
packages um in services like these now
there's a fun one out there that's a
throwback to a command that's been
around for years in command line
environments called cow c is a package
in Python that allows you to have a cow
say something on your screen if curious
to read up on it its own documentation
is on p.org specifically at this URL
here but how do you actually get the
package into your system well
technically you could figure out how to
download the file and maybe unzip it and
put it into the right location on your
Mac or PC but nowadays a lot of
languages python among them has what's
called its own package manager this one
here called pip which is just one so pip
is a program
that generally comes with python itself
nowadays that allows you to install
packages onto your own Macs or PCS or
Cloud environment by just running a
command and then voila you have access
to a whole new library in Python that
didn't come with python itself but now
it's available on your system for you
let's go back to vs code here and in my
terminal window I'm going to go ahead
and type pip install cow now what's
going on here pip is the command the
package manager and I want to install
what package the package called cow I'm
going to go ahead and hit enter here and
after a little bit of output it has
successfully installed C now what does
that mean that means I can now go about
importing this into my own code well
let's go ahead and see what this means
let me go ahead and create a new file
with code called say dopy because I want
something to be said on the screen and
in my new tab here I'm going to go ahead
and import C which presumably is now
installed I'm now going to import CIS as
well because I'd like to use some
command line arguments in this program
just so that I can run it quickly and
without using the input function I can
get the user's name immediately from The
Prompt and let me go ahead and do this
I'm going to do a bit of error checking
proactively this time and rather than
use less than or greater than I'm this
time going to say if the length of
cis.org V does uh does equal two so if
the human is provided just the name of
the program and their own first name
we're good to go I'm going to do the
following I'm going to call a function
called cow in the package called coway
and I'm going to pass in a string hello
comma and then as in the past I'm going
to pass in just one string because
according to its documentation it's not
like print I can't pass in comma this
comma that I can only pass in one string
so I'm going to concatenate the contents
of sis. argv bracket1 so long as then I
type in my name David after the name of
this program it should end up in cy.
arv1 one in which case this line five of
code should concatenate hello with my
name with a space in between and
apparently a cow is going to say it so
let's see what happens here let me go
ahead and clear my screen and increase
the size of my terminal window let me go
ahead and run python of say. py and type
my name David and enter there is the
program called coway it literally has a
cow say something on the screen and this
is a throwback to a program from yester
year that tended to come with a lot of
syst sys um this is otherwise known as
asky art it's a textual way using just
keys on your keyboard to print pictures
of sorts on the screen now we can really
go down the rabbit hole here and there's
questionable academic value of doing so
so I'll do so just once turns out the
coway package comes with other functions
as well one of those functions for
instance is T-Rex and if I now increase
the size of my terminal window we'll
perhaps see where we're going with this
let me now run again python of.pi this
time let me not provide my name just to
see if it's broken it's still okay
because we have that if condition if the
length of cy. RGV equals equals two and
only if it equals equals 2 do we do
anything that's why we're not seeing
anything here let me go ahead and
cooperate now say. piy space David and
it's no longer a cow but if I zoom out
on my screen a T-Rex why just because
these are the things you can do once you
know how to program you can even package
them up and make them freely available
to others as open source software for us
it's demonstrative of a feature more
generally here namely being able to
install these thirdparty packages and
how you might do so in Python now I'll
leave this up on the screen for a moment
and see if there's any questions about
cows or Tyrannosaurus Rexes or packages
more
generally I'm really qualified to speak
to just one of
those hi um I've got two questions it's
a bit earlier than what it's supposed to
be um so the first question
is the the packages that you calling um
U to uh use in the program are they the
same as um let's say because I'm doing
Java um the same as calling a class of a
Java file in order to use its
functions and my second question is
what's the actual purpose of using
command arguments as you used because
it's not really the best way
to uh as you say be user friendly where
as in let's say the person who's using
the program doesn't know what it what
they want what the the program's asking
them really good questions the first
question about the comparison with Java
python packages are similar to Java
packages where you have something do
something do something at the top of
your program that gives you access to a
class or something else python itself
supports classes more on those down the
road and you can do very similar things
in python as you can do with Java but
the analog really is python packages to
Java packages here as for command line
arguments you ask a good question why do
we use them especially if they're a
little less user friendly they're a
little less user friendly to people who
aren't in this Zoom to be honest you and
I as we learn more and more about
programming and more about command line
arguments I dare say will become more
comfortable with and tend to prefer the
ability to customize commands using
these commandline arguments why
productivity it tends to make you faster
because you get into the habit of
knowing exactly how you can configure
your software without having to manually
answer questions and case in point all
of this time uh have we been running
python of something. py you could
imagine not doing that you could imagine
typing only python hitting enter and
then you're prompted for the name of the
file you want to run so you type in
something piie and then it runs not a
big deal but I I would argue that over
time you're going to get a little tired
of that tedium and you would much prefer
to just automate the command again and
again and again especially with little
conveniences like being able to hit up
and down in your keyboard history so as
to rerun those same commands automation
is Big too if you emerge from a class
like this and start using python to
automate processes at work or for
personal projects or the like the
ability to specify all of your inputs on
the one line just means you can get work
done more quickly so so hands down
absolutely using commandline arguments
is a more Arcane uh feature of systems
that most of us are no longer as
familiar with because of Windows and Mac
OS and other operating systems that have
buttons and goys and menus but the more
comfortable get you get with programming
I dare say the more you will tend to
prefer these capabilities because they
allow you to do things more quickly with
that said allow me to propose that we
take a turn toward yet another package
that's particularly popular and just as
easy to install all toward an end of
using apis now apis are not something
that's python specific more generally an
API is an application programming
interface and it can refer to python
files and functions but often apis
really refer to third-party services
that you and I can write code that talk
to many apis but not all live on the
internet these days so that so long as
you have a browser or so long as you
have some experience with Python
Programming or programming in any
language you can write code that in
effect pretends to be a browser connects
to that thirdparty API on a server and
download some data that you can then
incorporate into your own program now
how do you do this well python has a
very popular package that you can
install via pip called requests the
requests Library allows you to make web
requests internet requests using python
code essentially as though you were a
browser yourself you can automate
therefore the retrieval of URLs that
start with HTTP or https the
documentation for this library is at a
URL like this but it too can be
installed at the command line and even
though it's third party it's one of the
most popular and commonly used packages
out there in Python and this too is one
of the reasons again that python is so
popular there's just so many solutions
to problems that you and I have or are
invariably going to have when we write
projects of our own there's just a
really vibrant EOS system a really
Vibrant Community of Open Source
software that's that easy for us to
install let me go back to my terminal
window now and run pip install requests
in order to install this package on my
own system and after some lines of
output I'll see that it's successfully
installed now let's go ahead and create
a new file here for instance
itunes. it turns out that Apple has its
own API for their iTunes service the
software that provides you with the
ability to download and search for music
and songs and other information as well
and it turns out that let me go back
over to my computer here and open up a
browser like Chrome and let me go ahead
and visit this URL here https col
itunes.com
search question mark entity equals song
Ampersand limit equals 1 Ampersand term
equals Weezer now I constructed this URL
manually by reading the documentation
for Apple's API application programming
interface for iTunes and what they told
me is that if I want to search for
information about songs in their
database I should specify entity equals
song so that it's songs and not albums
or artists or something like that if I
just want to get back information on one
song I'm going to provide limit equals
one and if the band I want to search for
the artist is Weezer I should specify
term equals Weezer so with this if I go
ahead and hit enter and visit this URL I
actually end up with a text file in my
downloads folder on my Mac if I go ahead
and open that text file that my browser
just downloaded we'll see all of this
text here which at first glance might
look a c bit cryptic but it actually
follows a pattern notice this curly
brace at the start and notice this
closed curly brace at the end notice
this open square bracket here and notice
this closed square bracket here and in
between those pieces of syntax are a
whole bunch of strings and values in
fact a whole bunch of key value pairs
what we're looking at here is a standard
text format known as Json JavaScript
object notation which yes is technically
related to yet another programming
language called JavaScript but Json
itself is typ typically used nowadays as
a language agnostic format for
exchanging data between computers by
language agnostic I mean you don't have
to use JavaScript you can use python or
any other language to read Json or write
it as well and it's a completely
text-based format which means that if I
visit that URL with my browser what gets
downloaded is just a bunch of text but
that text is formatted in a standard way
using curly braces and square brackets
using quotes and some colons that
ultimately contain contains all of the
information in Apple's database on
Weezer song at least the first one CU I
limited it to one in their database and
that's an API an application programming
interface a mechanism whereby I can
access data on someone else's server and
somehow integrate it into my own program
now of course my browser Chrome is not
something I wrote I should actually
write some python code that perhaps
pretends to be a browser to grab the
same data so let's do that let me go
back to vs code here and let me write a
program with code itunes. and we're
going to write some code via which I can
then use the iTunes API and in turn
python to get information about any band
that I might want I'm going to go here
and import first the requests Library
which I installed earlier in order to
make those HTTP requests I'm going to go
ahead and import the CIS Library via
which I'll have the ability to use
command line arguments like
specification of the band that I want to
search for if not Weezer and then down
here I'm going to go ahead and insert
some error checking to say if the length
of cy. argv does not equal to so if the
user does not provide me with the name
of the file they want to run and the
name of a band and that's it you know
what let's just go ahead and exit for
now I could provide a more explanatory
message but for now I'm going to keep
things simple and just exit the program
prematurely so that I can trust
Hereafter that cy. arv has what I want
and now I have the opportunity to use
the requests library to write some
python code that effectively is
pretending to be a web browser so as to
connect to that same https URL on
Apple's own server so now that I've
guaranteed that the user has typed in
not just the name of the file but also
the name of a band at the prompt giving
me a length of two for cis.org V let's
go ahead and execute requests.get which
is a function inside of the requests
package that will literally get some
response from a server and the URL that
I want to get is the exactly the same as
before
https itunes.com search question mark
entity equals song Ampersand limit
equals 1 Ampersand term equals
previously Weezer but let's make this
program a little interactive and
actually allow the human to specify at
the command line what artists they'd
like to search for so I'm going to go
ahead and close my quote early and just
append using the concatenation operator
as in the past
sis. Arvy bracket1 and now it'd actually
be nice to store the response from the
server in a variable so I'm going to go
ahead and say response equals and to
store all of the response that comes
back from the server in a variable
called response down here now I'd like
to just understand what the server is
returning to me to make sure I know how
next to proceed so this isn't going to
be very pretty yet but I'm going to go
ahead and print out response. Json which
ensures that the data I'm getting back
is formatted on my screen as is exactly
that Json the same text format as we saw
on my screen it's not a useful program
yet I'm really just learning along the
way but let me go ahead now and increase
the size of my terminal window and run
python of itunes. and type in the name
of a band like Weezer and hit enter and
what we see on the screen formatted
almost the same as before is exactly
that same text but what you'll see here
is that this has been standardized now
as a python dictionary what indeed
Apple's returning is technically
adjacent response JavaScript object
notation but python the request library
is converting it to a python dictionary
which happens to use wonderfully
coincidentally almost the same syntax it
uses curly braces to represent the
dictionary here and a closed curly brace
to represent the end of it here for any
lists therein it uses a square bracket
here and a closed square bracket down
here it uses quotes single quotes in
this case or equivalently double quotes
to represent the keys in that dictionary
and after a colon it stores the value of
that key and so you'll see that indeed
we have a result count key whose value
is one but then a more interesting
result key called results whose value is
this entire list of data now honestly
this is such a big blob of text that
it's going to take me forever to wrap my
mind around what I'm seeing so let me
propose temporarily we use another
library in Python that will allow me to
format my data a little little more
cleanly it turns out that python also
comes with a special Library uh called
Json that allows you to manipulate Json
data and even just printy print it that
is format it in a way that's going to be
way easier for you and I to understand
so let me go back to my code here let me
shrink my terminal window and let me
propose that just temporarily again we
do this let me import this additional
Library Json which comes with python so
I don't need to install it manually with
Pip and let me go ahead now and not just
print out response. Json which was that
Big Blob of hard to understand text let
me go ahead and use one other function
here called json. dumps for dump string
and pass to that function that response.
Json return value so again I'm just
introducing another function who I claim
it has a purpose in life of pretty
printing nicely formatting on the screen
the exact same information and I know
this from the documentation having done
this before but I'd like things to be
nicely into Ed and according to the
documentation if I pass in a named
parameter of indent equals 2 that's
going to indent everything at least two
spaces I could do four or something else
but it's going to be enough to help me
wrap my mind around what the data is I'm
getting back because again I'm just
learning along with you so let me
increase the size of my terminal window
again let me run python of itunes. and
again let's search for Weezer and hit
enter and now notice it's still a little
bit cryptic because there's a lot going
on here but my gosh I can totally read
this more easily now notice now that I
still see the first curly brace which
means hey this is a dictionary in Python
a collection of keys and values the
first key is called result count it
happens to be displayed in double quotes
now but that's just an issue of
formatting it could be double or single
so long as we're consistent the value of
that key is one why well I told the URL
to only limit the responses to one
Weezer song so I've gotten a result set
of one if I increase that limit I could
probably get more
then the interesting part of this
response is really the data itself
notice in the res results key here
there's a really big value the value is
a python list as
implied by this square bracket what does
this list contain well I know from
skimming it earlier that this contains
one dictionary and that's why we see
another curly brace here so again if
this gets a little more complicated keep
in mind that a dictionary is just a
collection of key value Pairs and python
uses curly braces to indicate as much it
is perfectly reasonable for a dictionary
to be inside of another dictionary if
the value of some key itself is another
dictionary so this is a common Paradigm
and even though it might seem a bit
cryptic it's just something that allows
us to associate more keys with more
values now most of this information I
probably don't care about for instance
according to Apple the unique identifier
for Weezer is apparently 115,000
234 that might be useful if I'm making
my own database and I want this to be
searchable but for today's purposes all
I care about is the name of the track
otherwise called track name as key and
the first song and only song because we
limited it to one that we got back from
iTunes here is the song that you might
know by Weezer called Say It Ain't So so
now I have a bit of a clue if my goal
here is to implement a program called
itunes. that doesn't just dump the
response from the which is admittedly
very cryptic but to print out all of the
songs that iTunes has for the band
called Weezer maybe I can iterate over
this somehow so let me backtrack here's
the key called track name it is inside
of a dictionary that is the value of
results here so how can I go about
getting this well let me go ahead and
try this let me go ahead and Shrink my
terminal window back down and let me
propose now for one final flourish we
don't just lazily print out the contents
of that response because that's not
interesting or pretty for anyone let's
do this let me go ahead and create a new
variable just for the sake of discussion
called o for object and I'm going to go
ahead and call uh o equals response.
Json just to store that Json response
specifically in a variable called o but
I could name it anything I want and now
I'm going to do this for each result in
that object's key called result
go ahead and print out that results
track name and notice I have used
exactly the same capitalization track
name has a capital N results is all
lowercase and let me rewind before we
run the actual program in line eight we
are making an HTTP request using python
to the server just like you and I as
humans type URLs into a browser and hit
enter this is the python equivalent
there of I am then on line 10 just
grabbing from that variable that
contains the server's respon
the Json object that I care about the
thing between those curly braces at the
very top and the bottom but because
we've poked around and because I read
the documentation earlier I know that
that object has a key called results and
that results key again is a list now at
the moment that list contains only one
song Say It Ain't So because I limited
my response to one but even so my Loop
will work it's just going to iterate
once and each time through that loop
it's going to print the current results
track name if I want to make this even
more interesting let me change this
limit now from one to 50 so I'll at
least get back 50 track names instead
let me go ahead now and increase the
size of my terminal once more and go
ahead now and run python of itunes.
searching again for a band like Weezer
and here we go and voila there are 50
songs that iTunes has for Weezer and if
we scroll back up to the top here we'll
see that the very first one there is
indeed say it ain't so but now we got
undone The Sweater Song Buddy Holly
apparently another rendition of Say It
Ain't So perhaps from another album
another Buddy Holly undone my name is
Jonas and so forth questions now on this
program which integrates python with a
real world third party
API yeah hi uh can we use breake instead
of system. exit exit good question but
no um break again is used to break out
of things like Loops like we saw ear
clear cy. exit is used to break out of
the whole program itself use break for
Loops for now and use cy. exit to
terminate the whole program good
question other questions now on this
program are others from where we bring
the name of the key results from where
do we get the name of the key uh results
itself yeah can we change the results
name you cannot so we could in our
program so the keys that come back in
that Json response to be clear come from
itunes. apple.com some engineer some
team of Engineers decided for us what
all of those keys would be called
including track name results result
count and everything else you and I can
absolutely store those same values in
variables just like I'm doing here with
o just like I'm doing here with result
you can rename those keys anything you
want using python variables but the Json
response is coming from that thirdparty
server other questions yes sir sir uh I
have a question related to to C package
so like uh yes so sir what sort of ask
Graphics is it capable of outputting the
coway package um I would refer you to
the URL in the slides earlier uh if only
because it's more thorough they have not
just cows but Tyrannosaurus Rexes and
several other animals as well I should
emphasize that this is not a package I
suspect you will use much in the real
world it's really just meant to be
representative of the types of packages
you can install but allow me to refer to
the documentation for what more is there
but aski artart uh is the all we had
before there were emojis let alone gifs
and jpegs and pings but it's what's is
immortalized in C well allow me to
transition us back now to one final
capability of python which is that you
yourselves have the ability to make your
own libraries up until now we've been
writing all of our functions in our one
file hello pi and everything since and
now that we've introduced modules in
Python like random and statistics we can
import those that come with python but
that's other people's code as well and
we've now used Pip this package manager
to install third- party packages as well
in the system and using other people's
code still but to come full circle what
if you yourself find yourself
implementing the same kinds of functions
again and again or you find yourself
opening up old programs copying and
pasting code you wrote into new programs
because you have the same problem yet
again a good practice would be to
somehow bundle up that code you keep
reusing and make your own python module
or package you can keep it local on your
own Mac or PC or Cloud Server or you can
go through the steps of actually
bundling it up making it free and open
source and putting it on something like
pii for others to use as well okay I'm
going to go ahead and run code of
sayings. py to create a brand new file
called sayings dopy which is going to be
my own sayings module and I'm going to
define a couple of simple functions in
there I'm going to define a hello
function that's going to take name
parameter is input and that function is
simply going to print out an F string
that contains hello comma and then in
curly BRAC whatever that person's name
actually is then I'm going to go ahead
and Define one other function a goodbye
function that has def goodby also takes
a name as its input and then that prints
out by contrast an F string that says
goodbye comma and then in curly brace's
name and now just for good measure just
so I can be sure that these functions
are working as expected I'm going to go
ahead and Define a main function in here
too just for the purposes of testing and
I'm going to go ahead and Define a main
function that simply does a couple of
tests for instance it calls uh hello of
quote unquote worlds shall we say and
then it's going to call goodbye of quote
unquote world as well and hopefully what
I'll see on the screen then is hello
world and goodbye world when I run this
program of course as always I need to
explicitly tell python to call that
function so I'm going to call Main at
the very bottom of this file all right
all right let's try it out python of
sayings. py enter and indeed I see Hello
World and goodbye world and so I think
it's reasonable for me to assume that
these functions albeit simple are pretty
correct at this point but now suppose
that I want to use these functions as
though I've indeed created my own
Library my own python module that makes
available a hello function for me or
anyone else who wants to use it or a
goodbye function as well well let me go
ahead and open up again say. py but
start fresh and rather than have the C
say anything let me go ahead and have my
own Library do the talking so I'm going
to go ahead and as before import CIS so
that I have access to command line
arguments and from my own module called
sayings I'm going to import hello so
because I created a file called sayings.
py I can say from sayings and it's
inferred by python that I mean sayings.
py at least in this current directory
but I specifically going to import just
one of the functions for now namely
hello and now I can do something like
this if the user obliges by giving me
two command line arguments which I can
check by just checking the length of cy.
argv I'm going to then go ahead and call
this new hello function passing as its
input assist. arv bracket one which
should hopefully be the person's name
which I'm going to expect them to type
at the prompt so here we go I'm going to
go down to my terminal window run python
of s.p and my own name because I want my
own name to end up in the command line
arguments and therefore be part of the
hello so when I hit enter and just a
moment I should hopefully see hello
comma David so here we go enter and huh
I see Hello World Goodbye World and then
I see hello David so why is this
happening well it turns out even though
I've done everything according to our
own past practice it's not really the
right way to go about calling Maine
after all if I'm blindly calling Maine
here at the bottom of my file that means
whenever this file is loaded by python
Maine is going to get called and
unfortunately that's true even if I'm
importing this file or just a function
from this file as I am here in my s.p
program this is to say on line three
here when I say from sayings import
hello this effectively tells python to
go find that module sayings. py read it
from top to bottom left to right and
then import specifically the hello
function unfortunately by the time
python has read the file from top to
bottom left to right that last line of
code recall is to call Maine Maine gets
called no matter what so really the
right way to go about using a main
function which does solve that problem
of ensuring that we can order our
functions however we want and all the
functions will be defined at the time
they're invoked I shouldn't be
unconditionally calling main at the
bottom of this or really any of my
programs I should instead use this
technique I should say if underscore
underscore name underscore underscore
equals equals quote unquote underscore
uncore maincore uncore close quote then
and only then should you actually call
Main well it turns out that this
variable is a special symbol in Python
underscore uncore name underscore
underscore and notice that vs code
because of its font isn't quite showing
those two underscores but they're indeed
there to the left and the right this is
a special variable whose value is
automatically set by python to be quote
unquote main when you run a file from
the command line as by running python of
sayings. piy so Watch What Happens now
with this additional conditional in
sayings. py if I run python of sayings.
py it still works as before because name
will be automatically set to underscore
uncore maincore uncore when I run this
file using python ofs sayings. py but
notice this name is not going to be set
to quote unquote main it's going to be
set to something else technically the
name of the module when I instead import
the file like I do here so this
highlighted of code even though it will
cause python to go find sayings. py read
it from top to bottom left to right it's
going to ignore the call to main this
time because it's wrapped in that
conditional in this case when I'm
importing a file and not running it
directly at the command line Maine will
not get called by definition of name's
value so let me go ahead and try this
instead of running python of sayings. py
which is the module which contains that
conditional main let me go ahead here
and run python of say. py which is the
program here before me that Imports
hello from sayings but because of that
conditional it's not going to say hello
to anyone else except me in this case
all right we're here at the end of our
week it's only appropriate I think to
import something other than hello why
don't I go ahead and import not hello
but goodbye from here let me go ahead
and call goodbye instead of hello and
this time when I run python of sayy I'm
not going to type my own name allow me
if I may to type in the whole world so
that our final sentiment today is
goodbye World indeed that's it for this
week we will see you next time
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men and this is our week on unit tests
up until now we've been writing a lot of
code and you might have been testing
your code by running your program and
passing in some sample inputs and
running it again and passing in some
sample inputs or you might have been
waiting for us to test your code instead
but it's actually much better practice
to get into the Habit sooner rather than
later of testing your own code using
Code of your own in fact whether you're
writing a personal project or working in
industry it's very common nowadays to
not only write code to solve the
problems that you want to solve but also
to write a little extra code to test the
code that you wrote and that's what
we're going to focus on today writing
our own test so as to be all the more
confident all the more certain that the
problems we have been trying to solve
are in fact solved correctly so let's
rewind a few weeks now to a program we
wrote a while back namely to to
calculate uh numbers and specifically we
left off with this calculator on trying
to compute the power of a number like X
squar or uh where X might be two or
three or some other number as well well
let me go ahead and resurrect that file
by going into my terminal window here
and running again code of calculator. Pi
and let me go ahead and pick up where we
left off way back when by defining a
main function here and then in my main
function I did something like this I
said x equals int of input and I asked
the user what's X question mark and then
I immediately went ahead and printed out
something like x^2 is and then I passed
in as a second argument to print the
result of calling a function called
Square passing in that value X now of
course I haven't yet implemented the
square function so let's define that as
well let me go down a couple of lines
and Define square and it takes an
argument recall a parameter that at the
time I called n for number so I'll do
that again though I could technically
choose any name for this variable and I
call did this I returned n * n and there
were multiple ways to do this the
squaring a number is multiplying it by
itself so I could also use other syntax
here but this is what we ultimately
settled on and then recall that I
ultimately called Main in order to kick
off the process of running this program
so just as a test manually let me go
ahead and run python of calculator. piy
and hit enter what's X let's start with
two all right x^2 is 4 I think that's
correct so let's run it again just for
good measure of calculator. Pi let's
type in three for X this time x^2 is 9
and I think that's correct and I might
be feeling pretty good at this point and
I go off and submit my code to a course
or I post it on the internet for others
to use but I haven't really methodically
tested this code and it's not
necessarily the case that it works
entirely in fact I haven't really
considered a number of corner cases I
went with some pretty obvious numbers
like two and three but what about zero
what about negative numbers what about
any number of other infinite numbers
well we're not going to test infinite
number of inputs to this because the
program would never halt but we should
test some representative inputs
ultimately but before we do that let's
get into the habit of making sure that
Maine isn't always called let's adopt
this habit again of doing if underscore
uncore name underscore underscore equals
equals quote unquote underscore uncore
maincore underscore only then should we
execute Main and I'm doing this now
proactively because I want to make sure
that when I import my Square function
perhaps from another library from
another file treating it as though it's
a library I want to make sure that main
is not just automatically called itself
now what do I want to do from here now
that I've modified this program as
follows well let's go ahead and write a
completely different program whose sole
purpose in life is to now test this
program so I've got my actual calculator
in calculator. I've readed myself to
call Main conditionally so that I can
safely import one or more things from
this file in another file well what
should that other file be well by
convention I'm going to create a file
that's called test underscore and then
because the thing I'm testing is this
calculator itself let's call this file
test calculator. piy that's going to
give me a new tab in which I can write a
brand new program whose purpose in life
is now specifically to test that program
but really that program's specific
functionality built into that program is
the square function let's focus on
testing that function all right so how
do I access that function in this
program well recall that I can import a
function from another file as though
it's a library of my own a so-called
module so I'm going to do this from
calculator import Square I could go
ahead and just import Square itself but
then I would have to prefix my use of
square recall by saying calculator dot
everywhere and it's just a little
cleaner to just import the one function
and now let me go ahead and do this let
me go ahead and Define a function called
test Square this two is a convention if
you want to test a function called
Square your function for testing should
be called testore Square or
alternatively you could do Square
underscore test but I'll adopt this
convention here now what kind of tests
can we do well I don't dislike the test
I ran earlier testing xals 2 and x
equals 3 but every time I uh want to
test my program previously I would have
to do that manually and that's going to
get tedious it's not going to be easy
for someone else to test it and if I'm
actually working in the real world it
would be nice if I could automatically
have my program tested again and again
by having some automated process run my
own code so let's do that and take the
human ultimately out of the equation so
how might I go about testing the square
function that I've now imported per line
one well in my test Square function why
don't I do this if uh the result of
calling square of two does not equal
four why don't we go ahead and print an
error message because I know that in the
real world 2 squared should equal four
so if square of two does not equal four
there's a bug in my program there's a
bug in my function I've made a mistake
so let me go ahead and print something
like that so I or someone else knows 2^2
was not four for instance so I could
print out anything here what should I
maybe next test well let's do more than
one test let's say if the square of
three does not equal 3^2 9 then let's go
ahead and print out that 3^ SAR was not
9 so I haven't done any more testing
than I did earlier but I've baked those
two tests xal 2 and xal 3 into my own
code here so I can now run those tests
automatically if you will now it's not
enough to just Define a function called
test Square I actually if I want to run
this function need to call it somehow
and our convention for doing that is the
same as always in this function here in
this file two let me Define Main and
Main's sole purpose in life is going to
be to test square and now at the bottom
of this file as before let me go ahead
and adopt my Convention of if underscore
uncore name underscore uncore equals
equals quote unquote underscore uncore
maincore uncore then go ahead and call
Main so a lot of this is just
boilerplate like we've seen this before
defining a main function and calling a
function to kick off some process now
adding the conditional at the bottom of
the file to make sure I'm only
conditionally calling main just in case
I import anything from this file
elsewhere so let's see let's go ahead
and test my code now let me go ahead and
run test calculator with python and hit
enter and nothing outputs nothing
outputs but I think it's okay I think no
output is good because look at my test
Square function I'm not printing
anything if all seems well so let's
let's demonstrate as much by going back
to my calculator and let me break it let
me introduce a bug maybe I didn't even
get it right the first time maybe my
code originally looked like this I
wasn't thinking I forgot my squares and
so I thought that the square of a number
is n plus n instead of n * n so a
reasonable mistake to make perhaps
arithmetically let me now go back to my
test calculator which which I'm not
going to change but I am going to rerun
it python of test calculator. Pi going
to cross my fingers here but for not I'm
going to see immediately that 3^ SAR was
not n now what is it well let's see when
your tests fail how can we put our
finger on what's wrong well it's a
little interesting that I completely
broke my Square function and yet only
one of these tests is failing it looks
like this test lines 9 and 10 is fine
because I'm not seeing that output but
of course these two lines this test is
failing because 3^ s is not n when I'm
using plus so just to be clear here why
is my function only partially broken
just to be clear why am I seeing only
one error instead of two even though the
square function is now mathematically
broken because 2 plus two is four no
yeah I mean it's as simple as that I
just got lucky that 2+ 2 is the same
thing as 2 * 2 so this is one of those
Corner cases and this is why it's good
to be in the habit of not just testing
one thing but test several and make sure
you're covering your bases so to speak
so I got lucky here and that explains
why I'm seeing only one error even
though the function itself is flawed but
let me propose that there's another way
we could do this because honestly if I
extrapolate from this simple example
running not just two tests but three or
four or 10 or 20 tests you can imagine
that my God the code is going to get so
much more complicated than the function
itself I mean already look in
calculator. the function in question is
two lines long and yet in test
calculator the fun code in question is
five lines long like I've written more
code to test my code than I actually
wrote original code so the fewer lines
of code we can write when testing code I
think the more likely you and I are to
do it because it's going to be literally
a little less work and just fewer
opportunities for mistakes so what's
another approach I can take here well it
turns out in Python there is another
keyword that we haven't yet used which
is this here assert
assert is a keyword in Python and some
other languages as well that allow you
to do exactly that as in English to
assert that something is true to sort of
boldly claim that something is true and
if it is nothing's going to happen no
errors are going to appear on the screen
but if you assert something in Python
and it is not true that is the thing
you're insert asserting a Boolean
expression is false you're actually
going to see some kind of error on the
screen so let's go ahead and try this
new keyword as follows let me go back to
my code here and just to make it a
little simpler let me propose that I I
use this new keyword as follows let me
simply assert that the square of two
should equal four so I've changed my
logic instead of checking for not equals
I'm now asserting very loudly that it
should equal four and then on one
additional line let me do the other test
assert that the square of 3 equals
equals 9 and that's it no if no indented
print I'm just going to assert more
simply these two things that I want to
be true well let me go ahead now with
calculator. pi still broken I'm still
using plus accidentally instead of
multiplication let me go ahead now and
run python of test calculator. Pi
crossing my fingers as always but it's
not going to go well this time a whole
lot of Errors seem to appear on the
screen and if I scroll up here for this
traceback we'll see that the thing that
failed was this line here assert Square
of three equals equals 9 now
unfortunately when you're using the
assert keyword it's not terribly
userfriendly it shows you the files and
the line numbers involved but it does
show you the specific line of code that
failed the assertion that failed so to
speak it's now kind of up to you and me
to infer from this well wait a minute
why is the square of three not equal to
9 so it's not super user friendly but
honestly it was like half as much code
for me to write it's just two lines
instead of those previous four but
notice this little Remnant down here
this was an assertion error and we have
seen errors before we've seen errors
before when we've made other mistakes in
our code and in the past what was our
solution for catching those
errors how do we catch errors that seem
to resemble this even though we've not
seen this one before um try and accept
yeah in Python we can use the try and
accept keywords to try to do something
optimistically except if something goes
wrong do something else instead so this
is a step forward and that I can at
least catch this error but it's going to
be perhaps a step backward and that I'm
going to end up writing I'll admit in
advance a little more code uh instead so
let me go ahead and try this let me go
back into my code here and instead of
just asserting blindly let me go ahead
is to proposed and try to do this first
assertion except if there is an
assertion error like we saw a moment ago
then go ahead and print out something
more userfriendly that explains what
actually failed 2 squar
is uh was not four and let me go ahead
similarly and try to assert that the
square of 3 equals 9 except if there's
an assertion error there in which case
I'm going to print out more user
friendly 3^ squar was not n so I've
taken a step forward but also a step
back because now I have more code but I
have at least introduced assertions and
exceptions in a manner consistent with
how we've seen it in the past when
something goes wrong you actually see an
exception raised well let me go ahead
and run this version of the program now
instead python of test calculator.
crossing my fingers all right it still
failed because I'm seeing output but
we're back to at least userfriendly
output so that's at least progress in
some way here but it's again more code
than might have been ideal and in fact
if we continue this further what if we
actually want to add additional test
cases here as well well it seems like we
might end up writing way more code than
would be ideal for instance I'm testing
two and three now I should probably test
some negative numbers as well so why
don't I go ahead and add in for instance
let me go ahead and copy and paste this
let me try to assert that the square of
-2 equals equals 4 which should be the
case mathematically and if not let me go
ahead and change this to say -22 was not
four and you know what let me go ahead
and copy paste this again test another
negative number just for good measure
let's test the square ofg -3 which
should equal 9 but if it doesn't let's
go ahead and say that -32 was not 9 and
just to think aloud here what might be
another good value to test I've tried
two I've tried three I've tried ne-2
I've tried negative3 I can't try in
infinite numbers but there's at least
something that's a little different in
between those values let's try zero zero
is an interesting case too just in case
something might be wrong and Y zero I'm
just going with instincts here right
odds are positive numbers are generally
going to behave the same negative
numbers might generally behave the same
zero might be a little anomalous there's
no uh science to it necessarily
but rather considering for yourself
based on your own experience like what
are the potential Corner cases based on
the function you're trying to test I'm
trying to test something mathematical so
I want to test representative values so
let me go ahead and paste in one more
try accept block let's assert that the
square of zero should equal zero and if
not I'll say something explanatory like
0^ squar was not zero now if I go ahead
and run this python of test calculator.
piy and hit enter now I see multiple
errors and and this is interesting it's
a bit of a clue because notice that some
but not all of these assertions are
failing the one for 2^ SAR is apparently
okay as we noted earlier recall that 2^
SAR happens to be 2 plus 2 so that bug
doesn't really throw off our test but
it's a good thing we tested for three
it's a good thing we tested for neg -2
and neg3 because all of those tests
caught this error the zero test did not
notice because 0 squared is of course 0
but 0 + 0 is 0 so we're getting lucky or
unlucky there depending on how you you
view the glass is half full or half
empty here we at least by way of having
multiple tests caught this mistake
somehow so it would be nice though if we
weren't writing so much darn code here
right because notice what I've done I
have try except try except I have all of
these assertions I have a main function
I have this if conditional at the bottom
of my file I mean honestly who's going
to want to write 31 lines of code now
just to test a two line function right
no one's going to write test code like
this if we're all writing so much more
code to do the actual testing so people
have solved this problem if you are in
the habit of testing your code a lot or
wanting to if I'm in the habit of
wanting to test my code a lot if
everyone else in the real world is in
this habit of wanting to test their code
why don't we create tools that make it a
little easier to do so and in fact there
is a mechanism for doing this whereby we
can use a tool that's popularly called
pest so py test is a third-party program
that you can downloaded install that
will automate the testing of your code
so long as you write the tests but
what's nice about this library and
others like it is that it adopts some
conventions so that you don't have to
write as many lines of code yourself
manually they do some of that
automatically for you now this is a
thirdparty library there's other
libraries for unit tests uh so to speak
that is testing units of your code uh
some of them come with python itself
we're proposing that we look at py test
today because it's actually a little
simpler than the unit testing Frameworks
that come with python itself and what do
we mean by unit testing unit testing is
just a formal way of describing testing
individual units of your program what
are those individual units they're
typically functions so unit tests are
typically tests for functions that you
have written now what does this mean in
practice here well let me go back to my
VSS code here and let me propose that we
simplify my test calculator
significantly I'm going to go ahead and
delete all of these tests which were
um which we're accumulating to like 31
lines of code and let's see if we can
distill the tests to their Essence using
p test from my same calculator program
let me still import Square so I do still
need that line of code so that I can
test that specific function now I'm
going to go ahead and Define a function
just like I did before as follows I'm
going to define a function called test
Square Again by convention test
underscore and the name of the function
you want to test though it doesn't have
to be that way and now I'm going to go
ahead and make a few assertions I'm
going to assert that the square of two
should equal four I'm going to assert
that the square of three should equal 9
I'm going to assert that the square of
-2 should equal 4 and I'm going to
insert that the square of -3 should
equal 9 and lastly for now I'm going to
assert that the square of 0 should equal
zero so I'm still using the assert
keyword as I introduced earlier and even
though it was a little tedious to type
those I mean it's only eight lines of
code now and they're so easy to type
it's try and accept and all of this
wouldn't it be nice if something else
someone else handled the try the accept
the printing all of the standardization
of actually running these tests and
that's where indeed P test comes into
play per the documentation for py test
which can itself be installed with Pip
install py test which we've used to
install other libraries in the past you
can look at the documentation here for
all of its formal usage but fortunately
pest is pretty userfriendly
testing Frameworks go and it actually
allows us to Dive Right In by just
running P test on the code that we've
written so if I go back to vs code here
and look at my test calculator. piy
which notice has no main function
anymore it has no conditional it has no
tries it has no accepts it has no prints
it just has my few assertions Pi test
and other libraries like it are going to
automate the process of running these
tests for me and informing me on the
screen whether or not any of those tests
failed so so let me go ahead and do this
I'm going to go ahead and increase the
size of my terminal window for a moment
just so we can see more on the screen
and I'm going to run not python as I've
been doing I'm going to run Pi test
which again is this third party tool for
running tests in your code I'm going to
run Pi test of testore calculator so
that same file I'm going to cross my
fingers as always and hit enter and
we'll see that ah something has failed
now admittedly even though I do think
you'll find that Pi test is relatively
simple to use its output at least at
first glance is not necessarily super
user friendly so what are we seeing here
we'll notice at the very top of my
window is the command that I ran after
my prompt right below that is a single F
in red which means fail so not very
encouraging I tried really hard here but
fail is my grade on this program but
let's see exactly what happened well if
I look at this excerpt here under
failures you'll see that test square is
the function that failed all right that
makes sense because that's the only one
I wrote and you'll see here somewhat uh
Arcane output describing what the error
was so what you're seeing here is the
first line of output equals equals 4
which was fine there's no red error
message below that so that one's okay
but this line of code here assert that
square of three equals equals 9 pi test
did not like that assertion because it
didn't end up being true in fact per the
red e at the start of this line You'll
see that I'm effectively trying to
assert that 6 equals equals 9 now where
did the six come from okay wait a minute
if my test involves this notice that
where 6 equals square of three this is
saying that because I've called Square
passing in a value of three it turns out
its return value is six and of course
mathematically six does not equal equal
9 so that's why this is failing now Pi
test is not as user friendly as telling
you exactly why the bug is there or how
to fix it this is really just a clue to
you what must be wrong what you're
seeing here is a clue that the first
test passed because there's no red error
below that line of code but this test
failed somehow or other your Square
function is returning six when passed in
three instead of nine so at this point
you sort of put your detective hat on
you go back to your actual code and you
think about in calculator to Pi how in
the world is line seven of my square
function returning six instead of nine
and at this point odds are the light
bulb would go off above your head
proverbially and you would see oh I'm
using addition instead of multiplication
but what P test has done for us is
automate the process of at least
pointing out that error for us and if I
now go in and fix this let me go ahead
and the light bulb has gone off I change
the plus to a uh to multiply now I'm
going to go ahead and after clearing my
screen I'm going to run not python but
Pi test of test calculator. Pi crossing
my fingers again and now it's green and
I see just a DOT which indicates that my
one and only only test passed I'm good
100% success with my test now after
fixing that bug all right let me pause
here and see if there's any questions so
my question is what if a user uh instead
of because we are taking input from the
user what if the user is uh somewhat
malicious and types in a string instead
of an integer or maybe he types in a
float or some other data type yeah so
what if the user like we've seen in past
examples types in instead of a number
when we're expecting an integer how do
we test for something like that at the
moment I'm admittedly not testing user
input if I go back to my code here
notice that my calculator function of
course has the square function that we
keep testing and retesting but notice
that all of the user input is currently
relegated to my main function and
admittedly as of now I am not testing my
main function so they could be one of
those bugs and in fact there would be
because if the user types in a string
like cat instead of an integer like two
or three then line two recall would
actually raise a value error exception
so we've seen that before so when it
comes to testing your code this is
actually a good reason for having
multiple functions in your program
rather than putting all of your logic in
just the file itself rather than putting
all of the logic in just main it's
actually really good really helpful
practice to break your ideas up into
smaller bite-sized functions that
themselves are testable and what do I
mean here Square is perfectly testable
why because it takes as input a
parameter called n and it returns as
output an integer which is going to be
the square thereof hopefully it has a
well-defined input and a well-defined
output it is therefore completely within
your control in your test program to
pass in those values now I will say if
you want to test whether Square behaves
properly when past something like a
string like quote unquote cat we could
absolutely do something like this assert
that the square of uh quote unquote cat
it's not going to equal something you
can actually using different syntax
assert that a specific exception will be
raised so if we were actually going to
go back into our Square function improve
it and deliberately raise an exception
we could test for that too but for now
I'm deliberately only testing the square
function I'm not testing for specific
user input but that's another problem to
be solved other questions
now on unit tests uh do use the units
test to test the code
for the C cs50 check so check 50 is
similar in spirit cheze 50 is a tool
that we cs50 wrote that is essentially
doing something like pie test for the
evaluation of students code it is
similar in spirit but think of cze 50 as
being an alternative to P test if you
will but it works a little bit
differently but same idea pie test and
unit testing more generally is a
technique that is independent of cs50
and is something that you can and should
be doing on your own code both in or
outside of this class how about one
other question here
on on um on our uh unit tests uh my
question is instead of writing four
times like s square of 2al 4 uh instead
of that can we write if is uh I is
equals to in square brackets the numbers
we want instead of writing four lines a
really good question absolutely right
now if I go back to test calculator.
it's in pretty manual I mean it took me
a while to say and to type out those
several lines and you could imagine
writing some kind of loop to just assert
in a loop that this equals that that
this equals that and so forth using a
list or using maybe a list or a
dictionary or some structure like that
so yes you can absolutely automate some
of these tests by not just doing the
same thing again and again you can still
use all of the syntax of python to do
loops but generally speaking your test
should be pretty simple and in fact let
me propose that we improve upon even
this design further because at the
moment what's not really ideal when I
run all of this uh when I run all of
these tests when my uh function is buggy
is notice the output that I got let me
reintroduce that same bug by changing my
multiplication back to addition let me
increase the size of my terminal window
again and let me run Pi test again of
test calculator. Pi so this is the
version of my code now that has the bug
again so I'm going to see that big
massive failure where this failure has
been displayed to me but this is not as
helpful as it could be right because I
have all of those other tests in my code
recall that I had what 1 2 3 four five
separate tests and it I'm only seeing
the output of the first now why is that
well if we go back to my code here
you'll see that the first assertion
that's failing namely this one here that
assert of square of three equals equals
9 the other tests aren't even getting
run and that's not a big deal in the
sense that my code is buggy so one or
more of them are probably going to fail
anyway but wouldn't it be nice to know
which of them are going to fail and in
fact it's ideal to run as many tests all
at once as possible to give you as many
Clues as possible to finding your bug so
let me propose that we improve the
design of my testing code now still
using pi test as follows instead of
having one big function called test
square that tests the entire function
itself with so many different inputs
let's break down my tests into different
categories and here too there's no one
right way to do this but my mind is
thinking that I should maybe test
positive numbers separately test
negative numbers separately and test
zero separately I could think of other
ways I could test even numbers I could
test odd numbers or maybe some other
pattern alt together but separating this
big test into multiple tests is probably
going to yield more clues for me when
something goes wrong so let me do this
let me go ahead and rename this function
to test positive initially and let me
include in that function only those
first two tests let me then create
another function here called test
negative and in this function let me
test only -2 and -3 then down here let
me do one more def of test zero and I'll
just run one test in there so I have the
same assertions the same five but I've
now divided them up among three separate
functions what's nice about Pi test and
other unit testing Frameworks is that
all three of these test functions will
be run automatically even if one of them
fails the others will be attempting
that means that if one or two or three
of them fail I'll have one or two or
three Clues now for helping me find that
mistake so let me go ahead and again
increase the size of my terminal window
just so we can see more on the screen my
calculator still has the bug using
addition instead of multiplication let
me go ahead and run not python but again
Pi test of test calculator. piy crossing
my fingers as always and now oh my God
there's even more errors on the screen
but this in itself is more helpful let's
work through them from top to bottom so
under failures here in all caps which I
know is not very encouraging to see
failure when you're just trying to solve
a problem but that's what these
Frameworks do under failures the first
function that failed is test positive
but here too we see the same clue as
before the first one two the square of
two equals equals 4 that one's fine it's
not airing with any red errors but the
next one is failing so I know that
square is broken when I pass in three
all right what about down here it looks
like unfortunately my test negative
function is failing to why well when I
pass in oh this is interesting here now
-2 doesn't even work so I got lucky with
positive two but negative -2 isn't
working so that's a bit of a clue but in
total only two tests failed so notice at
the very bottom this summary two failed
and one passed what's the other one what
was the third one test zero so test zero
is passing these two are failing and so
that kind of leads me logically
mathematically if you will to the source
of the bug and just to be clear too if
you have a lot of tests this little
oneline output is helpful even though
also a bit discouraging fail fail and
Dot means pass so there are the three
tests just depicted graphically a little
bit differently well let me rewind now
and go back into calculator. Pi let's
fix that bug because let's suppose that
I've deduced okay I'm using addition I
should have been using multiplication
all this time let me now after fixing
the bug yet again let me go back to my
big terminal let me run Pi test of test
calculator. Pi hitting enter crossing my
fingers now and dot dot dot means all is
well 100% of my tests passed all three
of them so now I'm good it doesn't
necessarily mean that my code is 100%
correct but it does mean that it has
passed 100% of my current tests and so
it would probably behoove us to think a
little harder about maybe we should test
bigger numbers maybe we should test even
smaller numbers maybe we should test
strings or something else the onus is
ultimately on you to decide what you're
going to test but in the real world
you're going to be very unhappy with
yourself or someone else maybe your boss
is going to be very unhappy with you if
you did not catch a bug in your code
which you could have caught had you just
written a test to try that kind of input
all right let me pause again and see if
there's any questions now on unit
testings with P test um so if you wanted
to test like someone suggested before
user input as well as testing your
function do you do that within the same
file or do you make separate files for
different types of test
really good question you could
absolutely make separate files to test
different types of things or if you
don't have that many you can keep them
all in the same file at the moment I've
been storing all of my tests in one file
for convenience and there's not terribly
many of them but we'll take a look in a
bit at an example that allows me to put
them into a folder and even run P test
on a whole folder of tests as well so
that's possible other questions on unit
testing so I've got two questions um so
a couple while ago you just used um an
exception called
assertion um I'm not sure what was oh
yeah assertion error um what exactly
does that particular error catch and my
second question is does the assert
keyword um stand out to the compiler and
exactly tell them to assert this
particular um line of code indeed the
assert keyword we're seeing and the
assertion error we saw earlier are
intertwined so when you use assert and
the assertion fails because whatever
Boolean expression you're using is not
true it's false an assertion error by
definition of python will be raised so
those two work in conjunction those
errors those assertion errors are still
being raised by my code here when any of
these lines of code fail however pest
this third party library is handling the
process of catching those exceptions
automatically for me so as to give me
the standard output so we started to
today's Story by really implementing
unit testing myself I wrote all of the
code myself I wrote main I did my
conditional I did try except honestly
it's going to get incredibly painful to
write tests long term if you and I have
to write that much code every time
especially when our function is this
small uh so pie test and unit testing
Frameworks like it just automate so much
of that essentially P test adds the try
the accept the if the prints for you so
you can just focus on the essence of the
tests which really are these inputs and
outputs how about time for one other
question here on unit testing as well
sir uh when we uh enter minus 6 or
minus5 uh the uh square or Square uh
square root of the that uh number comes
up but when we put 6.6 or 5.6 something
like that integer then
uh line shows error so what's happening
there so if I'm deliberately testing
integers right now in large part because
I only want pow to operate on inte ERS
and that might be conveyed in Python's
documentation or my own documentation
for that function if we were to pass in
something else like a float it turns out
that floating Point values in Python and
other languages are actually very hard
if not impossible to represent 100%
precisely and so if you are trying to
compare it against some other value they
might be slight rounding errors as a
result I'm just inferring from what
you've described but I'm very
deliberately now testing this function
with only the inputs that I would expect
it might indeed throw other errors if
other inputs are passed all right allow
me to propose that we consider what
should happen if Square isn't actually
passed a number for instance if I go
back to calculator. Pi and suppose that
I or perhaps someone else using my
Square function simply forgets to
convert the return value of input from a
stir to an INT as by modifying line two
here well now something's definitely
going to go wrong if I type in a stir
instead of what appears to be an INT for
instance if I clear my terminal here run
pip Pyon of calculator. Pi and hit enter
let's type in cat as our value for x and
of course this raises Now a type error
why can't multiply sequence by non-int
of type stir what does that mean well
you can't do cat times cat because
indeed square is expecting that n will
be some number but that doesn't
necessarily mean that square itself is
buggy but this does mean that if I
expect a type error to be raised let's
test for that too so that I know the
behavior indeed works as expected so let
me go back to test calculator p and let
me go and add a fourth test down here
how about Define testore and I'll call
this tester because I'm going to
specifically and deliberately pass in a
stir for testing and I want to in spirit
assert that passing in something like
cat to square will raise a type error
but we don't use the assert keyword for
that rather we need this let me go to
the top of this file and let me
additionally import the pest Library
itself because it turns out there's a
function in that Library called raises
that allows me to express that I expect
an exception to be raised and I can
express that as follows with pest.
raises and then in parenthesis I can
pass in the type of exception I expect
which is going to be a type error in
this case and now when do I expect that
type error to be raised whenever I do
something like calling square and
passing in not a number but something
like cat so now if I go back to my
terminal window run Pi test of test
calculator. piy this time having four
tests I should see that all four now are
successful all right let's now consider
how we could test code that doesn't just
expect numbers as input but actually
strings and let me rewind Us in time
here in VSS code to that very first
program rewrote a few different versions
of in hello.py that ultimately looked a
little something like this I had a main
function that prompted the user for the
value of a variable by asking them
what's your name question mark and then
we went ahead and did something like
hello open pen name passing that user's
name into a function called hello now
that function hello recall ultimately
looked like this we defined hello as
taking a parameter called two the
default value of which was world and
that function very simply printed hello
followed by a comma and then whatever
the name that had been passed in and
then we ultimately called main but for
now onward I'm going to always add this
if conditional if name equals equals
underscore uncore main then and only
then do I want to call Main so that's
essentially what this program looked
like in its last Incarnation how do we
go about testing it well here again too
I'm not going to test the user's input
per se in main I'm going to focus really
on the module the module of code here
that's of Interest which is the hello
function itself how can I go about
testing the hello function well
unfortunately even if I start by doing
something like code of test hello.py
let me go about and start writing a test
program I could import from my hello
program a function called hello so a bit
strange to see from Hello import hello
but notice that on this line here I'm
importing from the module that is the
file called hello.py the function called
hello and how do I go about testing this
well if I have a function like Define uh
test argument like this well let me Sue
this so if I were toine a function like
like Define test hello what could I do
well I could call hello with quote
unquote say uh David and then check if
it equals what hello comma David so
would this work this approach here if
I've written a test called test hello
that calls hello with an argument of
David and then tests its return value
just like we've done for our calculator
would this work as written
and let me go back to in just a moment
the version of hello that we're testing
so you can see that function hello
here's the test here is the actual code
would this test now
work any thoughts uh I think the problem
is that in the first version in
hello.py you're using the toe argument
that you first declare when you declare
the function instead of using the
name okay I that is actually uh not a
bug here so let me stipulate that in
hello.py this code actually does work as
intended and let me go ahead and test it
manually just to demonstrate as much let
me run python of hello.py typing in as
my name David and I see in fact that it
says hello David if though I were to
change this program and get rid of the
name argument get rid of the name
variable and just call hello again
running python of hello.py this time I'm
not even prompted because I got rid of
my input call but it does pre behave as
I expect it does say hello world so let
me stipulate that this code in its
current form is actually correct but my
test is not going to work as I'd hoped
and there's a subtle difference between
hello versus my pow function that expl
versus my there's a subtle difference
between my hello function and my Square
function that
explains why might this test not work as
intended um because it's not returning a
value yeah exactly recall our discussion
early on about functions functions can
either return a value like my Square
function hands you back the square of
some value or they can have side effects
sort of visual uh artifacts that might
happen on the screen like printing
something out on the screen and by
definition that's how Print Works notice
that hello it is short but it's
implemented ultimately using the print
function which does not return a value
as I'm using it here it instead has this
side effect of printing something onto
the screen so it is not correct in my
test function to check if the return
value of hello equals equals hello David
because again hello is not returning
anything it's printing something with
that side effect but notice literally it
has no return keyword unlike my Square
function which did so here's an
opportunity too to perhaps change how I
go about implementing my actual
functions it turns out that as your
programs get more and more sophisticated
more and more complicated it tends to be
best practiced not to have side effects
if if you can avoid it especially if you
want your code to be testable and in
fact I'm going to propose that we change
my hello program to now work as follows
let me go ahead and change this function
to not print hello and then that name
let me go ahead and literally return
maybe an F string which will clean this
up a little bit hello comma 2 close
quote at the end so my syntax here is
just the familiar F string or format
string it's going to return hello world
or hello David or hello whoever name is
passed in as that argument but I'm
returning it now I'm not printing it out
so what needs to change up here well I
could do something like this I could say
something like output equals hello and
then print output in my main function or
I can simplify that because I don't
really need that variable I could
instead just do this I could still call
hello but I could immediately print out
the result and this version of my hello
program now is actually more test able
why because these assert statements that
we're using and we've seen th far for
our tests are really designed to test
arguments into functions and return
values there from not testing side
effects so if you're doing equals equals
you're looking for a return value
something that's handed back from the
function so that's fine if I modify the
design of my program now not to just
print hello but to return the string the
sentence the phrase that I want to
construct I can leave it to the caller
that is the function who's using this
hello function to handle the actual
printing now what does this mean in my
code well it means now if my hello.py
looks like this and hello is indeed
returning a value in my test hello
function I can test it exactly like this
so let me go ahead and run Pi test of
test hello.py crossing my fingers as
always and voila one passed so I passed
this test because apparently the return
value of hello does indeed equal hello
comma David well let's test the scenario
what if I P call hello without any
arguments let's assert that calling
hello with nothing in those parentheses
similarly equals hello comma but world
the default value let me now go ahead
and run Pi test of test hello.py and
that too passes entirely but there too
suppose that I had made some mistake
suppose that there were a bug in my code
it might not be best practice to combine
multiple tests in this one function so
let's make it more clear what might pass
or fail let's call the first function
test the default uh to this function and
let's only include this first line of
code and then let's go ahead and Define
another function like test argument to
test this other line of code here so now
I have two different tests Each of which
is testing something a little
fundamentally different so now when I
run my code it's still not broken if I
run Pi test of test hello.py enter I've
now passed two tests and that's just as
good as before but if I did have a bug
having two tests instead of one would
indeed give me perhaps a bit more of a
hint as to what's wrong questions now on
this testing of return values when these
return values are now strings instead of
integers and why we've done this so my
question is uh about function inside the
function uh can we test that too or
recursion we we we have't
seen if you have if you have a recursive
function which we've not discussed in
this class yes you can absolutely test
those two uh by simply calling them
exactly in this way recursion does not
affect this process all right how about
one more question here on unit test
before we look at one final example when
testing our uh arguments like uh can we
use something like a Loops or inside of
assert or for the values absolutely you
can absolutely use a loop to test
multiple values in this case for
instance I could do something like this
I could say for name in The Following
list of
Hermione uh say Harry and Ron I could
then within this Loop assert that hello
of that given name equals equals say the
format string of hello comma name and
then run all of these here at once by
running again Pi test of test hello.py
it's still going to be just one test
within that function but if there's
something interesting about those
several strings that makes it compelling
to test all of them you can absolutely
automate the tests in that way with that
said each of your test should ideally be
pretty simple and pretty small why
because you don't want to write so much
code so much complicated code that your
tests might be flawed what we don't want
to have to do is write tests for our
tests and tests for our test for our
tests because it would never end so
keeping tests nice and simple is really
the goal so that a reasonable human
yourself included can eyeball them and
just claim yeah that is correct we don't
need tests for our tests all right how
about one other feature suppose that we
don't have just one test but many
different tests instead and we want to
start to organize those tests into
multiple files and even a folder well P
test and other Frameworks support that
Paradigm as well in fact let me go ahead
and test hello.py using a folder of
tests with technically just one test but
it would be representative of having
even more in that folder I'm going to go
ahead and create a new folder called
test using makeer at my command line and
then Within that file I'm within that
and then within that folder I'm going to
go ahead and create a file called test
hello.py within this file meanwhile I'm
going to test the same things I'm going
to go ahead and from Hello import
hello and I'm going to go ahead and
Define a function like test default that
simply tests the scenario where hello
with no arguments returns hello comma
world and I'm going to have that other
function where I test that an argument
is passed and in this case I'll choose
an argument like asserting that hello
quote unquote David equals indeed hello
comma not world but David So in this
case I've just recreated the same test
as earlier but they're in a file now in
a folder called test well P test allows
me to run these here too but to do so I
actually need to create one other file
within my test directory I need to
create a file called uncore uncore init
uncore uncore dopy which has the effect
even if this file is empty of ing python
to treat that folder as not just a
module but a package so to speak a
package is a python module or multiple
modules that are organized inside of a
folder and this file underscore uncore
init underscore uncore Pi is just a
visual indicator to python that indeed
it should treat that folder as a package
if I had more code in this folder I
could do even more things with this file
but for now it's just a cluee that it's
indeed meant to be a package and not
just a module or file alone what I can
now do in closing is run P test not even
on that specific file but on a whole
folder of tests so if I run Pest of test
where the test is the name of that
folder pest will automatically search
through that folder looking for all
possible tests granted there's just
those two in this one file but when I
run it now with enter I'll still pass
those tests I'll still get 100% And I
now have a mechanism ultimately for
testing my own code so whether you're
writing functions that return integers
or something else functions that have
side effects that could be Rewritten as
functions that return values you now
have a mechanism to not just wait for
one someone like us to test your code
and not just test your code manually
again and again which might get tedious
and you might make mistakes by not
including some possible inputs we now
have an automated mechanism for testing
one's own code that's going to be even
more powerful when you start
collaborating with others so that you
can write tests that ensure that if they
make a change to the same code they
haven't broken the code that you've
written all right that's it for this
week we'll see you next time
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men and this is our week on file IO
input and output of files so up until
now most every program we've written
just stores all the information that it
collects in memory that is in variables
or inside of the program itself a
downside of which is that as soon as the
program exits anything you typed in
anything that you did with that program
is lost now with files of course on your
Mac or PC you can hang on to information
long term and file IO within the context
of programming is all about writing code
that can read from that is load
information from or write to that is
save information to files themselves so
let's see if we can't transition then
from only using memory and variables and
the like to actually writing code that
save some files for us and therefore
data persistently well to do this let me
propose that we first consider a
familiar data structure a familiar type
of variable that we've seen before that
of a list and using lists we've been
able to store more than one piece of
information in the past using one
variable we typically store one value
but if that variable is a list we can
store multiple values unfortunately
lists are stored in the computer's
memory and so once your program exits
even the contents of those disappear but
let's at least give ourselves a starting
point so I'm over here in vs code and
I'm going to go ahead and create a
simple program using Code of names. py a
program that just collects people's
names students names if you will and I'm
going to do it super simply initially in
a manner consistent with what we've done
in the past to get user input and print
it back out I'm going to say something
like this name equals input quote
unquote what's your name thereby storing
in a variable called name the return
value of input as always and as always
I'm going to go ahead and very simply
print out a nice F string that says
hello comma and then in curly brace's
name to print out hello David hello
world however happens to be using the
program let me go ahead and run this
just to remind myself what I should
expect and if I run python of names.
high and hit enter type in my name like
David of course I now see hello comma
David suppose though that we wanted to
add support not just for one name but
multiple names maybe three names for the
sake of discussion so that we can begin
to accumulate some amount of information
in the program such that it's really
going to be a downside if we keep
throwing it away once the program exits
well let me go back into names. up here
at top let me proactively give myself a
variable this time called names plural
and set it equal to an empty list recall
that the square bracket notation
especially if nothing's inside of it
just means give me an empty list that we
can add things to over time well what do
we want to add to it well let's add
three names each from the user and let
me say something like this uh for
underscore in range of three let me go
ahead and prompt the user with the input
function and getting their name in this
variable and then using list syntax I
can say names. append name to that list
list and now I have in that list that
given name one two three of them other
points to note is I could use a variable
here like I which is conventional but if
I'm not actually using I explicitly on
any subsequent lines I might as well
just use underscore which is a pythonic
convention and actually if I want to
clean this up a little bit right now
notice that my name variable doesn't
really need to exist because I'm
assigning it a value and then
immediately appending it well I could
tighten this up further by just getting
rid of that variable Al together and
just appending immediately the return
value of input I think we could go both
ways in terms of design here on the one
hand it's a pretty short line and it's
readable on the other hand if I were to
eventually change this phrase to be not
what's your name but something longer we
might want to break it out again into
two lines but for now I think it's
pretty readable now later in the program
let's just go ahead and print out those
same names but let's sort them
alphabetically so that it makes sense to
be gathering them all together then
sorting them and printing them so how
can I do that well in Python the
simplest way to sort a list in a loop is
probably to do something like this for
name in names but wait let's sort the
names first recall that there's a
function called sorted which will return
a sorted version of that list now let's
go ahead and print out uh an F string
that says again hello bracket name close
quote all right let me go ahead and run
this so Python ofn names. and let me go
ahead and type in a few names this how
about hermion how about Harry how about
Ron and notice that they're not quite in
alphabetical order but when I hit enter
and that Loop kicks in it's going to
print out hello Harry hello Hermione
hello Ron in sorted order but of course
now if I run this program again all of
the names are lost and if this is a
bigger program than this that might
actually be pretty painful to have to
re-input the same information again and
again and again wouldn't it be nice like
most any program today on a phone or or
a laptop or desktop or Cloud to be able
to save this information somehow instead
and that's where file IO comes in and
that's where Files come in they are a
way of storing information persistently
on your own phone or Mac or PC or some
Cloud servers uh disk so that they're
there when you come back and run the
program again so how can we go about
saving all three of these names on in a
file as opposed to having to type them
again and again let me go ahead and
simplify this file and again give myself
just a single variable called name and
set the return value of input equal to
that variable so what's your name as
before quote unquote and now let me go
ahead and let me do something more with
this value instead of just adding it to
a list or printing it immediately out
let's save the value of the person's
name that's just been typed in to a file
well how do we go about doing that well
in Python there's this function called
open whose purpose in life is to do just
that to open a file but to open it up
Pro grammatically so that you the
programmer can actually read information
from it or write information to it so
open is like the programmer's equivalent
of like double clicking on an icon on
your Mac or PC but it's a programmer's
technique because it's going to allow
you to specify exactly what you want to
read from or right to that file formally
its documentation is here and you'll see
that its usage is relatively
straightforward it minimally just
requires the name of the file that we
want to open and optionally how we want
to open it so let me go back back to vs
code here and let me propose now that I
do this I'm going to go ahead and call
this function called open passing in an
argument for names.txt which is the name
of the file I would like to store all of
these names in I could call it anything
I want but because it's going to be just
text it's conventional to call it
something. txt but I'm also going to
tell the open function that I plan to
write to this file so as a second
argument to open I'm going to put
literally quote unquote W for right and
that's going to tell open to open the
file in a way that's going to allow me
to change the content and better yet if
it doesn't even exist yet it's going to
create the file for me now open returns
what's called a file handle a special
value that allows me to access that file
subsequently so I'm going to go ahead
and sign it equal to a variable like
file and now I'm going to go ahead and
quite simply write this person's name to
that file so I'm going to literally type
file which is the variable uh linking to
that file WR which is a function
otherwise known as a method that comes
with open files that allows me to write
that name to the file and then lastly
I'm going to quite simply going to go
ahead and say file. close which will
close and effectively save the file so
these three lines of code here are
essentially the programmers equivalent
to like double clicking an icon on your
Mac or PC making some changes in
Microsoft Word or some other program and
going to file save we're doing that all
in code with just these three lines here
well let's see now how this works let me
go ahead now and run python of names.
piy and enter let's type in a name I'll
type in her Mayan enter all right where
did she end up well let me go ahead now
and type code of names.txt which is a
file that happens now to exist because I
opened it in right mode and if I open
this in a tab we'll see there is
Hermione well let's go ahead and run
names. py once more I'm going to go
ahead and run python of names. py enter
and this time I'll type in Harry let me
go ahead and run it one more time and
this time I'll type in Ron and now let
me go up to names. text where hopefully
I'll see all three of them here but no
I've just actually seen
Ron What might explain what happened to
Hermione and Harry even though I'm
pretty sure I ran the program three
times and I definitely wrote the code
that writes their name to that file
what's going on here do you think I
think because we are not appending them
we should append the names uh since we
are writing directly it is erasing the
old content and it is replacing with the
last uh um set of characters that we
mentioned exactly unfortunately quote
unquote W is a little dangerous not only
will it create the file for you it will
also recreate the file for you every
time you open the file in that mode so
if you open the file once and write
Hermione that worked just fine as we saw
but if you do it again for Harry if you
do it again for Ron the code is working
but each time it's opening the file and
recreating it with brand new contents so
we had one version with Hermione one
version with Harry and one final version
with Ron but ideally I think we probably
want to be appending as bashall says
each of those names to the file not just
clobbering that is overwriting the file
each time so how can I do this it's
actually a relatively easy fix let me go
ahead and do this as follows I'm going
to first remove the old version of
names. text and now I'm going to change
my code to do this I'm going to change
the W quote unquote to just a quote
unquote a for aend which means to add to
the bottom to the bottom to the bottom
again and again now let me go ahead and
rerun python of names. piy enter I'll
again start from scratch with hermion
because I'm creating the file new notice
that if I now do code of names.txt enter
we do see that hermion is back so we've
after removing the file it did get Rec
created even though I'm using a pend
which is good but now let's see what
happens when I go back to my terminal
and this time I run python of names. py
again this time typing in Harry and let
me run it one more time this time typing
in Ron so hopefully this time in that
second tab names. text I should now see
all three of them but but but but this
doesn't look ideal what have I clearly
done
wrong something tells me even though all
three names are there it's not going to
be easy to read those back unless you
know where each name ends and Begins the
English format is not correct like the
English format is not correct like it's
say correct it's concatenating them it
is it's it's in can it's well it appears
to be concatenating but technically
speaking it's just a pending to the file
first Hermione then Harry then Ron it
has the effect of combining them back to
back but it's not concatenating per se
it really is just a pending let's go to
another hand here what really have I
done wrong or equivalently how might I
fix it would be nice if there were some
kind of gaps between each of the names
so we could read them more cleanly Hello
uh we should uh add new line before we
uh write new name good we want to add a
new line ourselves so whereas print by
default recall always outputs
automatically a line ending of back sln
unless we override it with the named
parameter called n and right does not do
that right takes you literally and if
you say WR Hermione that's it you're
getting the H through the E if you say
right hairry you get the H through the Y
you don't get any extra new lines
automatically so if you want to have a
new line at the end of each of these
names we've got to do that manually so
let me again Clos names. text and let me
remove the current file and let me go
back up to my code here and I can fix
this in any number of ways but I'm just
going to go ahead and do this I'm going
to write out an F string that contains
name and back sln at the end we could do
this in different ways we could manually
print just the new line or some other
technique but I'm going to go ahead and
use my f strings as I'm in the habit of
doing and just print the name and the
new line all at once I'm going to go
ahead now and down to my terminal window
run python of names. py again enter
we'll type in Hermione I'm going to run
it again type in Harry I'm going to type
it again and this time Ron now I'm going
to run code of names.txt and open that
file and now it looks like the file is a
bit cleaner indeed I have each of the
name on its own line as well as a line
ending which ensures that uh we can
separate one from the other now if I
were you know writing code I bet I could
parse that is read the previous file by
looking at differences between lowercase
and uppercase letters but that's going
to get messy quickly generally speaking
when storing data longterm in a file you
should probably do it somehow cleanly
like doing one name at a time well let's
now go back and I I'll propose that this
code is now working correctly but we can
design it a little bit better it turns
out that it's all too easy when writing
code to sometimes forget to close files
and sometimes this isn't necessarily a
big deal but sometimes it can create
problems files could get corrupted or
accidentally deleted or the like
depending on what happens in your code
so it turns out that you don't strictly
need to call close on the file yourself
if you take another approach instead
more pythonic when M uh manipulating
files is to do this to introduce this
other keyword called quite simply with
that allows you to specify that in this
context I want you to open and
automatically close some file so how do
we use with it simply looks like this
let me go back to my code here I've
gotten rid of the close line and I'm now
just going to say this instead instead
of saying file equals open I'm going to
say with open then the same arguments as
before and somewhat curiously I'm going
to put the variable at the end of the
line why that's just the way this is
done you say with you call the function
in question and then you say as and
specify the name of the variable that
should be assigned the return value of
open then I'm going to go ahead and
indent the line underneath so that the
line of code that's writing the name is
now in the context of this withth
statement which just ensures that
automatically if I had more code in this
file down below no longer indented the
file would be automatically closed as
soon as line four is done executing so
it doesn't change what has just happen
but it does automate the process of at
least closing things for us just to
ensure I don't forget and so that
something doesn't go wrong but suppose
now that I wanted to read these names
from the file all I've done thus far is
write code that writes names to the file
but let's assume now that we have all of
these names in the file and heck let's
go ahead and add one more let me go
ahead and run this one more time python
of names. py and let's let in Draco to
the mix so now that we have all four of
these names here how might we want to re
them back well let me propose that we go
into names. now or we could create
another program Al together but I'm
going to keep reusing the same name just
to keep us focused on this and now I'm
going to write code that reads an
existing file with Hermione Harry Ron
and Draco together and how do I do this
well it's similar in spirit I'm going to
start this time with with open and then
the first argument is going to be the
name of the file that I want to open as
before and I'm going to open it this
time in read mode quote unquote r and to
read a file just means to load it not to
save it and I'm going to name the return
value file and now I'm going to do this
and there's a number of ways I can do
this but one way to read all of the
lines from the file at once would be
this let me declare a variable called
lines let me access that file and call a
function or a method that comes with it
called read lines so if you read the
documentation on file IO in Python
you'll see that open files come with a
special method whose purpose in life is
to read all the lines from the file
and return them to me as a list so what
this line two is doing is it's reading
all of the lines from that file storing
them in a variable called lines now
suppose I want to iterate over all of
those lines and print out each of those
names for line in lines this is just a
standard for Loop in Python lines is a
list line is the variable that will be
automatically be set to each of those
lines let me go ahead and print out
something like oh hello uh comma and
then I'll print out the line itself all
right so let me go to my terminal window
run python of names. py now I have not
deleted names.txt so it still contains
all four of those names and hit enter
and okay it's not bad but it's a little
ugly here what's going on when I ran
names. py it's saying hello to hermion
to Harry to Ron to Draco but there's
these gaps now between the
lines what's explains that symptom if if
nothing else it just looks ugly it
happens because in the text file we have
a new line symbols uh in between those
names and the print always adds another
new line at the end so you you use the
same symbol twice perfect and here's a
good example of a bug a mistake in a
program but if you just think about
those first principles like how do each
of the lines of code work that I'm using
you should be able to reason exactly as
Rafal did there to say that all right
well one of those new lines is coming
from the file after each name and then
of course print all of these Weeks Later
is still giving us for free that extra
new line so there's a couple possible
solutions I could certainly do this
which we've done in the past and pass in
a named argument to print like end
equals quote unquote and that's fine I
would argue a little better than that
might actually be to do this to strip
off of the end of the line the actual
new line itself so that print is
handling the printing of everything the
person's name as well as the new line
but you're just stripping off what is
really just an implementation detail in
the file we chose to use new lines in my
text file to separate one name from
another so arguably it should be a
little cleaner in terms of design to
strip that off and then let print print
out what is really just now a name but
that's ultimately a design decision the
effect is going to be exactly the same
well if I'm going to open this file and
read all the lines and then iterate over
all of those lines and print them each
out I could actually combine this into
one thing because right now I'm doing
twice as much work I'm reading all of
the lines then I'm iterating over all of
the lines just to print out each of them
well in Python with files you can
actually do this I'm going to erase
almost all of these lines now keeping
only the width statement at top and
inside of this width statement I'm going
to say this for line in file go ahead
and print out quote unquote hello comma
and then line. rstrip so I'm going to
take the approach of stripping off the
end of the line
but notice how elegant this is so to
speak I've opened the file in line one
and if I want to iterate over every line
in the file I don't have to very
explicitly load all read all the lines
then iterate over all of the lines I can
combine this into one thought it in
Python you can simply say for line in
file and that's going to have the effect
of giving you a for Loop that iterates
over every line in the file one at a
time and on each iteration updating the
value of this variable line to be
Hermione then Harry then Ron than Draco
so this again is one of the appealing
aspects of python is that it reads
rather like English for line and file
print this it's a little more compact
when written this way well what if
though I don't want quite this Behavior
because notice now if I run python of
names. piy it's correct I'm seeing each
of the names and each of the hos and
there's no Extra Spaces in between but
just to be difficult I'd really like us
to be sorting these hellos really I'd
like to Draco first then Harry then
Hermione then Ron no matter what order
they appear in the file so I could go in
of course to the file and manually
change the file but if that file is
changing over time based on who is
typing their name into the program
that's not really a good solution in
code I should be able to load the file
no matter what it looks like and just
sort it all at once now here is a reason
to not do what I've just done I can't
iterate over each line in the file and
print it out but sort everything in
advance right logically if I'm looking
at each line one at a time and printing
it out it's too late to sort I really
need to read all of the lines first
without printing them sort them then
print them so we have to take a step
back in order to add now this new
feature so how can I do this well let me
combine some ideas from before let me go
ahead and start fresh with this let me
give myself a list called names and
assign it in empty list just so I have a
variable in which to accumulate all of
these lines and now let me open the file
with open quote unquote names. text and
it turns out I can tighten this up a
little bit it turns out if you're
opening a file to read it you don't need
to specify quote unquote r that is the
implicit default so you can tighten
things up by just saying open names.
text and you'll be able to read the file
but not write it I'm going to give
myself a variable called file as before
I am going to iterate over the file in
the same way for line in file but
instead of printing each line I'm going
to do this I'm going to take my name's
list list and append to it and this is
appending to a list in memory not
appending to the file itself I'm going
to go ahead and append the current line
but I'm going to strip off the new line
at the end so that all I'm adding to
this list is each of the students names
now I can use that familiar technique
from before let me go outside of this
with statement because now I've read the
entire file presumably so by the time
I'm done with lines four and five again
and again and again for each line in the
file I'm done with the file it can close
I now have all of the students names in
this list variable let me do this for
name in not just names but the sorted
names using our python function sorted
which does just that and do print quote
unquote with an FST string hello comma
and now I'll plug in bracket name so now
what have I done I'm creating a list at
the beginning just so I have a place to
gather my data I then on lines 3 through
five iterate over the file from Top top
to bottom reading in each line one at a
time stripping off the new line and
adding just the students name to this
list and the reason I'm doing that is so
that on line seven I can sort all of
those names now that they're all in
memory and print them in order I need to
load them all into memory before I can
sort them otherwise I'd be printing them
out prematurely and Draco would end up
last instead of first so let me go ahead
in my terminal window and run python of
names. py now and hit enter and there we
go the same list of four hellos but now
they're sorted and this is a very common
technique when dealing with files and
information more generally if you want
to change that data in some way like
sorting it creating some kind of
variable at the top of your program like
a list adding or appending information
to it just to collect it in one place
and then do something interesting with
that collection that list is exactly
what I've done here now I should note
that if we just want to sort the file we
can actually do this even more simply in
Python particularly by not bothering
with this names list nor the second for
Loop and let me go ahead and instead
just do more simply this let me go ahead
and tell python that we want the file
itself to be sorted using that same
sorted function but this time on the
file itself and then inside of that for
Loop let's just go ahead and print right
away our hello comma followed by the
line itself but still stripping off of
the end of it any white space therein if
we go ahead and run this same program
now with python of names. py and hit
enter we get the same result but of
course it's a lot more compact
but for the sake of discussion let's
assume that we do actually want to
potentially make some changes to the
data as we iterate over it so let me
undo those changes leave things as is
whereby now we'll continue to accumulate
all of the names first into a list maybe
do something to them maybe forcing them
to uppercase or lower case or the like
and then sort and print out each item
let me pause and see if there's any
questions now on file IO reading or
writing or now accumulating all of these
values in some list hi it's is there a
way to sort the files but instead if you
want it from alphabetically from A to Z
is there a way to reverse it from Z to A
is there like a little extension that
you can add to the end to do that or
would you have to create a new function
if you wanted to reverse the contents of
the file yeah so if you instead of
sorting them from a to z in ascending
order if you wanted them in descending
order is there an extension for that
there is indeed and as always the
documentation is your friend so if the
goal is to sort them not in alphabetical
order which is the default but maybe
reverse alphabetical order you can take
a look for instance at the formal python
documentation there and what you'll see
is this summary you'll see that the
sorted function takes a first argument
generally known as an iterable and
something that's iterable means that you
can iterate over it that is you can Loop
over it one thing at a time what the
rest of this line here means is that you
can specify a key like how you want to
sort it but more on that later but this
last named parameter here is reverse and
by default per the documentation it's
false it will not be reversed by default
but if we change that to true I bet we
can do that so let me go back to vs code
here and do just that let me go ahead
and pass in a second argument to sorted
in addition to this iterable which is my
names list iterable again in the sense
that it can be looped over and let me
pass in Reverse equals true thereby
overwriting the default of false let me
now run python of names. piy and now
Ron's at the top and draco's at the
bottom so there too whenever you have a
question like that moving forward
consider what does the documentation say
and see if there's a germ of an idea
there because oddar if you have some
problem oddar some programmer before you
has had the same question other thoughts
uh can we limit uh number uh numbers of
names and the second question uh can we
find specific name in least really good
question can we limit the number of the
names in the file and can we find a
specific one we absolutely could if we
were to write code we could for instance
open the file first count how many lines
are already there and then if there's
too many already we could just exit with
cy. exit or some other message to
indicate to the user that sorry the
class is full as for finding someone
specifically absolutely you could
imagine opening the file iterating over
it with a for loop again and again and
then adding a conditional like if the
current line equals equals Harry then we
found the chosen run and you can print
something like that so you can
absolutely combine these ideas with
previous ideas like conditionals to ask
those same questions how about one other
question on file IO uh so I just thought
about um this function like uh read all
lines and uh it looks like it's uh like
separate all the lines by this special
character back sln but it looks like we
don't need it character and we we always
strip it uh and uh it looks like some
bad design of function why why wouldn't
we just strip it inside this function a
really good question so we are in my
examples thus far using our strip to
reverse uh to strip from the end of the
line all of this white space you might
not want to do that in this case I am
stripping it away because I know that
each of those lines isn't some generic
line of text each line really represents
a name that I have put there myself I'm
using the new line just to separate one
value from another in other scenarios
you might very well want to keep that
line ending because it's a very long
series of text or a paragraph or
something like that where you want to
keep it distinct from the others but
it's just a convention we have to use
something presumably to separate one uh
chunk of text from another there are
other functions in Python that will in
fact handle the removal of that white
space for you read lines though does
literally that though it reads all of
the lines as is well allow me to turn
our attention back to where we left off
here which is just names to propose that
with names. text we have an ability it
seems to store each of these names
pretty straightforwardly but what if we
wanted to keep track of other
information as well suppose that we
wanted to store information including a
student's uh name and their house at
Hogwarts be it Gryffindor or Slytherin
or something else well where do we go
about putting that you know Hermione
lives in Gryffindor so we could do
something like this in our text file
Harry lives in Gryffindor so we could do
that Ron lives in Gryffindor so we could
do that and Draco lives in Slytherin so
we could do that but I worry
here but I worry now that we're mixing
apples and oranges so to speak like some
lines are names some lines are houses so
this probably isn't the best design if
only because it's confusing or it's
ambiguous so maybe what we could do is
Adopt A convention and indeed this is in
fact what a lot of programmers do they
change this file not to be names. text
but instead let me create a new file
called names. CSV CSV stands for comma
separated values and it's a very common
convention to store multiple pieces of
information that are related in the same
file and so to do this I'm going to
separate each of these types of data not
with another new line but simply with a
comma I'm going to keep each student on
their own line but I'm going to separate
the information about each student using
a comma instead and so now we sort of
have a a two-dimensional file if you
will row by row we have our students but
if you think of these commas as
representing a column even though it's
not perfectly straight because of the
lengths of these names it's a little ra
it's a little uh Jagged you can think of
these commas as representing a column
and it turns out these CSV files are
very commonly used when you use
something like Microsoft Excel Apple
numbers or Google spreadsheets and you
want to export the data to share with
someone else as a CSV file or conversely
if you want to import a CSV file into
your preferred spreadsheet software like
Excel or numbers or Google spreadsheets
you can do that as well so CSV is a very
common very simple text format that just
separates values with commas and
different types of values ultimately
with new lines as well let me go ahead
and run code of students. CSV to create
a brand new file that's initially empty
and we'll add to it those same names but
also some other information as well so
if I now have this new file students.
CSV inside of which is one column of
names so to speak and one column of
houses how do I go about changing my
code to read not just those names but
also those names and houses so that
they're not all on one line we somehow
have access to both type of value
separately well let me go ahead and
create a new program here called uh
students. py and in this program let's
go about reading not a text file per se
but a specific type of text file a CSV a
comma separated values file and to do
this I'm going to use similar code as
before I'm going to say with open quotee
unquote students. CSV I'm not going to
bother specifying quote unquote R
because again that's the default but I'm
going to give myself a variable name of
file and then in this file I'm going to
go ahead and do this for line in file as
before and now I have to be a bit clever
here let me go back to students. CSV
looking at this file and it seems that
on my loop on each iteration I'm going
to get access to the whole line of text
I'm not going to automatically get
access to just Hermione or just
Gryffindor recall that the loop is going
to give me each full line of text so
logically what would you propose that we
do inside of a for Loop that's reading a
whole line of text at once but we now
want to get access to the individual
values like Hermione and Gryffindor
Harry and Gryffindor how do we go about
taking one line of text and gaining
access to those individual values do you
think just instinctively even if you're
not sure what the name of the functions
would be you can access access as you
would as if you were using a dictionary
like using a key and value so ideally we
would access it using it a key and value
but at this point in the story all we
have is this Loop and this Loop is
giving me one line of text at is a time
I'm the programmer now I have to solve
this there is no dictionary yet in
question how about another suggestion
here um so you can somehow split the two
words based on the comma yeah even if
you're not quite sure what function is
going to do this intuitively you want to
take this whole line of text hermion
comma Gryffindor Harry comma Gryffindor
and so forth and split that line into
two pieces if you will and it turns out
wonderfully the function we'll use is
actually called split that can split on
any characters but you can tell it what
character to use so I'm going to go back
into students. py and inside of this
Loop I'm going to go ahead and do this
I'm going to take the current line I'm
going to remove the white space at the
end as always using rst strip here and
then whatever the result of that is I'm
going to now call split and quote
unquote comma so the split function or
method comes with strings stirs in
Python any stir has this method built in
and if you pass in an argument like a
comma what this stri split function will
do is split that current string into one
two three maybe more pieces by looking
for that character again and again
ultimately strip uh ultimately split is
going to return to us a list of all of
the individual parts to the left and to
the right of those commas so I can give
myself a variable called row here and
this is a common Paradigm when you know
you're iterating over a file
specifically a CSV it's common to think
of each uh line of it as being a row and
each of the values therein separated by
commas as columns so to speak so I'm
going to deliberately name my variable
row just to be consistent with that
convention and now what do I want to
print well I'm going to go ahead and say
this print how about the following uh in
F string that starts with curly braces
well how do I get access to the first
thing in that row well the row is going
to have how many parts two because if
I'm splitting on commas and there's one
comma per line that's going to give me a
left part and a right part like hermion
and Gryffindor Harry and Gryffindor when
I have a list like row how do I get
access to individual values well I can
do this I can say Row Bracket zero and
that's going to go to the first element
of the list which should hopefully be
the student's name then after that I'm
going to say is in and I'm going to have
another curly brace here for Row Bracket
one and then I'm going to close my whole
quote so it looks a little cryptic at
first glance but most of this is just F
string syntax with curly braces to plug
in values and what values am I plugging
in well row again is a list and it has
two elements presumably Hermione in one
and Gryffindor in the other and so forth
so bracket zero is the first element cuz
remember we start indexing at zero in
Python and one is going to be the second
element so let me go ahead and run this
now and see what happens python of uh
students. py enter and we see hermion is
in Gryffindor Harry's in Gryffindor Ron
is in Gryffindor and Draco is in
Slytherin so we have now implemented our
own code from scratch that actually
parses that is reads and interprets a
CSV file ultimately here
now let me pause to see if there's any
questions but we'll make this even
easier to read in just a moment any
questions on what we've just done here
by splitting by comma so my question is
uh can we uh edit any line of code
anytime we want or uh the only option
that we have is to append uh the lines
or uh let's say if we want to let's say
change Harry's uh house to let's say
Slytherin or some other house
yeah a really good question what if you
want to in Python change a line in the
file and not just uh a pen to the end
you would have to implement that logic
yourself so for instance you could
imagine now opening the file and reading
all of the contents in then maybe
iterating over each of those lines and
as soon as you see that the current name
equals equals Harry you could maybe
change his house to slitherin and then
it would be up to you though to write
all of those changes back to the file so
in that case you might want to in
simplest form read the file once and let
it close then open it again but open for
writing and change the whole file it's
not really possible or easy to go in and
change just part of the file though you
can do it it's easier to actually read
the whole file make your changes in
memory then write the whole file out but
for larger files where that might be
quite slow you can be more clever than
that well let me propose now that we
clean this up a little bit because I
actually think this is a little cryptic
to read Row Bracket Z Row Bracket one
it's it's not that well written at the
moment I would say but it turns out that
when you have a variable that's a list
like row you don't have to throw all of
those variables into a list you can
actually unpack that whole sequence at
once that is to say if you know that a
function like split returns a list but
you know in advance that it's going to
return two values in a list the first
and the second you don't have to throw
them all into a variable that itself is
a list you can actually unpack them
simultaneously into two variables doing
name comma house so this is a nice
python technique to not only create but
assign automatically in parallel two
variables at once rather than just one
so this will have the effect of putting
the name in the left Hermione and it
will have the effect of putting
Gryffindor the house in the right
variable and we now no longer have a row
we can now make our code a little more
readable by now literally just saying
name down here and for instance house
down here so just a little more readable
even though functionally the code now is
exactly the
same all right so this now works and
I'll confirm as much by just running it
once more python of students. py enter
and we see that the text is as intended
but suppose for the sake of discussion
that I'd like to sort this list of
output I'd like to say hello again to
Draco first then hello to Harry then
Hermione then Ron how can I go about
doing this well let's take some
inspiration from the previous example
where we were only dealing with names
and instead do it with these full
phrases so and so is in house well let
me go ahead and do this I'm going to go
ahead and start scratch and give myself
a list uh called students equal to an
empty list initially and then with open
students. CSV as file I'm going to go
ahead and say this for line in file and
then below this I'm going to do exactly
as before name comma house equals the
current line stripping off the white
space at the end splitting it on a comma
so that's exact same as before but this
time before I go about uh printing the
sentence I'm going to store it
temporarily in a list so that I can
accumulate all of these sentences and
then sort them later so let me go ahead
and do this students which is my list do
append let me append the actual sentence
I want to show on the screen so another
F string so name is in house just as
before but notice I'm not printing that
sent sentence I'm appending it to my
list not a file but to my list why am I
doing this well just because as before I
want to do this for student in the
sorted students I want to go ahead and
print out student like this let me go
ahead and run python of students. py and
hit enter now and I think we'll see
indeed Draco is now first Harry is
second hermion is third and Ron is
fourth but this is arguably a little
sloppy right it seems a little hackish
that I'm constructing these sentences
and even though I'm technically want to
sort by name I'm technically sorting by
these whole English sentences so it's
not wrong it's achieving the intended
result but it's not really welld
designed because I'm just kind of
getting lucky that English is reading
from left to right and therefore when I
print this out it's sorting properly it
would be better really to come up with a
technique for sorting by the students
names not by some English sentence that
I've constructed here online six so to
achieve this I'm going to need to make
my life more complicated for a moment
and I'm going to need to collect
information about each student before I
bother assembling that sentence so let
me propose that we do this let me go
ahead and undo these last few lines of
code so that we currently have two
variables name and house Each of which
has name and the student's house
respectively and we still have our
Global variable students but let me do
this recall that python supports
dictionaries and dictionaries are just
collections of keys and values so you
can associate something with something
else like a name with Hermione like a
house with Gryffindor that really is a
dictionary so let me do this let me
temporarily create a dictionary that
stores this Association of name with
house let me go ahead and do this let me
say that the student here is going to be
represented initially by an empty
dictionary and just like you can create
an empty list with square brackets you
can create an empty dictionary with
curly braces so give me an empty
dictionary that will soon have two keys
name and house how do I do that well I
could do it this way student Open
Bracket name equals the student's name
that we got from the line student
bracket house equals the house that we
got from the line and now I'm going to
append to the students list plural that
particular student now why have I done
this I've admittedly made my code more
complicated it's more lines of code
but I've now collected all of the
information I have about students while
still keeping track what's a name what's
a house the list meanwhile has all of
the students names and houses together
now why have I done this well let me for
the moment just do something simple let
me do for student in students and let me
very Simply Now say print the following
F string the current student with this
name uh is in this current student
house and now notice one detail inside
of this F string I'm using my curly
braces as always I'm using inside of
those curly braces the name of a
variable as always but then I'm using
not bracket zero or one because these
are dictionaries now not list but why am
I using single quotes to surround house
and to surround
name why single quotes inside of this F
string
to access those keys yes um because you
have double quotes in that in that line
12 and so you have to tell p python to
differentiate exactly because I'm
already using double quotes outside of
the F string if I want to put quotes
around any strings on the inside which I
do need to do for dictionaries because
recall when you index into a dictionary
you don't use numbers like lists 0 1 two
onward you instead use strings which
need to be quoted but if you're already
using double quotes it's easiest to then
use single quotes on the inside so
python doesn't get confused about what
lines up with what so at the moment when
I run this program it's going to print
out those hellos but they're not yet
sorted in fact what I now have is a list
of dictionaries and nothing is yet
sorted but let me tighten up the code
too to point out that it doesn't need to
be quite as verbose if you're in the
habit of creating an empty dictionary
like this on line six and then
immediately putting in Keys name and
house each with two values name and
house respectively you can actually do
this all at once so let me show you a
slightly different syntax I can do this
give me a variable called student and
let me use curly braces on the right
hand side here but instead of leaving
them empty let's just Define those keys
and those values now quote unquote name
will be name and quote unquote house
will be house this achieves the exact
same effect in one line instead of three
it creates a new non dictionary
containing a name key the value of which
is the student's name and a house key
the value of which is the student's
house nothing else needs to change that
will still just work so that if I again
run python of students. I'm still seeing
those greetings but they're still not
quite actually sorted well what might I
go about doing here in order to what
could I do to improve upon this further
well we need some mechanism now of
sorting those students but unfortunately
you can't do this we can't sort all of
the students now because those students
are not names like they were before they
aren't sentences like they were before
each of the students is a dictionary and
it's nonobvious how you would sort a a
dictionary inside of a list so ideally
what do we want to do if at the moment
we hit hit line nine we have a list of
all of these students and inside of that
list is one dictionary per student and
each of those dictionaries has two keys
name and house
wouldn't it be nice if there were a way
in code to tell python sort this list by
looking at this key in each dictionary
because that would give this the ability
to sort either by name or even by house
or even by any other field that we add
to that file so it turns out we can do
this we can tell the sorted function not
just to reverse things or not it takes
another positional it takes another
named parameter called key where you can
specify what key should be used in order
to sort some list of dictionaries and
I'm going to propose that we do this I'm
going to first Define a function
temporarily for now called get name and
this function's purpose in life given a
student is to quite simply return the
student's name from that particular
dictionary so if student is a dictionary
this is going to return literally the
student's name and that's it that's the
sole purpose of this function in life
what do I now want to do well now that I
have a function that given a student
will return to me the student's name I
can do this I can change sorted to say
use a key that's equal to whatever the
return value of get name is and this now
is a feature of python python allows you
to pass functions as arguments in two
other functions so get name is a
function sorted is a function and I'm
passing in get name to sorted as the
value of that key parameter now why am I
doing that well if you think of the get
name function as just a bunch a block of
code that will get the name of a student
that's handy because that's the
capability that sorted needs when given
a list of students Each of which is a
dictionary sorted needs to know how do I
get the name of the student in order to
do alphabetical sorting for you the
authors of python didn't know that we
were going to be creating students here
in this class so they couldn't have
anticipated writing code in advance that
specifically sorts on a field called
student let alone called name name let
alone house so what did they do they
instead built into the sorted function
this named parameter key that allows us
all these years later to tell their
function sorted how to sort this list of
dictionaries so now watch what happens
if I run python of students. py and hit
enter I now have a sorted list of output
why because now that list of
dictionaries has all been sorted by the
student's name I can further do this if
as before we want to reverse the whole
thing by saying reverse equals true we
can do that too let me rerun python of
students. and hit enter now it's revers
now it's Ron than hermion Harry and
Draco but we can do something different
as well what if I want to sort for
instance by house name reversed I could
do this I could change this function
from get name to get house I could
change the implementation up here to be
get house and I can return not the
student's name but the student's house
and so now notice if I run python of
students. piy enter notice now it is
sorted by house in reverse order
Slytherin is first and then Gryffindor
if I get rid of the reverse but keep the
get house and rerun this program now
it's sorted by house Gryffindor is first
and Slytherin is last and the upside now
of this is because I'm using this list
of dictionaries and keeping the students
data together until the last minute when
I'm finally doing the printing I now
have full control over the information
itself and I can sort by this or that I
don't have to constru construct those
sentences in advance like I rather hack
asly did the first time all right that
was a lot let me pause here to see if
there are questions so when when we
sorting the files should we every time
should we use the uh Loops or like a
like a d dictionary or or any kind of
list can we sort by just sorting now
looping or any kind of stuff a good
question and the short answer with
python alone you're the programmer you
need to do the Sorting with libraries
and other techniques absolutely you can
do more of this automatically because
someone else has written that code what
we're doing at the moment is doing
everything from scratch ourselves but
absolutely with other functions or
libraries some of this could be made uh
more uh easily done some of this could
be made uh easier other questions
on this technique here it equal to the
returned value of the
function can it be equal to just
a a variable
or a value it well yes it should equal a
value so I'm spec and I should clarify
actually since this was not obvious so
when you pass in a function like get
name or get house to the sorted function
as the value of key that function is
automatic ially called by the get by the
sorted function for you on each of the
dictionaries in the list and it uses the
return value of get name or get house to
decide what strings to actually use to
compare in order to decide which is
alphabetically correct so this function
which you pass just by name you do not
pass in parentheses at the end is called
by the sorted function in order to
figure out for you how to compare these
same values
how can we use nested dictionaries I
have read about nested dictionaries what
is the difference between Ned
dictionaries and dictionary inside a
list I think it is sure um uh so we are
using a list of dictionaries why because
each of those dictionaries represents a
student and a student has a name in a
house and we want to I claim maintain
that Association and it's a list of
students because we've got multiple
students four in this case you could
create a a structure that is a
dictionary of dictionaries but I would
argue it just doesn't solve a problem I
don't need a dictionary of dictionary I
need a list of key value pairs right now
that's all so let me propose if we go
back to students. py here and we revert
back to the approach where we have get
name as the function both used and
defined here and that function Returns
the student's name what happens to be
clear is that the sorted function will
use the value of key get name in in this
case calling that function on every
dictionary in the list that it's
supposed to sort and that function get
name Returns the string that sorted
we'll actually use to decide whether
things go in this order left right or in
this order right left it alphabetizes
things based on that return value so
notice that I'm not calling the function
get name here with parenthesis I'm
passing it in only by its name so that
the sorted function can call that get
name function for me now it's turns out
as always if you're defining something
be it a variable or in this case a
function and then immediately using it
but never once again needing the name of
that function like get name we can
actually tighten this code up further I
can actually do this I can get rid of
the get name function Al together just
like I could get rid of a variable that
isn't strictly necessary and instead of
passing key the name of a function I can
actually Pass Key what's called in a
Lambda function which is an a function a
function that just has no name why
because you don't need to give it a name
if you're only going to call it in one
place and the Syntax for this in
Python's a little weird but if I do key
equals literally the word Lambda then
something like student which is the name
of the parameter I expect this function
to take and then I don't even type the
return key i instead just say student
bracket name so what am I doing here
with my code this code here that I've
highlighted is equivalent to to the get
name function I implemented a moment ago
the syntax is admittedly a little
different I don't use def I didn't even
give it a name like get name i instead
I'm using this other keyword in Python
called Lambda which says Hey python here
comes a function but it has no name it's
Anonymous that function takes a
parameter I could call it anything I
want I'm calling it student why because
this function that's passed in as key is
called on every one of the students in
that list every one of the dictionaries
in that list what do I want this
Anonymous function to return well given
a student I want to index into that
dictionary and access their name so that
the string Hermione and Harry and Ron
and Draco is ultimately returned and
that's what the sorted function uses to
decide how to sort these bigger
dictionaries that have other Keys like
house as well so if I now go back to my
terminal window and run python of
students. it still seems to work the
same but it's arguably a little better
design because I didn't waste lines of
Code by defining some other function
calling it in one and only one place
I've done it all sort of in one breath
if you will all right let me pause here
to see if there's any questions
specifically about Lambda or Anonymous
functions and this tightening up of the
code and I had one question like whether
we could Define Lambda twice can you you
can use Lambda twice you can create as
many Anonymous functions as you'd like
and you generally use them in context
like this where you want to pass to some
other function uh a function that itself
does not need a name so you can
absolutely use it in more than one place
I just have only one use case for it how
about one other question on Lambda or
Anonymous functions specifically what
what if our
Lambda would take more than one line for
example if sure if your Lambda function
takes multiple parameters that is fine
you can simply specify commas follow by
the names of those parameters maybe X
and Y or so forth after the name student
so here too Lambda looks a little
different from DEA in that you don't
have parentheses you don't have the
keyword def you don't have a function
name but ultimately they achieve that
same effect they create a function
anonymously and allow you to pass it in
for instance as some value here so let's
now change students. CSV to contain not
students houses at Hogwarts but their
homes where they grew up so Draco for
instance grew up in Malfoy Manor uh Ron
grew up in the burrow uh Harry grew up
in uh number four privet drive and
according to the internet no one knows
where hermion grew up the movies
apparently took certain liberties with
where she grew up so for this purpose
we're actually going to remove Hermione
because it is unknown exactly where she
was born so we still have some three
students but if anyone can spot the
potential problem now how might this be
a bad thing well let's go and try and
run our own code here let me go back to
students. py here and let me propose
that I just change my semantics because
I'm now not thinking about Hogwarts
houses but the students own home so I'm
just going to change some variables I'm
going to change this house to a home
this house to a home as well as this one
here I'm still going to sort the
students by name but I'm going to say
that they're not in a house but rather
from a home so I've just Chang the names
of my variables in my grammar in English
here ultimately to print out that for
instance Harry is from number four
privet drive and so forth but let's see
what happens here when I run python of
this version of students. having changed
students. CSV to contain those homes and
not houses
enter huh our first value error like the
program just doesn't work What might
explain this value error the explanation
of which rather cryptically is too many
values to unpack and the line in
question is this one involving split how
did all of a sudden after all of these
successful runs of this program did line
five suddenly now break in the line in
students that says we you have three
values there's a line that you have
three values and and students yeah I
spent a lot of time trying to figure out
where uh every student should be from so
that we could create this problem for us
and wonderfully like the first sentence
of the book is number four privet drive
and so the fact that that address has a
comma in it is problematic why because
you and I decided some time ago to just
standardize on commas CSV comma
separated values to denote the uh uh we
standardized on commas in order to
delineate one value from another and if
we have commas grammatically in the
student's home we're clearly confusing
it as this special symbol and the split
function is now for just Harry trying to
split it into three values not just two
and that's why there's too many values
to unpack because we're only trying to
assign two variables name and house now
what could we do here well we could just
change our approach for instance like
one Paradigm that is not uncommon is to
use something uh a little more um a
little less common like a vertical bar
so I could go in and change all of my
commas to Vertical bars that too could
eventually come back to bite Us in that
if my file eventually has vertical bars
somewhere it might still break so maybe
that's not the best approach I could
maybe do something like this I could
escape the data as I've done in the past
and maybe I could put quotes around any
English string that itself contains a
comma and that's fine I could do that
but then my code students. py is going
to have to change too because I can't
just naively split on a comma Now I'm
going to have to be smarter about it I'm
going to have to take into account split
only on the commas that are not inside
of quotes and oh it's getting
complicated fast and at this point you
need to take a step back and consider
you know what if we're having this
problem odds are many other people
before us have had this same problem it
is incredibly common to store data in
files it is incredibly common to use CSV
files specifically and so you know what
why don't we see if there's a library in
Python that exists to read Andor write
CSV files rather than reinvent a wheel
so to speak let's see if we can write
better code by standing on the shoulders
of others who have come before us
programmers passed and actually use
their code to do the reading and writing
of csvs so we can focus on the part of
our problem that you and I care about so
let's propose that we go back to our
code here and see how we might use the
CSV Library indeed within python there
is a module called CSV the documentation
for it is at this URL here in Python's
official documentation but there's a few
functions that are pretty readily
accessible if we just Dive Right In and
let me OS that we do this let me go back
to my code here and instead of
Reinventing this wheel and reading the
file line by line and splitting on
commas and dealing now with quotes and
privet drives and so forth let's do this
instead at the start of my program let
me go up and import the CSV module let's
use this library that someone else has
written that's dealing with all of these
Corner cases if you will I'm still going
to give myself a list initially empty in
which to store all these students but
I'm going to change my Approach here now
just a little bit when I open this file
with width let me go in here and change
this a little bit I'm going to go in
here now and say this uh reader equals
csvreader passing in file as input so it
turns out if you read the documentation
for the CSV module it comes with a
function called reader whose purpose in
life is to read a CSV file for you and
figure out where are the commas where
are the quotes where are all the the
potential Corner cases and just deal
with them for you you can override
certain defaults or assumptions in case
you're using not a comma but a pipe or
something else but by default I think
it's just going to work now how do I
iterate over a reader and not the raw
file itself it's almost the same the
library allows you still to do this for
each row in the reader so you're not
iterating over the file directly now
you're iterating over the reader which
is again going to handle all of the
parsing of comma in new lines and more
for each row in the reader what am I
going to do well at the moment I'm going
to do this I'm going to append to my
students list the following dictionary a
dictionary that has a name whose value
is the current Row's First Column and
whose house or rather home now is the
Row's second column now it's worth
noting that the reader for each line in
the file indeed returns to me a row but
it returns to me a row that's a list
which is to say say that the first
element of that list is going to be the
student's name as before the second
element of that list is going to be the
student's home uh as now before but if I
want to access each of those elements
remember that lists are zero indexed we
start counting at zero and then one
rather than one and then two so if I
want to get at the student's name I use
Row Bracket zero and if I want to get at
the student's home I use Row Bracket one
but in my four Loop we can do that same
unpacking as before if I know this CSV
is only going to have two columns I
could even do this for name home in
reader and now I don't need to use list
notation I can unpack things all at once
and say name here and home here the rest
of my code can stay exactly the same
because what am I doing now on line 8
I'm still constructing the same
dictionary as before albeit for homes
instead of houses and I'm grabbing those
values now not from the file itself and
my use of split but the reader and again
what the reader is going to do is figure
out where are those commas where are the
quotes and just solve that problem for
you so let me go now down to my terminal
window and run python of students. and
hit enter and now we see successfully
sorted no less that Draco is from Mal
for Manor Harry is from number four
comma Private Drive and Ron is from the
burrow questions now on this technique
of using CSV reader from that CSV module
which again is just getting us out of
the business of reading each line our in
Reading each of those commas and
splitting so my question is related to
something a bit bit in the past um I
recognize that you are reading a file
every time you well you we're we're
assuming that we have the CSV file to
hand already in this case um is it
possible to make a file readable and
writable so in in in in case if you want
you could you could write stuff to the
but then at the same time you could have
another function that reads through the
file and as changes to it as you go
along a really good question and the
short answer is yes however historically
the mental model for a file is that of a
cassette tape years ago not really in
use anymore but cassette tapes are
sequential whereby they start at the
beginning and if you want to get to the
end you kind of have to uh unwind the
tape to get to that point the closest
analog nowadays would be something like
Netflix or any streaming service where
there's a scrubber that you have to go
left to right you can't just jump there
or jump there you don't have Random
Access so the problem with files if you
want to read and write them you or some
Library needs to keep track of where you
are in the file so that if you're
reading from the top and then you write
at the bottom and you want to start
reading again you seek back to the
beginning so it's not something we'll do
here in class it's more involved but
it's absolutely doable for our purposes
we'll generally recommend read the file
and then if you want to change it write
it back out rather than trying to make
more peac mail changes which is good if
the though the file is massive and it
would just be very expensive TimeWise to
change the whole thing other questions
on this CSV reader is possible to write
uh a paragraph in that file absolutely
right now I'm writing very small strings
just names or houses as I did before but
you can absolutely write as much text as
you want indeed other questions on CSV
reader can user choose
himself a key like input key will be a
name or home so short answer yes we
could absolutely write a program that
prompts the user for a name and a home a
name and a home and we could write out
those values and in a moment we'll see
how you can write to a CSV file for now
I'm assuming as the programmer who
created students. CSV that I know what
the columns are going to be and
therefore I'm naming my variables
accordingly however this is a good seg
way to one final feature of reading csvs
which is that you don't have to rely on
either getting a row as a list and using
bracket zero or bracket one and you
don't have to unpack things manually in
this way we could actually be smarter
and start storing the names of these
columns in the CSV file itself and in
fact if any of you have ever opened a
spreadsheet file before be it in Excel
Apple Numbers Google spreadsheets or the
like odds are you've noticed that the
first row very frequently is a little
different it actually is boldface
sometimes or it actually contains the
names of those columns the names of
those attributes below and we can do
this here in students. CSV I don't have
to just keep assuming that the student's
name is first and that the student's
home is second I can explicitly bake
that information into the file just to
reduce the probability of mistakes down
the road I can literally use the first
row of this file and say name comma home
so notice that name is not literally
something some 's name and home is not
literally someone's home it is literally
the words name and home separated by a
comma and if I now go back into
students. py and don't use CSV reader
but instead I use a dictionary reader I
can actually treat my CSV file even more
flexibly not just for this but for other
examples too let me do this instead of
using a CSV reader let me use a CSV dict
reader which will now iterate over the
file top to bottom loading in each line
of text not as a list of columns but as
a dictionary of columns what's nice
about this is that it's going to give me
automatic access now to those columns
names I'm going to revert to just saying
for Row in reader and now I'm going to
append a name and a home but how am I
going to get access to the current rows
name and the current rows home well
earlier I used bracket zero for the
first and bracket one for the second
when I was using a reader a reader
returns lists a dict reader or
dictionary reader returns dictionaries
one at a time and so if I want to access
the current Row's name I can say row
quote unquote name I can say here for
home row quote unquote home and I now
have access to those same values the
only change I had to make to be clear
was in my CSV file I had to include on
the very first row little hints as to
what these columns are and if I now run
this code I think it's should behave
pretty much the same python of students.
and indeed we get the same sentences but
now my code is more robust against
changes in this data if I were to open
the CSV file in Excel or Google
spreadsheets or apple numbers and for
whatever reason change the columns
around maybe this is a file that you're
sharing with someone else and just
because they decide to sort things
differently left or right by moving the
columns around previously my code would
have broken because I was assuming that
name is always first and home is always
second but if I did this be it manually
in one of those programs or here home
comma name and suppose I reversed all of
this the home comes first followed by
Harry the burrow then by Ron and then
lastly Maloy Manor then Draco notice
that my file is now completely flipped
the First Column is now the second and
the second's the first but I took care
to update the header of that file the
first row notice my python code I'm not
going to going to touch it at all I'm
going to rerun python of students. py
and hit enter and it still just works
and this too is an example of like
coding defensively like what if someone
changes your CSV file your data file
ideally that won't happen but even if it
does now because I'm using a dictionary
reader that's going to infer from that
first row for me what the columns are
called my code just keeps working and so
it keeps getting if you will better and
better any questions now on this
approach yeah what is the importance of
new line CSV file what's the importance
of the new line in the CSV file it's
partly a convention in the world of text
files we humans have just been for
decades in the habit of storing um data
line by line it's visually convenient
it's just easy to extract from the file
because you just look for the new lines
so the new line just separates some data
from some other data we could use any
other symbol on the keyboard but it's
just common to hit enter to just move
the data to the next line just a
convention other questions it seems to
be working fine if you just have name
and home I'm wondering what will happen
if you want to put in more
data um say you wanted to add the house
to both the name and the home sure if
you wanted to add the house back so if I
go in here and add house last and I go
here and say uh Gryffindor for Harry
Gryffindor for Ron and Slither in for
Draco now I have three columns
effectively if you will home on the left
name in the middle house on the right
each separated by commas with weird
things like number four comma privet
Drive still quoted notice if I go back
to students. py and I don't change the
code at all and run python of students
dopy it still just works and this is
what's so powerful about a dictionary
reader it can change over time it can
have more and more columns your existing
code is not going to break your code
would break would be much more fragile
so to speak if you were making
assumptions like the first column's
always going to be name the second
column's always going to be house things
will break fast if those assumptions
break down so not a problem in this case
well let me propose that besides reading
csvs let's at least take a peek at how
we might write a CSV too if you're
writing a program in which you want to
store not just students names but maybe
their homes as well in a file how can we
keep adding to this file let me go ahead
and delete the contents of students. CSV
and just read a single simple row name
comma home so as to anticipate inserting
more names and homes into this file and
then let me go to students. py and let
me just start fresh so as to write out
data this time I'm still going to go
ahead and import CSV I'm going to go
ahead now and prompt the user for their
name so input quote unquote what's your
name question mark and I'm going to go
ahead and prompt the user for their home
so home equals input quote unquote
where's your home question mark now I'm
going to go ahead and open the file but
this time for writing instead of reading
as follows with open quote unquote
students. CSV I'm going to open it in
append mode so that I keep adding more
and more students and homes to the file
rather than just overwriting the entire
file itself and I'm going to use a
variable name of file I'm then going to
go ahead and give myself a variable
called writer and I'm going to set it
equal to the return value of another
function in the CSV module called CSV do
writer and that writer uh function takes
as its sole argument the file variable
there now I'm going to go ahead and just
do this I'm going to say writer. WR row
and I'm going to pass into WR Row the
line that I want to write to the file
specifically as a list so I'm going to
give this a list of name comma home
which of course are the contents of
those variables now I'm going to go
ahead and save the file I'm going to go
ahead and rerun python of students. hit
enter and what's your name well let me
go ahead and type in Harry as my name
and number
four comma Private Drive enter now
notice that input itself did have a
comma and so if I go to my CSV file now
notice that it's automatically been
quoted for me so that subsequent reads
from this file don't confuse that comma
with the actual comma between Harry and
his home well let me go ahead and run it
a couple of more times let me go ahead
and rerun python of students. py let me
go ahead and input this time Ron and his
home as the burrow let's go back to
students. CSV to see what it looks like
now we see Ron comma the burough has
been added automatically to the file and
let's do one more python of students.
enter let's go ahead and give draco's
name and his home which would be Malfoy
Manor enter and if we go back to
students. CSV now we see that Draco is
in the file itself and the library took
care of not only writing each of those
rows per the function name it also
handled the escaping so to speak of any
strings that themselves contained a
comma like Harry's own home well it
turns out there's yet another way we
could implement this same program
without having to worry about precisely
that order again and again and just
passing in a list it turns out if we're
keeping track of what's the name and
what's the home we could use something
like a dictionary to associate those
keys with those values so let me go
ahead and back up and remove these
students from the file leaving only the
header row again name comma home and let
me go over to students. py and this time
instead of using CSV writer I'm going to
go ahead and use CSV do dict writer
which is a dictionary writer that's
going to open the file in much the same
way but rather than write a row as this
list of name comma home what I'm now
going to do is follows I'm going to
first uh output an actual dictionary the
first key of which is Name colon and
then the value thereof is going to be
the name that was typed in and I'm going
to pass in a key of Home quote unquote
the value of which of course is the home
that was typed in but with dict writer I
do need to give it a hint as to the
order in which those columns are when
writing it out so that subsequently they
could be read even if those orderings
change let me go ahead and pass in field
names which is a second argument to dict
writer equals and then a list of the
actual columns that I know are in this
file which of course are name comma home
those times in quotes because that's
indeed the string names of the column so
to speak that I intend to write to in
that file all right now let me go ahead
and go to my terminal window run python
of students. py this time I'll type in
Harry's name again I'll again type in
number four comma Private Drive enter
let's now go back to students. CSV and
voila Perry's back in the file and it's
properly escaped or quoted I'm sure then
if we do this again with Ron and the
burrow and let's go ahead and run it one
third time with Draco and Malfoy Manor
enter let's go back to students. CSV and
Via this dictionary writer we now have
all three of those students as well so
whereas with CSV writer the onus is on
us to pass in a list of all of the
values we want to put from left to right
with a dictionary writer technically
they could be in any order in the
dictionary in fact I could just have
correctly done this passing in home
followed by name but it's a dictionary
and so the ordering in this case does
not matter so long as the key is there
and the value is there and because I
have passed in field names as the second
argument to dict writer it ensures that
the library knows exactly which column
contains name or home respectively are
there any questions now on dictionary
reading dictionary writing or csvs more
generally inia any specific specific
situation for me to use single quotation
or double quotation because uh after the
print we use single quotation to
represent the key of the dictionary but
after the reading or writing we use the
double
quotation it's a a good question in
Python you can generally use double
quotes or you can use single quotes and
it doesn't matter you should just be
self-consistent so that stylistically
your code looks the same all throughout
sometimes though it is necessary to
alternate if you're already using double
quotes as I was earlier for a long f
string but inside that F string I was
interpolating the values of some
variables using curly braces and those
variables were dictionaries and in order
to index into a dictionary you use
square brackets and then quotes but if
you're already using double quotes out
here you should generally use single
quotes here or vice versa but otherwise
I'm in the habit of using double quotes
everywhere others are in the habit of
using single quotes everywhere it only
matters sometimes if one might be
confused for the other
other questions on dictionary writing or
reading uh yeah d uh my question is can
we use multiple CSV files in any program
absolutely you can use as many CSV files
as you want and it's just one of the
formats that you can use to save data
other questions on csvs or file IO
thanks for taking my question uh so when
you're reading from the file the um you
had the um uh as a as a dictionary you
had the fields called um couldn't you
just call when you're reading could
couldn't you just call the row in the
previous version of the of the students
uh P file um when you're reading the uh
when you're reading each row you are
splitting out the um the fields by
name yeah so when you're pending to the
uh to the students list can you just
call the uh for row and reader students.
append row rather than uh rather than
naming each of the fields oh very clever
uh short answer yes in so far as dict
reader returns one dictionary at a time
when you Loop over it row is already
going to be a dictionary so yes you
could actually get away with doing this
and the effect would really be the same
in this case good observation how about
one more question on
csvs yeah uh when reading in csvs from
my past work with data a lot of things
can go wrong I don't know if it's a fair
question that you can answer in a few
sentences but are there any best
practices to double check that sort of
no mistakes occurred it's a really good
question and I would say in general if
you're using code to generate the csvs
and to read the csvs and you're using a
good Library theoretically nothing
should go wrong it should be 100%
correct if the libraries are 100%
correct uh you and I tend to be the
problem like when you let a human touch
the CSV or when Excel or apple numbers
or some other tools involve that might
not be aligned with your codes
expectations things then yes can break
um the goal really sometimes honestly
the solution is manual fixes you go in
and fix the CSV or you have a lot of
error checking or you have a lot of try
except just to tolerate mistakes in the
data but generally I would say if you're
using CSV or any file format internally
to a program to both read and write it
you shouldn't have concerns there you
and I the humans are the problem
generally speaking and not the
programmers the users of those files
instead all right allow me to propose
that we leave csvs behind but to note
that they're not the only file format
you can use in order to read or write
data in fact they're a popular format as
is just raw text files. txt files but
you can store data really any way that
you want we've just picked csvs because
it's representative of how you might
read and write from a file and do so in
a structured way where you can somehow
have multiple Keys multiple values all
in the same file without having to
resort to what would be otherwise known
as a binary file so a binary file is a
file that's really just zeros and ones
and they can be laid out in any pattern
you might want particularly if you want
to store not textual information but
maybe graphical or audio or video
information as well so it turns out that
python is really good when it comes to
having libraries for really everything
and in fact there's a popular Library
called pillow that allows you to
navigate image files as well and to
perform operations on image files you
can apply filters aot Instagram you can
uh animate them as well and so what I
thought we'd do is leave behind text
files for now and Tackle one more
demonstration this time focusing on uh
this particular library and image files
instead so let me propose that we go
over here to VSS code and create a
program ultimately that creates an anim
GIF these things are everywhere nowadays
in the form of memes and animations and
stickers and the like and an animated
gif is really just an image file that
has multiple images inside of it and
your computer or your phone shows you
those images one after another sometimes
on an endless loop again and again and
so long as there's enough images it
creates the illusion of Animation
because your mind and mind kind of fills
in the gaps visually and just assumes
that if something is moving even though
you're only seeing one frame per second
or some sequence thereof it looks like
an animation so it's like a simplistic
version of a video file well let me
propose that we start with maybe a
couple of uh costumes from another
popular programming language and let me
go ahead and open up my first costume
here number one so suppose here that
this is a costume or really just a
static image here costume 1.f and it's
just a static picture of a cat no
movement at all let me go ahead now and
open up a second one costume 2.gif that
looks a little bit different notice and
I'll go back and forth this cat's legs
are a little bit aligned differently so
that this was version one and this was
version two now these cats come from a
programming language from MIT called
scratch that allows you very graphically
to animate all this and more but we'll
use just these two static images costume
one and costume 2 to create our own
animated gif that after this you could
text to a friend or message them um much
like any meme online well let me propose
that we create this animated gif not by
just using some off-the-shelf program
that we downloaded but by writing our
own code let me go ahead and run code of
costumes. and create our very own
program that's going to take as input
two or even more image files and then
generate an animated gif from them by
essentially creating this animated gif
by toggling back and forth endlessly
between those two images well how am I
going to do this well let's assume that
this will be a program called costumes.
that expects uh two command line
arguments the names of the files the
individual costumes that we want to
animate back and forth so to do that I'm
going to import CIS so that we
ultimately have access to cis.org V I'm
then from this pillow Library going to
import support for images specifically
so from pil import image capital i as
per the library's documentation now I'm
going to give myself an empty list
called images just so I have a list in
which to store one or two or or more of
these images and now let me do this for
each argument in cy. argv I'm going to
go ahead and create a new image variable
set it equal to this image uh doop
function passing in ARG now what is this
doing I proposing that eventually I want
to be able to run python of costumes.
piy and then as command line argument
specify costume 1.f space costume 2. so
I want to take in those file names from
the command line as my arguments so what
am I doing here well I'm iterating over
sis. argv all of the words in my command
line arguments I'm creating a variable
called image and I'm passing to this
function image. open from the pillow
library that specific argument and that
library is essentially going to open
that image in a way that gives me a lot
of functionality for manipulating it
like animating now I'm going to go ahead
and uh pen to my images list that
particular image and that's it so this
Loop's purpose in life is just to
iterate over the command line arguments
and open those images using this Library
the last line is pretty s
straightforward I'm going to say this
I'm going to grab the first of those
images which is going to be in my list
at location zero and I'm going to save
it to disk that is I'm going to save
this file now in the past when we use
csvs or text files I had to do the file
opening I had to do the file writing
maybe even the closing I don't need to
do that with this Library the pillow
library takes care of the opening the
closing and the saving for me by just
calling save I'm going to call this save
function and just to leave space because
I have a number of arguments to pass I'm
going to move to another line so it fits
I'm going to pass in the name of the
file that I want to create costume. GIF
that will be the name of my animated gif
I'm going to tell this library to save
all of the frames that I passed to it so
the First costume the second costume and
even more if I gave them I'm going to
then append to this first image
the images zero uh the following images
equals this list of images and this is a
bit clever but I'm going to do this I
want to append the next image there
images one and now I want to specify a
duration of 200 Mill seconds for each of
these frames and I want this to Loop
forever and if you specify Loop equals
zero that is Time Zero it means it's
just not going to Loop an finite number
of times but an infinite number of times
instead and I need to do do one other
thing recall that sis. argv contains not
just the words I typed after my
program's name but what else does cy.
argv contain if you think back to our
discussion of command line
arguments what else is in sis. RGV
besides the words I'm about to type like
costume 1.f and costume 2 yeah so we'll
actually get in the the original name of
the program we want to run the costume
at p and we'll get the original name of
the program costumes. in this case which
is not a gif obviously so remember that
using slices in Python we can do this if
cy. Arvy is a list and we want to get a
slice of that list everything after the
first element we can do one colon which
says start at location one not zero and
take a slice all the way to the end so
give me everything except the first
thing in that list which to McKenzie's
point is the name of the program now if
I haven't made any mistakes let's see
what happens I'm going to run python of
costumes. piy and now I'm going to
specify the two images that I want to
animate so costume 1.f and costume
2.if what is the code now going to do
well to recap we're using the Cy library
to access those command line arguments
we're using the pillow library to treat
those files as images and with all the
functionality that comes with that
Library I'm using this images list just
to accumulate all of these images one at
a time from the command line and in
lines 7 through n I'm just using a loop
to iterate over all of them and just add
them to this list after opening them
with the library and the last step which
is really just one line of code broken
on to three so that it all fits I'm
going to save the first image but I'm
asking the library to append this other
image to it as well not bracket zero but
bracket one and if I had more I could
express those as well I want to save all
of these files together I want to pause
200 milliseconds a fifth of a second in
between each frame and I want it to Loop
infinitely many times so now if I cross
my fingers as always hit enter nothing
bad happened and that's almost always a
good thing let me now run code of
costumes. GIF to open up in VSS code the
final image and what I think I should
see is a very happy cat and indeed so
now we've seen not only that we can read
and write files be it textually we can
read and now write files that are binary
zeros and ones we've just scratched the
surface this is using the library called
pillow but ultimately this is going to
give us the ability to read and write
files however we want so we've now seen
that via file.io we can manipulate not
just textual files be it txt files or
csvs but even binary files as well in
this case they happen to be images but
if we dived in deeper we could find
explore audio and video and so much more
all by way of these simple Primitives
this ability somehow to read and write
files that's that's it for now we'll see
you next time
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men and this is our week on regular
Expressions so a regular expression
otherwise known as a Rex is really just
a pattern and indeed it's quite common
in programming to want to use patterns
to match on some kind of data often user
input for instance if the user types in
an email address whether to your program
or a website or an app on your phone you
might ideally want to be able to
validate that they did indeed type in an
email address and not something compl
completely different so using regular
Expressions we're going to have the new
found capability to Define patterns in
our code to compare them against data
that we're receiving from someone else
whether it's just a validated or heck
even if we want to clean up a whole lot
of data that itself might be messy
because it too came from us humans
before though we use these regular
Expressions let me propose that we solve
a few problems using just some simpler
syntax and see what kind of limitations
we run up against let me propose that I
open up via code here and let me create
a file called validate dopy the goal at
hand being to validate how about just
that a user's email address they've come
to your app they've come to your website
they type in their email address and we
want to say yes or no this email address
looks valid all right let me go ahead
and type code of validate dopy to create
a new tab here and then within this tab
let me go ahead and start writing some
code how about that keeps things simple
initially first let me go ahead and
prompt the user for their email address
and I'll store return value of input in
a variable called email asking them
what's your email question mark I'm
going to go ahead and preemptively at
least clean up the user's input a little
bit by minimally just calling strip at
the end of my call to input because
recall that input returns a string or a
stir stirs come with some built-in
methods or functions one of which is
strip which has the effect of stripping
off any leading white space to the left
or any trailing white space to the right
so that's just going to go ahead and at
least avoid the human having
accidentally typed in a space character
we're going to throw it away just in
case now I'm going to do something
simple for a user's input to be an email
address I think we can all agree that
it's got to minimally have an at sign
somewhere in it so let's start simple if
the user has typed in something with an
at sign let's very generously just say
Okay valid looks like an email address
and if we're missing that at sign let's
say invalid because clearly it's not an
email address it's not going to be the
best version of my code yet but we'll
start simple so I'm going to ask the
question if there is an at symbol in the
user's email address go ahead and print
out for instance quote unquote valid
else if there's not now I'm pretty
confident that the email address is in
fact invalid now what is this code doing
well if at sign in email is a pythonic
way of asking is this string quote
unquote at in this other string email no
matter where it is at the beginning the
middle of the end it's going to
automatically SE search through the
entire string for you automatically I
could do this more verbosely and I could
use a for Loop or a while loop and look
at every character in The user's email
address looking to see if it's an at
sign but this is one of the things
that's nice about python you can do more
with less so just by saying if at quote
unquote in email we're achieving that
same result we're going to get back true
if it's somewhere in there thus valid or
false if it is not well let me go ahead
now and run this program in my terminal
window with python of validate dopy and
I'm going to go head and give it my
email address maen harvard.edu enter and
indeed it's valid looks valid is valid
but of course this program is
technically broken it's buggy what would
be an example input if someone might
like to volunteer and answer here that
would be considered valid but you and I
know it really isn't valid yeah thank
you uh well for instance you can type
just two science science and that's it
and it still be valid still be valid
according to your program but this
exactly we've set a very low bar here in
fact if I go ahead and rerun python of
validate dopy and I'll just type in one
at sign that's it no username no domain
name this doesn't really look like an
email address but unfortunately my code
thinks it in fact is because it's
obviously just looking for an at sign
alone well how could we improve this
well minimally an email address I I
think tends to have though this is not
actually a requirement tends to have an
at sign and a single dot at least maybe
somewhere in the domain name so mailin
Harvard Dot edu so let's check for that
dot as well though again strictly
speaking doesn't even have to be that
case but I'm going for my own email
address at least for now as our test
case so let me go ahead and change my
code now and say not only if at is an
email but also uh dot is an email as
well so I'm asking now two questions I
have two Boolean Expressions if at an
email and I'm anding them together
logically this is a logical and so to
speak so if it's the case that at is an
email and Dot is an email okay now I'm
going to go ahead and say valid all
right this would still seem to work for
my email address let me go ahead and run
python of validate dopy uh maen
harvard.edu enter and that of course is
valid as expected but here too we can be
a little adversarial and type in
something nonsensical like at Dot and
unfortunately that too is going to be
mistaken as valid even though there's
still no username domain name or
anything like that so I think we need to
be a little more methodical here in fact
notice that if if I do this like this uh
the at sign can be anywhere and the dot
can be anywhere but if I'm assuming the
user is going to have a traditional
domain name like harvard.edu or
gmail.com I really want to look for the
dot in the domain name only not
necessarily just the username so let me
go ahead and do this let me go ahead and
introduce a bit more logic here and
instead do this let me go ahead and do
uh
email.it of quote unquote at sign so
email again is a string or a stir stirs
come with methods not just strip but
also another one called split that is
the name applies will split one stir
into multiple ones if you give it a
character or more to split on so this is
hopefully going to return to me two
parts from a traditional email address
the username and the domain name and it
turns out I can unpack that sequence of
respon is by doing this username comma
domain equals this I could store it in a
list or some other structure but if I
already know in advance what kinds of
values I'm expecting a username and
hopefully a domain I'm going to go ahead
and do it like this instead and just
Define two variables at once on one line
of code and now I'm going to be a little
more precise if
username uh uh if username then I'm
going to go ahead and say print valid
else I'm going to go ahead and say print
invalid now this isn't good enough but
I'm at least checking for the presence
of a username now and you might not have
seen this before but if you simply ask a
question like if username and username
is a string well usern if username is
going to give me a true answer if
username is anything except none or
quote unquote nothing so there's a
truthy value here whereby if username
has at least one character that's going
to be considered true but if username
has no characters it's going to be
considered a false value effectively but
this isn't good enough I don't want to
just check for username I want to also
check that it's the case that dot is in
the domain name as well so notice here
there's a bit of potential confusion
with the English language here I seem to
be saying if username and Dot in domain
as though I'm asking the question if the
username and the dot are in the domain
but that's not what this means these are
two separate Boolean Expressions if
username and
separately if dot in domain and if I
parenthesize this we could make that
even more clear by putting parenthesis
there parentheses here so just to be
clear it's really two Boolean
Expressions that we're anding together
not one longer english-like sentence now
if I go ahead and run this python of
validate dopy enter I'll do my own email
address again maen harvard.edu and
that's valid and it looks like I could
tolerate something like this if I do
mailin at just say Harvard I think at
the moment this is going to be invalid
now maybe the top level domain Harvard
exists but at the moment it looks like
we're looking for something more we're
looking for a top level domain too like
edu so for now we'll just consider this
to be invalid but it's not just that we
want to do it's not just that we want to
check for the presence of a username and
the presence of a dot let's be more
specific let's start to now narrow the
scope of this program not just to be
about generic emails more generally but
about edu addresses so specifically for
someone in a US University for instance
whose email address tends to end with
doedu I can be a little more precise and
you might recall this function already
instead of just saying is there a DOT
somewhere in domain let me instead say
and the domain ends with quote unquote.
edu so now we're being even more precise
we want there to be minimally a username
that's not empty it's not just quote
unquote nothing and we want the domain
name to actually end with doedu let me
go ahead and run python of validate dopy
and just to make sure I haven't made
things even worse let me at least chest
my own email address which does seem to
be valid now it seems that I minimally
need to provide a username because we
definitely do have that check in place
so I'm going to go ahead and say Ma and
now I'm going to go ahead and say at and
it looks like I could be a little
malicious here just say mailen at.edu as
though minimally meeting the
requirements of this of this pattern and
that of course is considered valid but
I'm pretty sure there's no one at mail
at.edu we need to have some domain name
in there so we're still not being quite
as generous now we could absolutely
continue to iter at on this program and
we could add some more Boolean
Expressions we could maybe use some
other python methods for checking more
precisely as there's something to the
left of the dot to the right of the dot
we could use split multiple times but
honestly this just escalates quickly
like you end up having to write a lot of
code just to express something that's
relatively simple in spirit just format
this like an email address so how can we
go about improving this well it turns
out in Python there's a library for
regular Expressions it's called ccin re
and in the re Library you have a lot of
capabilities to Define and check for and
even replace patterns again a regular
expression is a pattern and this Library
the re library in Python is going to let
us to Define some of these patterns like
a pattern for an email address and then
use some built-in functions to actually
validate a user's input against that
pattern or even use these patterns to
change the user's input or extract
partial information there from we'll see
examples of all this and more so what
can should I do with this Library well
first and foremost it comes with a lot
of functionality here is the URL for
instance to the official documentation
and let me propose that we focus on
using one of the most versatile
functions in the library library namely
this search re. search is the name of
the function in the re module that
allows you to pass in a few arguments
the first is going to be a pattern that
you want to search for in for instance a
string that came from a user the string
arguments here is going to be the actual
string that you want to search for that
pattern and then there's a third
argument optionally that's a whole bunch
of flags a flag in general is like a a
parameter you can pass in to modify the
behavior of the function but initially
we're not even going to use this we're
just going to pass in a couple of
arguments instead so let me go ahead and
employ this re Library this regular
expression library and just improve on
this design incrementally so we're not
going to solve this problem all at once
but we'll take some incremental steps
I'm going to go back to VSS code here
and I'm going to go ahead now and get
rid of most of this code but I'm going
to go into the top of my file and first
and all import this re Library so import
re gives me access to that function and
more now after I've gotten the user's
input in the same way as before
stripping off any leading or trailing
whites space I'm just going to use this
function super trivially for now even
though this isn't really a big step
forward I'm going to say if re. search
contains quote unquote at in the email
address then let's go ahead and print
valid
else let's go ahead and print invalid at
the moment this is really no better than
my very first version where I was just
asking python if at sign in the email
address but now I'm at least beginning
to use this Library by using its own re.
search function which for now you can
assume returns a a True Value
effectively if indeed the at sign is an
email just to make sure that this
version does work as I expect let me go
ahead and run python of validate dopy
and enter I'll type in in my actual
email address and we're back in business
but of course this is not great because
if I similarly run this version of the
program and just type in an at sign not
an email address and yet my code of
course thinks it is valid so how can I
do better than this well we need a bit
more vocabulary in the realm of regular
expressions in order to be able to
express ourselves a little more
precisely really the pattern I want to
ultimately Define is going to be
something like I want there to be
something to the left then an sign then
something to the right and that
something to the right should end with
edu but should also have something
before the edu like Harvard or Yale or
any other school in the US as well well
how can I go about doing this well it
turns out that in the world of regular
Expressions whether in python or a lot
of other languages as well there's
certain symbols that you can use to
define patterns at the moment I've just
used literal raw text if I go back to my
code here this technically qualifies as
a regular expression I've passed in a
quoted string inside of which is an at
sign now that's not a very interesting
pattern it's just an at sign but it
turns out that once you have access to
regular expressions or a library that
offers that feature you can more
powerfully express yourself as follows
let me reveal that the pattern that you
passed to ar. search can take a whole
bunch of special symbols and here's just
some of them in the examples we're about
to see in the patterns we're about to
Define here are the special symbols you
can use a single period a DOT to just
represent any character except a new
line a blank line so that is to say if I
don't really care what letters of the
alphabet are in the user's username I
just want there to be one or more
characters uh in the user's name dot
allows me to express a through z
uppercase and lowercase and a bunch of
other letters as well star is going to
mean in single asterisk zero or more
repetitions so if I say something star
that means that I'm willing to accept
either zero repetitions that is nothing
at all or more repetitions one or two or
three or 300 if you see a plus in my
patterns that's going to mean one or
more repetitions that is to say there's
got to be at least one character there
one symbol and then there's optionally
more after that and then you can say
zero or one repetition you can use a
single question mark after a symbol and
that will say I want zero of this
character or one but that's all I'll
expect and then lastly there's going to
be a to specify a specific number of
symbols if you use these curly braces
and a number represented here
symbolically as M you can specify that
you want M repetitions be it one or two
or three or 300 you can specify the
number of repetitions yourself and if
you want a range of repetitions like you
want this few characters or this many
characters you can use curly braces and
two numbers inside called here M and N
which would be a range of M through n
repetitions now what does all of this
mean well let me go back to vs code here
and let me propose that we iterate on
this solution further it's not
sufficient to just check for the at sign
we know that already we minimally want
something to the left and to the right
so how can I represent that I don't
really care what the user's username is
or what letters of the alphabet are in
it be it Ma or anyone else's so what I'm
going to do to the left of this equal
sign is I'm going to use a single period
the dot that again indicates any
character except for a new line but I
don't just want a single character
otherwise the P person username could
only be a at such and such or B at such
and such I want it to be multiple such
characters so I'm going to initially use
a star so dot star means give me
something to the left and I'm going to
do another one do star something to the
right now this isn't perfect but it's at
least a step forward because now what
I'm going to go ahead and do is this I'm
going to rerun python to validate dopy
I'm going to keep testing my own email
address just to make sure I haven't made
things worse and that's now okay I'm now
going to go ahead and type in some other
input like how about just uh maen at
with no domain name whatsoever and you
would think this is going to be invalid
but but but it's still considered valid
but why is that if I go back to this
chart why is maen at with no domain now
considered valid what's my mistake here
by having used doar at. Star as my
regular expression or Rex because you're
using the star instead of the plus sign
exactly the star again means zero or
more repetitions so r. search is
perfectly happy to accept nothing after
the equ after the at sign because that
would be zero repetitions so I think I
minimally need to evolve this and go
back to my code here and let me go ahead
and change this from Star to plus and
let me change the ending from Star to
plus so that now when I run my code here
let me go ahead and run python of
validate dopy I'm going to test my email
address as always still working now let
me go ahead and type in that same thing
from before that was accidentally
considered valid now I hit enter finally
it's invalid so now we're making some
progress on being a little more precise
as to what it is we're doing now I'll
note here like with almost everything in
programming python included there's
often multiple ways to solve the same
problem and does anyone see away in my
code here that I could make a slight
tweak if I forgot that the plus operator
exists and go back to using a star if I
allowed you only to use dots and only
Stars could you recreate the notion of
plus yes um use another dot dot dot star
yeah because if a DOT means any
character we'll just use a DOT and then
when you want to say or more use another
Dot and then the star so equivalent to
dot plus would have been dot dot star
because the first dot means any
character and the second pair of
characters Dot star means zero or more
other characters and to be clear it does
not have to be the same character just
by doing Dot or dot star does not mean
your whole username needs to be a or AA
or A AA or A A AA it can vary with each
symbol it just means zero or more of any
character back to back so I could do
this on both the left and the right
which one is better you know it depends
I think uh an argument could be made
that this is even more clear because
it's obvious now that there's a DOT
which means any character and then
there's the dot star but if you're in
the habit of doing this frequently one
of the reasons things like the plus
exist is just to consolidate your code
into something a little more succinct
and if you're familiar with seeing the
plus now maybe this is more readable to
you so again just like with python more
generally you're going to often see
different ways to express the same
patterns and reasonable people might
agree or disagree as to which way is
better than another well let me propose
to that we can think about both of these
models a little more graphically if this
looks a little cryptic to you let me go
ahead and rewind to the previous
incarnation of this regular expression
which was just a single dot star this
regular expression doar at dostar means
what again it means zero or more
characters followed by a literal at sign
followed by zero or more other
characters now when you pass this
pattern in as an argument to re. search
it's going to read it from left to right
and then use it to try to match against
the input email in this case that the
user typed in now how is the computer
how is r . search going to keep track of
whether or not the user's email matches
this pattern well it turns out that it's
going to be using a machine of sorts
implemented in software known as a
finite State machine or more formally a
non-deterministic finite automaton and
the way it works if we depict this
graphically is as follows the re. search
function starts over here in a so-called
start State that's the sort of condition
in which it begins and then it's going
to read the user's email address from
left to right and it's going to decide
whether or not to stay in this first
state or transition to the next state so
for instance in this first state as the
user reading my email address mailin at
harvard.edu it's going to follow this
curved edge up and around to itself a
reflexive Edge and it's labeled dot
because dot again just means any
character so as the function is reading
my email address mailin at harvard.edu
from left to right it's going to follow
these transitions as follows m a l a n
and then it's hopefully going to follow
this transition to the second state
because there's a literal at sign both
in this machine as well as in my email
address then it's going to try to read
the rest of my address h a r v a d do
du and that's it and then the computer's
going to check did it end up in a an
accept state a final State that's
actually depicted here pictorially a
little differently with double circles
one inside of the other and that just
means that if the computer finds itself
in that second accept state after having
read all of the users input it is indeed
a valid email address if by some chance
the machine somehow ended up stuck in
that first state which does not have
double circles and is therefore not an
accept state the computer would conclude
this is an invalid email address instead
by contrast if we go back to my other
version of the code where I instead had
Plus on both the left and the right
recall that re. search is going to use
one of these St machines in order to
decide from left to right whether or not
to accept the user's input like me
harbor. edu can we get from the start
state so to speak to an accept state to
decide Yep this was in fact meeting the
pattern well let's propose that this
non-deterministic finite automaton look
like this instead we're going to start
as before in the leftmost start State
and we're going to necessarily consume
one character per this first Edge which
is labeled with a DOT to indicate that
we can consume any one character like
the m in maen harvard.edu then we can
spend some time consuming more
characters before the at sign so the a l
a n then we can consume the at sign then
we can consume at least one more
character because recall that the Rex
has dot plus this time and then we can
consume even more characters if we want
so if we first consume the H in
harvard.edu that then leaves the a r v a
r d and then Dot e du and now here too
we're at the end of the story but we're
in an accept state because that circle
at the end has two circles total which
means that if the computer if this
function finds itself in that accept
state after reading the entirety of the
user's input it is too in fact a valid
email address if by contrast we had
gotten stuck in one of those other
states unable to follow a transition one
of those edges and therefore unable to
make progress in the user's input from
left to right then we would have to
conclude that that email address is in
fact invalid well how can we go upon
improving this code further let me
propose now that we check not only for a
username and also something after the
username like a domain name but
minimally required that the string ends
with doedu as well well I think I could
do this fairly straightforward not only
do I want there to be something after
the at sign like the domain like Harvard
I want the whole thing to end with
edu but there's a little bit of danger
here what have I done wrong by
implementing my regular expression now
in this way by using plus at. plus. edu
what could go wrong with this
version uh the dot is an dot means
something else in this context where it
means zero or more repetitions of a
character which is why it will interpret
it differently exactly even though I
mean for it to mean literally doedu a
period and then edu unfortunately in the
world of regular expression dot means
any character which means that this
string could technically end in a edu or
B edu or cedu and so forth but that's
not in fact that I want so any instincts
now as to how I could fix this problem
and let me demonstrate the problem more
clearly let me go ahead and run this
code here let me go ahead and type in
maen harvard.edu and as always this does
in fact work but Watch What Happens here
let me go ahead and do Ma at Harvard and
then uh M at Harvard question mark edu
enter that too is valid so I could put
any character there and it's still going
to be accepted but I don't want question
mark edu I want edu literally any
instincts then for how we can solve this
problem here how can I get this new
function re. search and a regular
expression more generally to literally
mean a dot might you think can you use
the uh Escape character the backslash
indeed the so-called Escape character
which we've seen before for outside of
the context of regular Expressions when
we talked about new lines back sln was a
way of telling the computer I want a new
line but without actually literally
hitting enter and moving the cursor
yourself and you don't want a literal n
on the screen so back sln was a way to
escape n and convey that you want a new
line it turns out regular Expressions
use a similar technique to solve this
problem here in fact let me go into my
regular expression and before that final
dot let me put a single backslash in the
world of regular Expressions this is a
so-called special special sequence and
it indicates per this backslash and a
single dot that I literally want to
match on a DOT it's not that I want to
match on any character and then edu I
want to match on a DOT or a period edu
but we don't want python to misinterpret
this backslash is beginning a an escape
sequence something special like backs
slash n which even though we as the
programmer might type two characters
backs slash n it really is interpreted
by python as a single new line we don't
want any kind of misinterpretation like
that here so it turns out there's one
other thing we should do for regular
expressions like this that have a
backslash used in this way I want to
specify to python that I want this
string this regular expression in double
quotes to be treated as a raw string
literally putting an r at the beginning
of the string to indicate to python that
you should not try to interpret any
backslashes in the usual way I want to
literally pass the backslash and the dot
and the edu into this particular
function search in this case so it's
similar in spirit to using that f at the
beginning of a format string which of
course tells python to format the string
in a certain way plugging in variables
that might be between curly braces but
in this case r indicates a raw string
that I want passed in exactly as is now
it's only strictly necessary if you are
in fact using backslashes to indicate
that you want some special sequence like
backs slash dot but in general it's
probably a good habit to get into to
just use raw strings for all of your
regular Expressions so that if you
eventually go back in make a change make
an addition you don't accident acally
introduce a backslash and then forget
that that might have some special or
misinterpreted meaning well let me go
ahead and try this new regular
expression I'll clear my terminal window
run python of validate run python of
validate dopy and then I'll type in my
email address correctly mailen
harvard.edu and that's fortunately still
valid Let Me Clear My screen and run it
one more time python of validate dopie
and this time let's mistype it as mailen
Harvard questionmark edu where by
there's obviously not a DOT there but
there is some other Single Character
that last time was misinterpreted as
valid but this time now that I've
improved my regular expression it's
discovered as indeed invalid any
questions now on this technique for
matching something to the left of the at
sign something to the right and now
ending with edu explicitly um what
happens when
that a good question and you kind of
called me out here well when in doubt
let's try let me go ahead and do python
validate dopy
mailin harvard.edu which ALS so is
incorrect unfortunately my code thinks
it's valid so another problem to solve
but a shortcoming for now other
questions on these regular Expressions
thus far can you use curly brackets M
instead of back can you use curly
brackets instead of backslash not in
this case if you want a literal dot
backslash Dot is the way to do it
literally how about one other question
on regular Expressions is this the same
thing that Google forms uses in order to
categorize data in let's say some if
you've got multiple people sending in
requests about some feedback do they
categorize the data that they get using
this particular regular expression thing
indeed if you've ever used Google forms
to not just submit it but to create a
Google form one of the menu options is
for response validation in English at
least and what that allows you to do is
specify that the user has to input an
email address or a URL uh or a string of
some length but there's an even more
powerful feature that some of you may
not have ever noticed and indeed if
you'd like to open up Google forms
create a new form temporarily and poke
around you will actually see in English
at least quote unquote regular
expression mentioned as one of the
mechanisms you can use to validate your
users's input into your Google form so
in fact after today you can start
avoiding these specific dropdowns of
like email address or URL or the like
and you can express your own patterns
precisely as well regular Expressions
can even be used in VSS code itself if
you go and find or do a find and replace
in VSS code you can of course just type
in words like you could into Microsoft
Word or Google Docs you can also type if
you check the right box regular
expressions and start searching for
patterns not literally specific values
well let me propose that we now enhance
this implementation further by
introducing a few other symbols because
right now with my code I keep saying
that I want my email address to end with
edu and start with a username but I'm
being a little too generous this does in
fact work as expected for my own email
address maen harvard.edu but what if I
type in a sentence like my email address
is maen harvard.edu and suppose I've
typed that into the program or I've
typed that into a Google form
is this going to be considered valid or
invalid well let's consider it's got the
at sign so we're good there it's got one
or more characters to the left of the at
sign it's got one or more characters to
the right of the at sign it's got a
literal doedu somewhere in there to the
right of the at sign and granted there's
more stuff to the right there's
literally this period at the end of my
English sentence but that's okay because
at the moment my expression is not so
precise as to say the pattern must start
with the username and end with the doedu
technically it's left unsaid what more
can be to the left and what more can be
to the right so when I hit enter now
you'll see that that whole sentence in
English is valid and that's obviously
not what you want in fact consider the
case of using Google forms or Office 365
to collect data from users if you don't
validate your input your users might
very well type in a full sentence or
some else with a typographic IAL error
not an actual email so if you're just
trying to copy all of the results that
have been typed into your form so you
can paste them into Gmail or some email
program it's going to break because
you're going to accidentally paste
something like a whole English sentence
into the program instead of just an
email address which is what your mailer
expects so how can I be more precise
well let me propose we introduce a few
more symbols as well it turns out in the
context of a regular expression one of
these patterns you can use the carrot
symbol the little triangular Mark to
repres presentent that you want this
pattern to match the start of the string
specifically not anywhere but the start
of the user string by contrast you can
use a dollar sign in your regular
expression to say that you want to match
the end of the string or technically
just before the new line at the end of
the string but for all intents and
purposes think of carrot as meaning
start of the string and dollar sign as
meaning end of the string it is a weird
thing that one is a carrot and one is a
dollar sign these are not really things
that I think of as opposites like a
parenthesis or something like that but
those are the symbols the world chose
many years ago so let me go back to VSS
code now and let me add this feature to
my code here let me specify that yes I
do want to search for this pattern but I
want the user's input to start with this
pattern and end with this pattern so
even though it's going to start looking
even more cryptic I put a carrot symbol
here at the beginning and I put a dollar
sign here at the end that does not mean
I want the user to type a carrot symbol
or a dollar sign this is special
symbology that indicates to re. search
that it should only look for now an
exact match against this pattern so if I
now go back to my terminal window and
I'll leave the previous result on the
screen let me type the exact same thing
my email address is ma at harvard.edu
enter sorry period and now I'm going to
go ahead and hit enter now that's
considered invalid but let me clear the
screen and just to make sure I didn't
break things let me type in just my
email address and that two is valid any
questions now on this version of my
regular expression which note goes
further to specify even more precisely
that I want it to match at the start and
the
end any questions on this one here okay
you have slash and do edu and then the
dollar sign but the dot is like one of
the regular expression right it normally
is but this backslash that I Deli put
before this period here is an escape
character it is a way of telling re.
search that I don't want any character
there I literally want a period there
and it's the only way you can
distinguish one from the other if I got
rid of that slash this would mean that
the email address just has to end with
any character then an e then a d then a
u i don't want that I want literally a
period Then the E then the D then the U
this is actually common convention in
programming and technology in general if
you and I decide on a convention whereby
we're using some character on the
keyboard to mean something special
invariably we create a future problem
for oursel when we want to literally use
that same character and so the solution
in general to that problem is to somehow
escape the character so that it's clear
to the computer that it's not that
special symbol it's literally the symbol
it sees so we don't even love it we
don't need another another slash before
the dollar sign no uh because in this
case dollar sign means something special
per this chart here dollar sign by
itself does not mean US dollars or
currency it literally means match the
end of the string if however I wanted
the user to literally type in a dollar
sign at the end of their input the
solution would be the same I would put a
backslash before the dollar sign which
means my email address would have to be
something like mait harvard.edu dollar
sign which is obviously not correct too
so back slashes just allow you to tell
the computer to not treat those symbols
specially like meaning something special
but to treat them literally instead how
about one other question here on regular
Expressions you said you said one
represents to to make it one plus then
you say one was to make it one with
nothing sure so let me rewind in time I
think what you're referring to was one
of our earlier versions that initially
looked like this which just meant Zero
or more characters then an at sign than
zero or more other characters we then
evolved that to be this Plus on both
sides which means one or more characters
on the left then an at sign then one or
more characters on the right and if I'm
interpreting your question correctly one
of the points I made earlier was that if
you didn't use Plus or forgot that it
exists you could equivalently achieve
the exact same result with two dots and
a star because the first dot means any
character it's got to be there the
second dot star means zero or more other
characters and same on the right so it's
just another way of expressing the same
idea one or more can be represented like
this with do do star or you can just use
the handier syntax of plus which means
the same thing all right so I dare say
there's still some problems with the
regular expression in this current form
because even though now we're starting
to look for the username at the
beginning of the string from the user
and we're looking for the edu literally
at the end of the string from the user
those dots are a little too encompassing
right now I am allowed to type in more
than the single at sign why because at
is a character and Dot means any
character so honestly I can have as many
at signs as this thing at the moment as
I want for instance if I run python of
validate dopy mailin harvard.edu still
works as expected but if I also run
python to validate dopy and incorrectly
do maen harvard.edu that should be
invalid but it's considered valid
instead so I I think we need to be a
little more restrictive when it comes to
that dot and we can't just say oh any
old character there is fine we need to
be more specific well it turns out that
regular Expressions also support this
syntax you can use square brackets
inside of your pattern and inside of
those square brackets include one or
more characters that you want to look
for
specifically alternatively you can
inside of those square brackets put a
car symbol which unfortunately in this
context means something completely
different from match the start of the
string but this would be the compliment
operator inside of these square brackets
which means you cannot match any of
these characters so things are about to
look even more cryptic now but that's
why we're focusing on regular
Expressions on their own here if I don't
want to allow any character which is
what a DOT is let me go ahead and I
could just say well I only want to
support a or B's or C's or D's or E's or
FS or G's I could type in the whole
alphabet here plus some numbers to
actually include all of the letters that
I do want to allow but honestly a little
simpler would be this I could use a
carrot symbol and then an at sign which
has the effect of saying this is the set
of characters that has everything except
an at sign and I can do the same thing
over here instead of a DOT to the right
of the at sign I can do Open Bracket
carrot at sign and I admit things are
starting to escalate quickly here but
let's start from the left and go to the
right this carrot outside of the square
brackets at the very start of my string
as before means match from the start of
the string and let's Jump Ahead the
dollar sign all the way at the end of
the regular expression means match at
the end of the string so if we can
mentally tick those off as
straightforward let's now focus on
everything else in the middle well to
the left here we have new syntax a
square bracket another carrot an at sign
and a Clos square bracket and then a
plus the plus means the same thing as
always it means one or more of the
things to the left what is the thing to
the left well this is the new syntax
inside of square brackets here I have a
carrot symbol and then an at sign that
just means any character except an at
sign it's a weird syntax but this is how
we can express that simple idea any
character on the keyboard EX except for
an at sign and heck even other
characters that aren't physically on
your keyboard but that nonetheless exist
then we have a literal at sign then we
have another one of these same things
square bracket carrot at close bracket
which means any character except an at
sign then one or more of those things
followed by literally a period
U so now let me go ahead and do this
again let me rerun python of validate
dopy and test my own email address to
make sure I've not made things work and
we're good now let me go ahead and clear
my screen and run python of validate
dopy again and do
mailin harvard.edu crossing my fingers
this time and finally this now is
invalid why I'm allowing myself to have
one at sign in the middle of the user's
input but everything to the left per
this new syntax cannot be an at sign it
can be anything but one or more times
and everything to the right of the at
sign can be anything but an at sign one
or more time followed by lastly a
literal. edu so again the new syntax is
quite simply this square brackets allow
you to specify a set of characters that
you literally type out at your keyboard
a bcde e f or the complement the
opposite the carrot symbol which means
not and then the one or more symbols you
want to
exclude questions now on this syntax
here so right after add sign can we use
the curly brackets M uh one so that we
can only have one repetition of the ad
symbol absolutely so we could do this
let me go ahead and pull a VSS code and
let me delete the current form of a
regular expression and go back to where
we began which was justar at and star I
could absolutely do something like this
and require that I want at least one of
any character here and then I could do
something more to have any more as well
so the curly brace syntax which we saw
on the slide earlier but didn't yet use
absolutely can be used to specify a
specific number of characters but
honestly this is more verbose than is
necessary the best solution arguably or
the simplest at least ultimately is just
to say do plus but there too another
example of how you can solve the same
problem multiple ways let me go back to
where the regular expression just was
and take other questions as well
questions on these sets of characters or
complimenting that set so can you use
that same syntax to say that you don't
want a certain character throughout the
whole stream
you could it's going to be uh you could
absolutely use the same character to
exclude a um you could absolutely use
the syntax to exclude a certain
character from the entire string but it
would be a little harder right now
because we're still requiring edu at the
end but yes
absolutely other questions what happens
if the user inputs edu in the beginning
of the thinging a good question what
happens if the user types in doedu the
beginning of the screen well let me go
back to VSS code here and let's try to
solve this in two different ways first
let's look at the regular expression and
see if we can infer if that's going to
be tolerated well according to the
current cryptic regular expression I'm
saying that you can have any character
except the at sign so that would work I
could have the dot for the edu but then
I have to have an at sign so that
wouldn't really work because if I'm just
typing in.edu we're not going to pass
that constraint so now let me try this
in uh by running the program let me type
in just literally doedu that doesn't
work but but but I could do this doedu
at.edu that too is invalid but let me do
this uhedu at something. edu that passes
so it's starting to get a little weird
now maybe it's valid maybe it's not but
I think we'll eventually be more precise
too how about one more question on this
regular expression
and these complimenting of sets can we
use uh another domain name as a string
input can you use another domain name
absolutely I'm using my own just for the
sake of demonstration but you could
absolutely use any domain or top level
domain and I'm using doedu which is very
us-centric but this would absolutely
work exactly the same for any top level
domain all right let me go ahead now and
propose that we improve this regular
expression further because if I pull it
up again in V vs code here you'll see
that I'm being a little too tolerant
still it turns out that there are
certain requirements for someone's
username and domain name in an email
address there is an official standard in
the world for what an email address can
be and what characters can be in it and
this is way to accommodating of all the
characters in the world except for the
at symbol so let's actually narrow the
definition of what we're going to
tolerate in usernames and companies like
Gmail could certainly do this as well
suppose that it's not just that I want
to exclude at sign suppose that I only
want to allow for say characters that
normally appear in words like letters of
the alphabet A through Z be it uppercase
or lowercase maybe some numbers in heck
maybe even an underscore could be
allowed too well we can use this same
square bracket syntax to specify a set
of characters as follows I could do a b
c d e f g h i j oh my God this is going
to take forever I'm going to have to
type out all 26 letters of the alphabet
both lowercase and uppercase so let me
stop doing that there's a better way
already if you want to specify Within
These square brackets a range of letters
you can actually just do a hyphen if you
literally do a hyphen Z in these square
brackets the computer is going to know
you mean a thusy you do not need to type
26 letters of the alphabet if you want
to include uppercase letters as well you
just do the same no spaces no commas you
literally just keep typing a through
capital Z so I have little a hyphen
little Z big a hyphen big Z no spaces no
commas no separators you just keep
specifying those ranges if I
additionally want numbers I could do 0 1
2 3 4 NOP you don't need to type in all
10 decimal digits you can just say 0
through n using a hyphen as well and if
you now want to support underscores as
well which is pretty common in usernames
for email addresses you can literally
just type in underscore at the at the
end notice that all of these characters
are in inside of square brackets which
just again means here is a set of
characters that I want to allow I have
not used a carrot symbol at the
beginning of this whole thing because I
don't want to complement it complement
it with an E not complement it with an i
I want don't want to complement it by
making it the opposite I literally want
to accept only these characters I'm
going to go ahead and do the same thing
on the right if I want to require that
the domain name similarly come from this
set of characters which admittedly is a
little too narrow but it's familiar for
now so we'll keep it simple I'm going to
go ahead and paste that exact same set
of characters over there to the right
and so now it's much more restrictive
now I'm going to go ahead and run python
of validate I'm going to test my own
email address and we're still good I'm
going to clear my screen and run it once
more this time trying to break it let me
go ahead and do something like how about
davidor maen harvard. e do you enter but
that too is going to be valid but if I
do something completely wrong again like
ma harvard.edu that's still going to be
invalid why because my regular
expression currently only allows for a
single at in the middle because
everything to the left must be alpha
numeric alphabetical or numeric or an
underscore the same thing to the right
followed by the edu now honestly this is
a regular expression that you might be
in the habit of typing in the real world
as in as cryptic as this might look this
is the world of regular Expressions so
you'll get more comfortable with this
syntax over time but thankfully some of
these patterns are so common that there
are builtin shortcuts for representing
some of the same information that is to
say you don't have to constantly type
out all of the symbols that you want to
include because odds are some other
programmer has had the same problem so
built into regular Expressions
themselves are some additional patterns
you use and in fact I can go ahead and
get rid of this entire set a through z
lowercase A through Z uppercase 0
through 9 and an underscore and just
replace it with a single back slw back
slw in this case represents a word
character which is commonly known as a
alpha numeric symbol or the underscore
as well I'm going to do the same thing
over here I'm going to highlight the
entire set of square brackets delete it
and replace it with a single backs slash
W and now I feel like we're making
progress because even though it's
cryptic and what if it looked way
cryptic a little bit ago um and even
though it would have looked even more
cryptic a little bit ago now it's at
least starting to read a little more
friendly the carrot on the left means
start matching at the beginning of the
string back slw means any word character
the plus means one or more at symbol
literally then another word character
one or more then a literal dot then
literally EDU U and then match at the
very end of the string and that's it so
there's more of these two and we won't
use them all here but here is a partial
list of the patterns you can use within
a regular expression one you have back
SL D for any decimal digit decimal digit
meaning 0 through n commonly done here
too is if you want to do the opposite of
that the complement so to speak you can
do back slash capital D which is
anything that's not a decimal digit so
it might be letter and punctuation and
other symbols as well Meanwhile Back SLS
means Whit space characters like a
single hit of the space or maybe hitting
tab on the keyboard that's whites space
back slash capital S is the opposite or
complement of that anything that's not a
whit space character back slw we've seen
a word character as well as numbers and
the underscore and if you want the
complement or opposite of that you can
use back SL capital W to give you
everything but a word character
again these are just common patterns
that so many people were presumably
using in yester year that it's now baked
into the regular expression syntax so
that you can more succinctly express
your same ideas any questions then on
this approach here where we're now using
backw to represent my word
character uh so what I want to ask about
uh was the uh actually the previous
approach like the square bracket
approach could we accept like uh lists
in there yes we'll see this before long
but suppose you wanted to tolerate not
just edu but maybe edu or do you could
do this you could introduce parentheses
and then you can or those together I
could say Comm or edu I could also add
in something like in the US or gov or
net or anything else or org or the like
and each of the vertical bars here means
something special it means or and the
parentheses simply group things together
formally you have this syntax here
A or B A or vertical Bar B means a has
to match or B has to match where A and B
can be any other patterns you want in
parentheses you can group those things
together so just like math you can uh
combine ideas into one phrase and do
this thing or the other um and there's
other syntax as well that we'll soon see
other questions on these regular
expressions in this syntax here what if
we put spaces in the expression sure so
if you want spaces in there you can't
use back slw alone because that is only
a word character which is alphabetical
numerical or the underscore but you
could do this you could go back to this
approach whereby you use uh square
brackets and you could say A through Z
or a through z or 0 through n or
underscore or I'm going to hit the space
bar a single space you can put a literal
space inside of the square brackets
which will allow you then to detect a
space alternatively I could still use
back slw but I could combine it as
follows I could say give me a back slw
or a back SL s because recall that back
SLS is wh space so it's even more than a
single space it could be a tab but by
putting those things in parentheses now
you can match either the thing on the
left or the thing on the right one or
more times how about one other question
on these regular
Expressions perfect so I was going to
ask um does the back slw um include a
DOT uh because no nope it only includes
letters numbers uh and underscore that
is it and I was wondering you gave an
example at the beginning that had uh
spaces like this is my email so on so um
I don't think our current version even
quite quite a long while ago stopped
accepting it was that because of the
carrot uh
or because of something no the reason I
was handling spaces and other English
words when I typed out my email address
is mailing at doedu was because we were
using initially star or plus which is
any character uh and even after that we
said anything except the at sign which
includes spaces only once I started
using square brackets and a through z
and 0 through 9 and underscore did we
finally get to the point where we would
reject whitespace and in fact I can run
this here let me go into the current
version of my code in VSS code which is
using again the back slw's for word
characters let me run python of validate
and incorrectly type in something like
my email address is mailen harvard.edu
period which has spaces to the left of
my username and that is now invalid
because space is not a word character
yorgo notes too that technically I'm not
allowing dots and some of you might be
thinking wait a minute my gmail address
has a dot in it that's something we're
going to still have to fix a back slw is
not the end all here it's just allowing
us to express our previous solution a
little more succinctly now one thing
we're still not handling quite properly
is uppercase versus lowercase the back
slw technically does handle lowercase
letters and uppercase because it's the
exact same thing as that set from before
which had little a through little Z and
big a through big Z but watch this let
me go ahead in my current form run
python to validate dopy and just because
my caps slot key is down maen
harvard.edu shouting my email address
it's going to be okay in terms of the ma
it's going to be okay in terms of the
Harvard because those are matching the
back slw which does include lowercase
and uppercase but I'm about to see
invalid why why is mailing at
harvard.edu
invalid when it's in all caps here even
though I'm using
backw yeah so you are asking for the
domain. edu in lowercase and you're
typing it in an uppercase exactly I'm
typing in my email address in all
uppercase but I'm looking for literally
edu and as I see you with airpods and so
many of you with headphones I apologize
for yelling into my microphone just now
to make this point but let's see if we
can't fix that well if my pattern on
line five is expecting it to be
lowercase there's actually a few ways I
can solve this one would be something
we've seen before I could just force the
user's input to all lowercase and I
could put on the end of my first line
lower and actually force it all to
lowercase alternatively I could do that
a little later instead of passing an
email I could pass in the lowercase
version of email because email addresses
should in fact be case insensitive so
that would work too but there's another
mechanism here which is worth seeing it
turns out that that function before
called re. search supports recall a
third argument as well these so-called
flags and flags are configuration
options typically to a function that
allow you to configure it a little
differently and how might I go about
configuring this call to re. search a
little bit differently in so far as I'm
currently only passing in two arguments
well it turns out that some of the flags
you can pass into this function are
these it turns out that the regular
expression library in Python AKA re
comes with a few built-in variables so
to speak things that you can think of as
constants that have meaning to re.
search and they do so as follows if you
pass in as a flag re. ignore case what
re. search is going to do is ignore the
case of the user's input it can be
uppercase lower case a combination
thereof the case is going to be ignored
it will be treated case insensitively
and you can do other things too that we
won't do here but if you want to handle
the user's input that maybe spans
multiple lines maybe they didn't just
type in an email address but an entire
paragraph of text and you want to match
different lines of that text that is
multiple lines another flag is for re
multi-line for just that or re doall
whereby you can con uh you can configure
the dot to rep to recognize not just any
character except new lines but any
character plus new lines as well but for
now let me go ahead and just make use of
this first one let me pass in a third
argument to re. search which is
re. uh ignore case let me now reun the
program without clearing my screen
python of validate dopy let me type in
again in all caps effective ly shouting
ma harvard.edu enter and now it's
considered valid because I'm telling re.
search specifically to ignore the case
of the input and that two here is fine
and why might I do this approach rather
than call do lower in one of those other
locations if I don't actually want to
change the user's input for whatever
reason I can still treat it case
insensitively without actually changing
the value of that variable itself are
any final questions now on this
validation of email
addresses uh so the pattern is a string
right M uh can we use an F string you
can you yes you can use an F string so
that you could plug in for instance the
value of a variable and pass it into the
function other questions on this access
W character could we take it as an input
from the user technically yes that's not
a problem we're trying to solve right
now we want the user to provide literal
input like their email address not
necessarily a regular expression but you
could imagine building software that
asks the user especially if they're more
advanced users to type in a regular
expression for some reason to validate
something else against that and in fact
that's what Google's doing if you play
around with Google forms and create a
form with response validation and select
regular expression Google lets you and I
type in our own regular Expressions
would be a per which would be a perfect
example of that all right well let me
propose that we try to solve one other
problem here whereby if I go into the
same version as before which is now
ignoring case but I type in one of my
other email addresses let me go ahead
and run python of validate dopy and this
time let me type in not mailen
harvard.edu which I use primarily but my
another email address of mine maen
cs50.h harvard.edu which forwards to the
same let me go ahead and hit enter now
and huh invalid even though I'm pretty
sure that is in fact my email address
well let's put our finger on the reason
why why at the moment is mail at cs50.h
harvard. edu being considered invalid
even though I'm pretty sure I send and
receive email from that address
too why might that be because there is a
DOT that has come after the ad symbol
exactly there's a DOT after my cs50 and
I'm not expecting any dots there I'm
expecting only again word characters
which is a through z 0-9 and under score
so I'm going to have to retool here but
how could I go about doing this well it
turns out theoretically there could be
other email addresses even though they'd
be getting a little excessively long for
instance mailin at something. cs50.h
harvard.edu which is not technically
exist but it could you can have of
course multiple dots in a domain name
like we see here wouldn't it be nice if
we could handle that as well well let me
propose that we modify my regular
expression as follows it turns out that
you can group ideas together and you can
not only ask whether or not this pattern
matches or this one using syntax like a
vertical Bar B which means either A or B
you can also group things together and
then apply some other operator to them
as well in fact let me go back to VSS
code here and let me propose that if I
want to tolerate a subdomain like cs50
that may or may not be there let me go
ahead and change it as follows I could
naively do this if I want to support
subdomain I could say well let's allow
for otherw characters plus and then a
literal Dot and notice I'll highlight in
blue here what I've just added
everything else is the same but I'm now
adding room for another sequence of one
or more word characters and then a
literal dot so this now I think if I
rerun python of validate dopy will work
for Ma at cs50.h harvard.edu enter
unfortunately does anyone see where this
is going let me rerun python of validate
dopy and type in as I keep doing maen
harvard.edu which up until now has kept
working despite all of my changes but
now finally I've broken my own email
address so logically what's the solution
here well there's a bunch of ways we
could solve this I could maybe start
using two regular expressions and
support you uh email addresses of the
form username at domain. TLD or username
at subdomain dodoma TLD where TLD just
means top level domain like edu or I
could maybe just modify this one because
I'd prefer not to have like two uh
regular expressions or one that's twice
as big why don't I just specify to re.
search that part of this pattern is
optional what was the symbol we saw
earlier that allows you to specify that
the thing before it is technically
optional the straight bar we are using
the Straight bar as a
optional make the opt the argument
optional so we could we could use a
vertical bar and some parentheses and
say either there's something here or
there's nothing we could do that in
parenthesis but I think there's actually
an even easier way uh actually is a
question mark indeed question mark think
back to this summary here of our first
set of symbols whereby we had not just
Dot and star and plus but also a
question mark which means literally zero
or one repetitions which affect ly means
optional it's either there one or it's
not zero now how can I translate to that
to this code here well let me go ahead
and Surround this part of my pattern
with parentheses which doesn't mean I
want literally a parenthesis in the
user's input I just want to group these
characters together and in fact this now
will still work I've only added
parentheses around the new part for the
subdomain let me run python of validate
dopy let me run maen cs50.h harvard.edu
enter that's still valid but to be clear
if I rerun it again for ma harvard.edu
that is still invalid but not if I go in
here and say after the parentheses which
now is one logical unit it's one big
group of ideas together I add a single
question mark there this will now tell
re. search that that whole thing in
parentheses can either be there once or
be there not at all zero times so what
does this translate into when I run it
well let me go ahead and rerun it with
maen cs50.h harvard.edu so that the
subdomain is there that works as before
let me clear my screen and run it again
python of validate dopy with ma
harvard.edu which used to work then
broke is are we back in business now we
are that's now valid again questions now
on this approach where we've use not
just the question mark But the
parenthesis as well okay yeah you works
for zero or one repetition what if you
have more what if you have more that's
okay that's where you could do star star
is zero or more which gives you all the
flexibility in the world yeah so I was
just asking that uh uh with question
mark there's only one repetition allow
it means zero or one repetition so it's
either not there or it is there and so
that's why this pattern now if I go back
to my code even though again it
admittedly looks cryptic let me
highlight everything after the at sign
and before the dollar sign this now
represents a domain name like
harvard.edu or a subdomain within the
domain name why well this part to the
right is the same as always backw plus
means something like Harvard or Yale
back.edu means literally doedu so the
new part is this in parentheses I have
another set of back
w+ back SL do now but it's all in
parentheses I'm now having a question
mark right after that which means that
whole thing in parenthesis either can be
there or it can't be there it's either
of those that are acceptable so a
question mark effectively make something
optional it would not be correct to
remove the parentheses because what
would this mean if I remove the
parentheses that would mean that only
this dot is optional which isn't really
what we want to express I want the
subdomain like cs50 and the additional
dot to be what's there or not there how
about one other question on Rex is here
can they use this for the usernames
absolutely we still have other problems
right we're not solving all of the
problems today just yet but absolutely
right now we are not letting you have a
period in your username and again some
of you with Gmail accounts or other
accounts you probably have not just
underscores numbers and letters you
might have periods too well we could fix
that not using question mark here per se
but now that we have these parentheses
at our disposal what I could do is this
I could use parentheses to surround the
back slw to say any word character which
is the same thing again as a letter or a
number or an underscore but I could also
or in using a vertical bar something
else like a literal dot now a literal
dot needs to be escaped otherwise it
represents any character which would be
a regression a step back but now notice
what I've done in parentheses I'm
telling re. search that those first few
characters in your email address that is
your username has to be a word character
Like A through Z uppercase or lowercase
or 0 through n or an underscore or a
literal dot we could do this differently
too I could get rid of the parentheses
and the or and I could just use a set of
characters I could again manually say a
through z a through z 0 through 9
underscore and then I could do a literal
dot with a back slash period and now I
technically don't even need the
uppercase because I'm already telling
the computer to ignore case I can just
pick one or the other which one is
better is really up to you whichever one
you think is more readable would
generally be the better design all right
let me propose that I rewind this in
time to where we left off which was here
and let me propose that there are indeed
still limitations of this solution not
just with the username not just with the
domain name we're still being a little
too restrictive so would you like to see
the official regular expression that at
least browsers use nowadays whenever you
type in an email address to a web form
and the web form the browser tells you
yes or no your email address is
syntactically valid ready ready here is
and this isn't even officially the right
regular expression it's a simplified
version that browsers use because it
catches most mistakes but not all here
we go this is the regular expression for
a valid email address at least as
browsers nowadays Implement them now
it's crazy cryptic at first glance but
not and it's wrapping onto many lines
but it's just one pattern but just
notice the now familiar symbols there is
the carrot symbol at the very top there
is the dollar sign at the very end there
is a square bracket over here and then
some of these ranges plus other
characters turns out you don't normally
see these characters in email addresses
it looks like you're swearing at someone
in their username but they're valid
characters they're valid officially that
doesn't mean that Gmail is going to
allow you to put dollar signs and other
punctuation in your username but
officially some servers might allow that
so if you really want to validate a
user's email address you would actually
come up with or copy paste something
like this but honestly this looks so
cryptic and if you were to type it out
manually you are so likely to make a
mistake what's the better solution here
instead this is where P past week's
libraries are your friend surely someone
else on the internet a programmer more
experienced than you even has come up
with code that validates email addresses
properly using this regular expression
or even something more sophisticated
than that so generally if the problem at
hand is to validate input that is pretty
conventional an email address a URL
something where there's an official
definition that's independent of you
yourself find a the popular library that
you're comfortable using and use it in
your code to validate email addresses
this is not a wheel necessarily that you
yourself should invent we've used email
addresses though to iteratively start
from something simple too simple and
build on top of that so you could
certainly imagine using regular
Expressions still to validate things
that aren't email addresses but are data
that are important to you so we at least
now have these building blocks now
besides the regular Expressions
themselves it turns out there's other
functions and Python's re library for
regular Expressions among them is this
function here re. match which is
actually very similar to re. search
except you don't have to specify the
carrot symbol at the very beginning of
your Rex if you want a match from the
start of a string re. match by Design
will automatically start matching from
the start of the string for you similar
in spirit is re. full match which does
the same thing but not only matches at
the start of the string but the end of
the string so that you too don't need to
type in the carrot symbol or the dollar
sign as well but let's go ahead and
transition back now to some actual code
whereby we solve a different problem in
spirit rather than just validate the
users's input and make sure it looks the
way we want let's just assume that the
users are not going to type in data
exactly as we want and so we're going to
have to clean up their input this
happens so often when you're using like
a Google form or Office 365 form or
anything else to collect user input no
matter what your form question says your
users are not necessarily going to
follow those directions they might go
ahead and type in something that's a
little differently formatted than you
might like now you could certainly go
through the results and download a CSV
or open the Google spreadsheet or
equivalent in Excel and just clean up
all the data manually but if you've got
lots of submissions dozens hundreds
thousands of rows in your data set doing
things manually might not be very fun it
might be much more effective to write
code as in Python that can allow you to
clean up that data and any future data
as well so let me propose that we go
ahead here and close validate dopy and
let's go ahead and create a new program
Al together called format. the goal of
which is to reformat the user's input in
the format we expect I'm going to go
ahead and run code of format. py and
let's suppose that the data we're going
to reformat is the user's name so not
email address but name this time and
we're going to hope that they type in
their name properly like David ma but
some users might be in the habit for
whatever reason of typing their name
backwards if you will with the comma
such as men comma David instead now it's
fine because both are clearly as
readable to the human but if you want to
standardize how those names are stored
in your system perhaps a database or CSV
file or something else it would be nice
to at least standardize or canonicalize
the format in which you're storing your
data so that if you print out the user's
name it's always the same format David
Ma and there's no commas or backwards to
it so let's go ahead and do something
familiar let's go and give myself a
variable called name and set it equal to
the return value of input asking the
user as we've done many times what's
your name question mark I'm going to go
ahead and proactively at least clean up
some messiness as we keep doing here by
just stripping off any leading or
trailing whites space just in case the
user accidentally hits the space bar we
don't want that ultimately in our data
set and now let me go ahead and do this
as we've done before let me just go
ahead quickly and print out just to make
sure I'm off to the right start hello
and then in curly brace's name so making
an F string to format hello comma name
now let me go ahead and clear my screen
and run python of format. let me behave
and type in my name as I normally would
David space ma enter and I think the
output looks pretty good it looks as
expected grammatically let me now go
ahead though and play this game again
but this time maybe because I'm not
thinking or I'm just in the habit of
doing last name comma first I do ma
comma David and hit enter all right well
this now is is weird even though the
program is just spitting out exactly
what I typed in arguably this is not
close to correct at least grammatically
it should really say hello David ma now
maybe I could have some if conditions
and I could just reject the user's input
if they type a comma or get their names
backwards somehow but that's going to be
uh too little too late if the user has
already submitted a form online and I
already have the data and now I need to
go in and clean it up and it's not going
to be fun to go through manually in
Google spreadsheets or apple numbers or
Microsoft Excel and manually fix a lot
of people's names to get rid of the
commas and move the first name before
the last as is conventional in the US so
let's do this it could be a little
fragile but let's like let's start to
express ourselves a little
programmatically here and ask this if
there is a comma in the person's name
which is pythonic I'm just asking the
question is this shorter string in this
longer string then let me go ahead and
do this let me go ahead and grab that
name in the variable split on not just
the Comm
but the space after assuming the human
typed in a space after their name and
let me go ahead and store the result of
that splitting of ma comma David into
two variables let's do last comma first
again unpacking the sequence of values
that comes back now let me go ahead and
reformat the name so I'm going to
forcibly change the user's name to be as
I expect so name is actually going to be
this format string first name then last
name both in curly braces but formatted
together with a single space so that I'm
overriding the user's input and updating
my name variable accordingly for the
moment to be clear this program is
interactive like the users like me are
typing their name into the program but
imagine the data already is in a CSV
file it came in from some process like a
Google form or something else online you
could imagine writing code similar to
this but that maybe goes and reads that
file into memory first maybe it's a CSV
via CSV reader or a dict reader and then
iterating over each of those names but
we'll keep it simple and just do one
name at a time but now what's kind of
interesting here is if I go back to my
terminal window and clear it and run
python of format. piy and hit enter I'm
going to type in David space ma as
before and I think we're still good but
I'm also going to go ahead and do this
python of format. ma comma David with a
space in between crossing my fingers and
hit enter and voila that now has been
fixed such a simple thing to be sure but
it is so commonly necessary to clean up
users input here we see at least one way
to do so pretty easily now to be fair
there's some problems here and in fact
can someone imagine a scenario in which
this code really doesn't fix the user's
input what could still go wrong even
with this fix in my code any thoughts if
they type their in their name comma and
then sign them oh and then something
else yeah so let me let me try this for
instance let me go ahead and run a
program and uh I am the only David men
that I know but suppose I were uh uh
let's say junior like this and it's
common in English at least to sometimes
put a comma there you don't necessarily
need the comma but I'm one of those
people who uses a comma that's now
really really broken so I've broken some
assumption there and so that could
certainly go wrong here what else well
let me go ahead and run this again and
if I did ma comma David no space because
I'm being a little sloppy I'm not paying
attention which is going to happen when
you have lots of users ultimately well
this really broke now notice I have a
value error an actual exception why well
because split is supposed to be
splitting the string into two strings by
looking for the comma and a space but if
there is no comma in space it can't
split it into two things and the fact
that I have two variables on the left
but I'm only getting back one thing on
the right means that I can't do this
code quite as this so it's fragile to be
sure but wouldn't it be nice if we could
at least improve it for instance we now
know some regular expression syntax what
if I at least wanted to make this space
optional well I could use my new found
regular expression syntax and put a
question mark question mark means zero
or one of the things to the left what's
the thing to the left it's literally a
space I don't even need parentheses if
there's just one thing there so that
would be the start of a pattern that
says I must have a comma and then I may
or may not have a space zero or one
spaces there after unfortunately the
version of split that's built into the
stir variable as in this case doesn't
support regular Expressions if we want
our regular Expressions we need to go
use that Library here so let me go ahead
and do this let me go in and leave this
code AS is but go up to the top now and
import re to import the library for
regular expressions and now let me go
ahead and start changing my Approach
here I'm going to go ahead and do this
I'm going to use the same function
called re. search and I'm going to
search for a pattern that I think will
be last comma first so let me use my new
found regular expression syntax and
represent a pattern for something like
ma comma space David how can I do this
well inside of my quotes for re. search
I'm going to have something so plus
sorry I'm going to have something so
plus then I'm going to have a comma then
I'm going to have a space then I'm going
to have something plus now I'm going to
preemptively refine this a little bit I
want this whole pattern to start
matching at the beginning of the user's
input so I'm going to add the carrot
right away and I want the end of the
user's input to be matched as well so
that I'm literally expecting any
character one or more times then a comma
then a space then any other character
one or more times and then that is it
and I'm going to pass in the name
variable as before now when we've used
re do search in the past we really used
it just to answer a question does the
user's input match the following pattern
or not true or false effectively but re.
search is actually more powerful than
that you can actually get back more
information and you can do this you can
specify a variable and then an
assignment operator and get back more
precise answers to what has been found
when searched for but what is it you
want to get back well it turns out
there's this other feature of regular
Expressions which allow you to use
parentheses not just to group things
together but to capture them it turns
out when you specify parentheses in a
regular expression unbeknownst to us up
until now everything in the parentheses
will be returned to you as a return
value from the re. search function it's
going to allow you to extract specific
amounts of information from the user's
own input you can reverse this process
too by using the non-capturing version
as well you can use parentheses and then
literally a question mark and a colon
and then some other stuff and that will
say don't bother capturing this I just
want to group things but for now we're
going to use just the parentheses
themselves so how am I going to do this
well if I want to get back the user's
last name and first name I think what I
want to capture is the plus here and the
plus here so I've deliberately
surrounded in par parentheses the dot
plus both to the left and the right of
the comma not because I'm grouping them
together per se I'm not adding a
question mark I'm not adding of another
Plus or a star I'm using parentheses now
for capturing purposes why well I'm
going to do this next I'm going to still
ask a Boolean question like if there are
matches then do this so if matches is
not effectively false like none I do
expect I've gotten back some matches and
watch what I can do now I can do last
comma first equals whatever matches in
and get back all of the groups of
matches then go ahead and update name
just like before with a format string
and do first and then last in curly
braces as well and then at the very
bottom just like before print out for
instance hello comma name so the new
code now is everything highlighted here
I'm using re search to search for
whether the US user typed their name in
last comma first format but I am more
powerfully using re. search to capture
some of the user's input what's going to
get captured anything I surround it in
parentheses will be returned to me as
return values how do you get at those
return values you ask the variable to
which you assigned them for all of the
groups all of the groups of parentheses
that were captured so let me go ahead
and do this let me go ahead now and run
python of format stop Pi enter and I'm
going to type my name as usual in this
case nothing happens with this if
condition why because I did not type a
comma and so this search does not find a
comma so there are no matches so we
immediately just print out hello name
nothing interesting or new there but if
I now go ahead and clear my screen and
run python a format up high and do maen
commas space David enter we've
reformatted my name
well how did this work let me be a
little more explicit now it turns out I
don't have to just say matches. groups I
can get specific groups back that I want
so let me change my code a little bit
more let me go ahead now and just say
this let's update name uh to well
actually let's do this let's say that
the last name is going to be in the
matches but specifically group one the
first name is going to be in the matches
but specifically group two why one and
two because this is the first set of
parentheses to the left of the comma
this is the second set of parentheses to
the right of the comma and based on the
input this would be the user's last name
in this scenario me this would be the
user's first name David in this scenario
that's why I'm using group one for the
last name and group two for the first
name and now I'm going to go ahead and
say name equals uh F string again uh
first and then last done and let me
refine this one last step before we take
questions I don't really need these
variables if I'm immediately using them
let's just go ahead and tighten this up
further as we've done in the past for
design sake if I want to make the name
the concatenation of the person's first
name and last name let's just do this
matches. group two first plus a space
plus matches. group one so it's just up
to me to know from left to right this is
group one this is group two so group one
is last group two is first so if I want
to flip them around and update the value
of name I can explicitly get group two
first concatenate using plus a single
space and then concatenate on group one
all right that was a lot let me pause to
see if there are questions the key
difference here is we're still using re.
search the exact same way but now I'm
using its return value not just to
answer a question true or false but to
actually get back specific matches
anything I captured so to speak with
parentheses why is it here we're using
one and two instead of Z and one really
good question caping the first a good
observation in almost every other
context we've started counting at zero
and one instead of one and two it turns
out there's something else in location
zero when it comes back from re. search
related to the string itself so
according to the documentation of this
function only one is the first set of
parentheses and two is the second set
and onward from there just a different
convention here other questions uh what
if we write nothing like white space
comma whes space uh how how we check um
true of condition before I answer
directly let me just run this and make
sure I've not broken anything further
let me run python of format. let me type
in David space maen the right way let me
run it once more let me type it Ma comma
David the wrong way that we're fixing
and we're still good but I think it will
still break let me run it a third time
with me comma David with no space and
now it's still broken why because I'm
still looking for comma space now how
can I fix that one way I could do that
is to add a question mark here which
again is zero or more of the thing
before so if I have a space and then a
question mark literally no need for any
parentheses then I can literally
tolerate both ma comma space David or ma
comma David so let's try again before
this did not work let's do me comma
David with no space now it does actually
work so we can tolerate different
amounts of white space if I am a little
more precise with my formula let me go
ahead and try once more let me very
weirdly but possibly hit the space bar a
few too many times so now they're really
separated this again is uh not going to
work quite right because it's going to
consume all of that white space so now I
might want to strip left and right any
of the leading white space on the result
or what I could do here is say this
instead of zero or one I could use a
star here so space star and now if I run
this once more with ma comma space space
space David enter now we've cleaned up
things further so you can imagine
depending on how messy the data is that
you're cleaning up your regular
Expressions might need to get more and
more sophisticated it really depends on
just how many problems we want to solve
at once well allow me to propose that we
Forge ahead further just to clean this
up even more so using a feature that's
actually relatively new to python itself
it is very common when using regular
Expressions to do exactly what I've done
here to call a function like re. search
with capturing parentheses inside such
that you get back a return value that
I'm calling matches you could call it
something else but I'm calling it by
default matches and then notice on the
next line I'm saying if matches wouldn't
it be nice if I could just tighten
things up further
and do these all on the same line well
you can sort of let me go ahead and do
this let me get rid of this if and let
me just try to say something like this
if matches equals re search and then
colon so combining my if condition into
just one line instead of those two um in
C or C++ or Java you would actually do
something like this surrounding the
whole thing with parentheses sometimes
double sets to suppress any warnings if
you want to do two things at once if you
want to not only assign the return value
of re. search to a variable called
matches but you want to subsequently ask
a Boolean question is this effectively
true or false that's what I was doing a
moment ago let me undo this a moment ago
I was getting back the return value and
assigning it to matches and then I was
asking the question well it turns out
this need to have two lines of code
presumably rubbed people wrong for too
long long in Python and so you can now
combine these two kinds of lines into
one but you need a new operator you
cannot just say if matches equals re
search and then an cin at the end you
instead need to do this you need to do
colon equals if and only if you want to
assign something from right to left and
you want to ask an if or an L if
question on the same line This is
affectionately known as you can see here
as the wall
operator and it's new to python in
recent years and it both allows you to
assign a value as I'm doing from right
to left and ask a Boolean question about
it like I'm doing with the if or
equivalently L if does anyone know why
this is called The Walrus operator if
you kind of look at it like this perhaps
if you're familiar with walruses it kind
of sort of looks like a walrus so a
minor detail but a relatively new
feature of python that honestly you'll
probably continue to see online and in
source code and in textbooks and so
forth increasingly so now that it does
exist it does not change the logic at
all if I run python of format. piy and
type maen commas space David it still
fixes things but it's tightened up my
code just a bit more all right let's go
ahead and look at one final problem to
solve that of extracting information now
as well so at this point we've now
validated the user's input by checking
whether or not it meets a certain
pattern we've cleaned up the users input
by checking against a pattern whether it
matches or not and if it does match we
kind of reorganize some of the users
information so we can clean up their
input and standardize the format in
which we're storing or printing it in
this case let's do one final example
where we're very specifically extracting
information in order to answer some
question so let me propose this let me
go ahead and close format. and create a
new file called
twitter. the goal of which is to prompt
users for the URL of their Twitter
profile and extract from it infer from
that URL what is the user's username now
why might you want to do this well one
you might want users to be able to just
very easily copy and paste the URL from
their own Twitter profile into your form
into your app so that you can figure out
what their uh username is or you might
have a form that asks the user for their
Twitter username and because people
aren't necessarily paying very close
attention some people type their
username some people type their whole
URL or something else altogether it
would be nice now that you're a
programmer to just be more tolerant of
different types of input and just take
on the burden of canonicalizing
standardizing the data but being
flexible with the users it's arguably a
better user experience if you just let
me copy paste or type in what I want you
clean it up you're the programmer not me
LS for a better experience perhaps well
let me go ahead and do this with
twitter. let me first go ahead and
prompt the user here for a value for a
variable that I'll call you URL and just
ask them to input the URL of their
Twitter profile I'm going to go ahead
and strip off any leading or trailing
whitespace just in case users
accidentally hit the space bar that's
like literally the least I can do quite
easily but now let's go ahead and do
this suppose that the users address is
the following let me print out what they
type in and let me clear my screen and
run python of twitter. I'm going to go
ahead and type in for instance
https
twitter.com David J ma which happens to
be my own Twitter username for now we're
just going to print it back onto the
screen just to make sure I've not messed
up yet okay so I've printed back out the
exact same URL but the goal at hand is
to extract the username only now let me
just ask perhaps a straightforward
question logically what do I need to do
to get at the user's username well um we
just ignore what's before the username
and then just extract the username
perfect yeah I mean it is simple as that
if you know the usernames at the end
well let's just somehow ignore
everything to the beginning well what's
at the beginning well it's a URL so
we're probably going to need to ignore
an https a colon a twitter.com and a
slash so we just want to throw all of
that away why because if it's a URL We
Know by how Twitter works that the
username comes at the end so let's use
that very simple idea to get at the
information we want well I'm going to
try this a few different ways let me go
back into my program here and instead of
just printing it out which was just to
see what's going on let me do this let
me create a new variable called username
and let me call url. replace it turns
out that if URL is a string or a stir in
Python it again comes with multiple
methods like strip uh and split and
others as well one of which is called
replace and replace will do just that
you pass a two arguments the first of
which is what do you want to replace the
second argument is what do you want to
replace it with so if I want to get rid
of as I've been proposed really just
everything before the username that is
the Twitter URL or the beginning thereof
let's just say this go ahead and replace
https
twitter.com close quote that's what I
want to replace and comma second
argument what do you want to replace it
with nothing so I'm literally going to
pass in quote unquote to effectively do
a find and replace that's what the
replace method does just like you can do
it in Microsoft Word or Google Docs this
is the programmer's way of doing find
and replace now let me go ahead and
print out just the username so I'll use
an F string like this I'll say username
colon and then in curly braces username
just to format it nicely all right let
me go ahead and clear my screen and run
python of twitter. enter URL here we go
https
[Music]
twitter.com davidj maen enter okay now
we've made some progress done for the
day right well what is suboptimal about
this can anyone critique or find fault
with my program it is working now but
it's a little fragile I bet we could
contrive some scenarios where I think it
works but it doesn't well I have a few
ideas actually well first of all uh if
we if we don't specify https it will
broken secondly if we have slash at the
end it also will be broken if we if we
have like question mark up the after
question mark it also w't work so lot of
scenar actually oh my God I mean here we
are I was pretending to think I was done
but my God like Alex gave us a whole
laundry list of like problems and just
to recap then what if it's not https
it's HTTP slightly less secure but I
should still be able to tolerate that
programmatically uh what if the protocol
is not there what if the user just typed
twitter.com davidj maen it would be nice
to tolerate that rather than show an
error and make me type in the protocol
why it's not good user experience what
if it had a flash at the end of the
username or a question mark If you think
about URLs you've seen on the web
there's very commonly more information
especially if it's been shared on social
media there might be HTTP parameters so
to speak just stuff there that we don't
want there could be a www. twitter.com
which I'm also not expecting but does
work if you go to that URL too so
there's just so many things that can go
wrong and even if I come back to my
contrived example as earlier what if I
run this program and say this uh my
username is H H
gtps
twitter.com davidj maen enter well that
too just just didn't really work it got
rid of the U
actually okay actually that kind of
worked but the goal here is to actually
get the user's username not an English
sentence describing the user's username
so I would argue that even though I just
accidentally created perfectly correct
English grammar I did not extract the
Twitter username correctly I don't want
words like my username is as part of my
input so how can we go about improving
this and maybe chipping away at some of
those problems one by one well let me
clear my screen here let me come back up
to my code and let me not just replace
it but let me do something else instead
I'm going to go ahead and instead of
using replace I'm going to use another
function called remove prefix a prefix
is a string or a substring that comes at
the start of another so if I remove
prefix I don't need a second argument
for this function I just need one what
prefix do you want to remove so this
will at least now fix the problem I just
described of typing in like a whole
sentence where the URL is there but it's
not the beginning it's only at the end
so here this still is not correct but we
don't create this weird looking output
that just removes the URL part of the
input uh my username is
htps twitter.com davidj maen a moment
ago it did remove the URL and left only
the David J ma this is not perfect still
but at least now it does not weirdly
remove the URL and then leave the
English it's just leaving it alone so
maybe I could handle this better but at
least it's removing it from the part of
the string I might
anticipate well what else could we do
here well it turns out that like regular
Expressions just let us express patterns
much more precisely we could spend all
day using a whole bunch of different
python functions like remove prefix or
remove and strip and others and kind of
make our way to the right solution but a
regular expression just allows you to
more succinctly if admittedly more
cryptically Express these kinds of
patterns and goals and we've seen from
parentheses which can be used not just
to group symbols together as sets but to
capture information as well we have a
very powerful tool now in our toolkit so
let me do this let me go ahead and start
fresh here and import the re Library as
before at the very top of my program I'm
still going to get the user's URL via
the same l of code but I'm now going to
use another function as well it turns
out that there's not just re. search or
rd. match or re. full match there's also
re. sub in the regular expression
Library where sub here means substitute
and it takes more arguments but they're
fairly straightforward the first
argument to re.sub is the pattern the
regular expression that you want to look
for then you have a replacement string
what do you want to replace that pattern
with and where do you want to do all
that well you pass in the string that
you want to do the substitution on then
there's some other arguments that I'll
wave my hands at for now among them are
the same flags and also a count like how
many times do you want to do find and
replace do you want it to do all or do
you want to do it just one or so forth
you can have further control there too
just like you would in Google Docs or
Microsoft Word well let me go back to my
code here and let me do this I'm going
to go ahead and call re not search but
re.sub for substitute I'm going to pass
in the following regular expression
https
twitter.com uh Slash and then I'm going
to close my quote and now what do I want
to replace that with well like before
with the simple stir replace function I
want to replace it with nothing just get
rid of it alt together but what uh
string do I want to pass in to do this
to the URL from the user and now let me
go ahead and assign the return value of
re sub to a variable called username so
re sub purpose in life is again to
substitute some value for some regular
expression some number of times it
essentially is find and replace using
regular expressions and it returns to
you the resulting string once you've
done all those substitutions so now the
very last line of my code can be the
same as before print and I'll use an F
string username colon and then in curly
braces username so I can print out
literally just that all right let's try
this and see what happens I'll clear my
terminal window run python of twitter.
and here we go
https
twitter.com
davidj cross my fingers and hit enter
okay now we're in business but it is
still a little fragile and so let me ask
the
group what problem should I now further
chip away at they've been said before
but let's be clear what's one or more
problems that still remain the protocols
and the uh domain prefixes for good the
protocol so HTTP versus https maybe the
subdomain www should it be there or not
and there's a few other mistakes here
too let me actually stay with the group
what are some other shortcomings of this
current solution um if we use a phrase
like you do before we are going to have
the same problem because it's not taken
account in the first part of the the
text example good I might still allow
for like some words uh some English to
the left of the URL because I didn't use
like my carrot symbol so I'll fix that
and any final observations on
shortcomings here uh well it could be a
HTTP or they could be like less than two
slashes okay so it could be HTP and I
think that was mentioned too in terms of
protocol there could be fewer than two
slashes that I'm not going to worry
about if the user gives me one slash
instead of two that's really user error
and I could be tolerant of it but you
know what at that point I'm okay yelling
at them with an error message saying
please fix your input otherwise we could
be here all day long trying to handle
all possible typos for now I think in
the interest of usability or user
experience ux let's at least be tolerant
of all possible valid inputs or
reasonable inputs if you will so let me
go here and let me start chipping away
at these here what are some problems we
can solve well let me propose that we
first address the issue of matching from
the beginning of the string so let me
add the carrot to the beginning and let
me add not a dollar sign at the end
though right because I don't want to
match all the way to the end because I
want to tolerate a username there so I
think we just want the carrot symbol
there there's a subtle bug that no one
yet mentioned and let me just kind of
highlight it and see if it jumps out at
you now it's a little subtle here on my
screen I've highlighted in blue a final
bug here maybe some Smiles on the screen
yeah can we take one hand here why am I
highlighting the dot in twitter.com even
though it definitely should be there so
the dot without a backlash mean any
character is up a new line yeah exactly
it's not it's means any character so I
could type in something like Twitter uh
question markc or Twitter anything com
and that would actually be tolerate it's
not really that bad cuz why would the
user do that but if I want to be correct
and I want to be able to test my own
code properly I should really get this
detail right so that's an easy fix too
but it's a common mistake anytime you're
writing regular Expressions that happen
to involve special symbols like dots in
a URL or domain name a dollar sign in
something involving currency remember
you might indeed Need to Escape it with
a backslash like this here all right let
me ask the group about the protocol
specifically https is a good thing in
the world it means secure there is
encryption being used so generally you
like to see https but you still see
people typing or copy pasting HTTP What
would be the simplest fix here to
tolerate as has been proposed both HTTP
and https I'm going to propose that I
could do this I could do HTTP vertical
bar or https which again Means A or B
but I think I can be smarter than that I
can keep my code a little more succinct
any recommendations here for
tolerating HTTP or
https we could try to put an question
mark behind the
perfect just use a question mark right
like both of those would be viable
Solutions if you want to be super
explicit in your code fine use
parentheses and say HTTP or https so
that you the reader your boss your
teacher just know exactly what you're
doing but you know if you keep taking
the more of a Bose approach all the time
it might actually become less readable
certainly once your regular Expressions
get this big instead of this big so
let's save space where we can and I
would argue that this is pretty
reasonable so long as you're in the
habit of reading regular expressions and
know that question mark does not mean a
literal question mark but it means zero
or one of the thing before I think we've
effectively made the S optional here now
what else can I do well suppose we want
to tolerate the www dot which may or may
not be there uh but it will work if you
go to a browser I could do this
www. uh wait I want a backs slash there
so I don't repeat the same mistake as
before but this is no good either
because I want to tolerate www being
there or not being there and now I've
just required that it be there but I
think I can take the same approach any
recommendations how do I make the www
dot optional just to hammer this home we
can like group uh make a
and question mark perfect so question
mark is the short answer again but we
have to be a little smarter this time as
Maria's noted we need parentheses now
because if I just put a question mark
after the dot that just means the dot is
optional and that's wrong because we
don't want the user to type in wwwt w i
TT e r we want the dot to be there or
just not at all with no www so we need
to group this whole thing together put a
parenthesis there and then a parenthesis
not after the third W after the dot so
that that whole thing is either there or
it's not there and what else could we
still do here you know there's going to
be one other thing we should tolerate
and it's been said before and I'll pluck
this one off what about the protocol
like what if the user just doesn't type
or doesn't copy paste the HTTP colon
slash or an https colon right honestly
you and I are not in the habit generally
of even typing the protocol anymore
nowadays you just let the browser figure
it out for you and automatically add it
instead so this one's going to look like
more of a mouthful but if I want this
whole thing here in blue to be optional
it's actually the same solution as Maria
offered a moment ago I'm going to go
ahead and put a parenthesis over here
and a parenthesis after the two slashes
and then a question mark so it's to make
that whole thing optional as well and
this is okay it's totally fine to make
this whole thing optional or inside of
it this little thing just the S optional
as well so long as I'm applying the same
principles again and again either on a
small scale or a bigger scale it's
totally fine to Nest one of these inside
of the other
questions now on any of these
refinements to this parsing this
analyzing of Twitter what if we put a
vertical bar besides this www do what if
we use a a vertical bar there so we
could do something like that too we
could do something like this uh instead
of the question mark I could do www. or
nothing and just leave that in the
parenthesis that too would be fine I
personally tend not to like that because
it's a little less obvious to me wait a
minute is that deliberate or did I
forget to finish my thought by putting
something after the vertical bar but
that too would be allowed there as well
if that's what you mean other questions
on where we left things here where we
made the protocol optional too what
coulden if we have parenthesis and then
inside we have another parenthesis and
another parenthesis to feel with each
other if you have parentheses inside of
parentheses that too is totally fine and
indeed that should be one of the
reassuring lessons today as complicated
as each of these regular Expressions has
admittedly gotten I'm just applying the
exact same principles in the exact same
syntax again and again so it's totally
fine to have parentheses inside of
parentheses if they're each solving
different problems and in fact the
lesson I would really emphasize the most
today is that you will not be happy if
you try to write out a whole complicated
regular expression all at once like if
you're anything like me you will fail
and you will have trouble finding the
mistake because my God look at these
things they are even to me all these
years later cryptic the better way I
would argue whether you're new to
programming or as old to it as I am is
to just take these baby steps these
incremental steps where you do something
simple you make sure it works you add
one more feature make sure it works add
one more feature make sure it works and
hopefully by the end because you've done
each of those steps one at a time the
whole thing will make sense to you but
you'll also have got gotten each of
those steps correct um at each turn so
please do avoid the inclination to try
to come up with long sophisticated
regular Expressions all at once because
it's just not a good use of a time if
you then stare at it trying to find a
mistake that you could have caught if
you did things more incrementally
instead all right there Still Remains
arguably at least one problem with this
solution in that even though I'm calling
re.sub to substitute the URL with
nothing quote unquote I then on my final
line of code line six I'm just blindly
assuming that it all worked and I'm
going to go ahead and print out the
username but what if the user if I clear
my screen here and run python of
twitter. doesn't even type a Twitter URL
what if they do something like
https
www.google.com slash like completely
unrelatedly for whatever reason enter
that is not their Twitter username so we
need to have some conditional logic I
would argue so that for this program's
sake we're only printing out or in a
backend system we're only saving into
our database or a CSV file the username
if we actually matched the proper
pattern so rather than use re.sub which
is useful for cleaning up data as we've
done here to get rid of something we
don't want there why don't we go back to
re. search where we began today and use
it to solve the same problem but in a
way that's conditional whereby I can
confidently say yes or no at the end of
my program here's the username or here
it is not so let me go ahead now and
I'll clear my terminal window here I'm
going to keep most of uh the I'm going
to keep the first two lines the same
where I import re and I get the URL from
the user but this time let's do this
let's this time search for using re.
search instead of re.sub the following
I'm going to start matching at the
beginning of the UR of the string
https uh question mark to make the S
optional colon SL slash then I'm G to
make my uh www
uh optional by putting that in question
marks there then a twitter.com with a
literal dot there so I'll stay ahead of
that issue too then a slash and then
well this is where David J ma is
supposed to go how do I detect this well
I think I'll just tolerate anything at
the end of the URL here all right dollar
sign at the very end close quote for the
moment I'm going to stipulate that we're
not going to worry about question marks
at the end or hashes like for fragment
IDs and URLs we're going to assume for
Simplicity now that the URL just ends
with the username alone now what am I
going to do well I want to search for
this URL specifically and I'm going to
ignore case so rei. ignore case uh uh
applying that same lesson learned from
before rei. search recall will return to
you the matches you've captured well
what do I want to capture well I want to
capture everything to the right of the
twitter.com URL here so let me surround
what should be the user's username with
parentheses not for making them optional
but to say capture this set of
characters Now ar. search recall returns
an answer matches will be my variable
name again but I could call it anything
I want and then I can do this if matches
now I know I can do this let's print out
the format string username colon and
then uh what do I want to print out well
I think I want to print out matches.
group one for my matched username all
right so what am I doing just to recap
line one I'm importing the library line
two I'm getting the URL from the user so
nothing new there line five I'm
searching the user's URL as indicated
here as the second argument for this
regular expression this pattern I have
surrounded the plus with parentheses so
that they are captured ultimately so I
can't extract in this final scenario the
user's username if I indeed got a match
and matches is non none it is actually
containing some match then and only then
print out username in this way let me
try this now if I run python of twitter.
and type in HTTPS
www.google.com now nothing gets printed
so I've at least solved the mistake we
just saw where I was just assuming that
my code worked now I'm making sure that
I have searched for and found the
Twitter URL prefix all right well let's
run this for real now python of twitter.
https twitter.com davidj maen but note I
could use HTTP I could use www I'm just
going to go ahead here and hit
enter huh
none what has gone
wrong this one's a bit more
subtle but why does matches. group one
contain nothing wait a minute let me
maybe I maybe I did this wrong Maybe
maybe do we need the www let me run it
again so here we go https let add it
www. twitter.com davidj mail all right
enter what is going on we have to say
group group I have to say group two well
wait all right because we had the the
subdomain was optional and to make it
optional I needed to use parentheses
here and so I then said zero or one okay
so that means that actually I'm
unintentionally but by Design capturing
the www dot or none of it if it wasn't
there before but I have a second match
over here because I have a second set of
parentheses so I think yep let me change
matches group one to matches group two
and let's rerun this python of twitter.
https www. Twitter let's do this uh
twitter.com David J ma enter and now
we've got access to the username let me
go ahead and tighten it up a little bit
further uh if you like uh our new friend
uh it's hard not to like if we like our
old friend the wallus uh operator let's
go ahead and add this just to tighten
things up let me go back to vs code here
and let me get rid of the unnecessary
condition there and combine it up here
if matches equals that but let's change
the single assignment operator to the
Wallace operator now I've tightened
things up further but I bet I bet I bet
there might be another solution here and
indeed it turns out
that we can come back to this final set
of syntax recall that when we introduced
these parentheses we did it so that we
could do a or b for instance with the
vertical bar though you can even combine
more than just one bar we use the group
to combine ideas like the www do and
then there's this admittedly weird
syntax at the bottom here up until now
not used there is a non capturing
version of parentheses if you want to
use parentheses logically because you
need to but you don't want to bother
capturing the result and this would
arguably be a better solution here
because yes if I go back to vs code I do
need to surround the
www.t with parenthesis at least as I've
written my Rex here because I wanted to
put the question mark after it but I
don't need the www dot coming back in
fact let's only extract the data we care
about just so there's no confusion down
the road for me or my colleagues or my
teachers so what could I do well the
syntax per this slide is to use a
question mark and a colon immediately
after the open parenthesis it looks
weird admittedly those of you who have
prior programming experience might
recognize the syntax from Turner
operators doing an if else allinone line
a question mark colon at the beginning
of that parenthetical means yes I'm
using parentheses to group these things
together but no you do not need to
capture them instead so I can change my
code back now to matches. group one I'll
clear my screen here run python of
twitter. I'll again run here uh
https twitter.com davidj maen with or
without the www and now I indeed get
back that username any questions then on
these final
techniques so first of all could we move
the carrot right at the beginning of
Twitter and then just start reading from
there and then get rid of everything
else before that the kind of
WWE uh issues that we had and then my
second question is how would we um use
kind of I guess it either a list or a a
dictionary to to sort the do kind of
thing because we have dood UK and that
kind of St how would we bring that into
uh the re function a good question but
no if I move the carrot before
twitter.com and throw away the protocol
and the www then then the user is going
to have to type in literally
twitter.com username they can't even
type in that other stuff so that would
be a regression a step back as for the
do and the.org and.edu and so forth the
short answer is there's many different
solutions here if I wanted to be
stringent about do and suppose that
Twitter probably owns multiple domain
names even though they tend to use just
this one suppose they have uh something
like.org as well you could use more
parentheses here and do something like
this Comm or org I'd probably want to go
in and add a question mark colon to make
it non-capturing because I don't care
which it is I just want to tolerate both
alternatively we could capture that we
could do something like this where we do
dot plus so as to actually capture that
and then we could do something like this
if matches. group one now equals equals
Comm then we could support this so you
could imagine factoring out the logic
just by extracting the top level domain
or TLD and then just using python code
maybe a list maybe a dictionary to
validate elsewhere outside of the redx
if it's in fact what you expect for now
though we kept things simple we focused
only on the Doom in this case let's make
one final change to this program so that
we're being a little more specific with
the definition of a Twitter username it
turns out that we're being a little too
generous over here whereby we're
accepting one or more of any character I
check the documentation for Twitter and
Twitter only only supports letters of
the alphabet A through Z numbers 0-9 or
underscore so not just dot which is
literally anything so let me go ahead
and be more precise here at the end of
my string let me go ahead and say this
set of symbols in square brackets I'm
going to go ahead and say a through z uh
0 through 9 and an underscore because
again those are the only valid symbols I
don't need to bother with an uppercase a
or a lowercase C because we're using re.
ignore case over here but I want to make
sure now that I tolerate not only one or
more of these symbols here but also
maybe some other stuff at the end of the
URL I'm now going to be okay with there
being a slash or a question mark or a
hash at the end of the URL all of which
are valid symbols in a URL but I know
from the Twitter's documentation are not
part of the username all right now I'm
going to go ahead and run python of
twitter. one final time typing in
HTTPS
twitter.com David M maybe with maybe
without a trailing slash but hopefully
with my biggest fingers crossed here I'm
going to go ahead now and hit enter and
thankfully my username is indeed David J
Ma so what more is there in the world of
regular expressions and this own Library
not just re. search and also re.sub
there's other functions too there's re
dosit via which you can split a string
not using a specific character or
characters like a comma and a space but
multiple characters as well and there's
even functions like re . findall which
can allow you to search for multiple
copies of the same pattern in different
places in a string so that you can
perhaps and manipulate more than just
one so at the end of the day now you've
really learned a whole other language
like that of regular expressions and
we've used them in Python but these
regular Expressions actually exist in so
many languages too among them JavaScript
and Java and Ruby and more so with this
new language even though it's admittedly
cryptic when you use it for the first
time you have this new found ability to
express these patterns that again you
can use to validate data to clean up
data or even extract data and from any
data set you might have in mind that's
it for this week we will see you next
time
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
men and this is our week on
objectoriented programming or oop it
turns out that in the world of
programming there's different paradigms
of programming languages there's
different ways of solving problems with
code and it's a little hard to see this
at first if you've only learned one
language but over time if and when you
learn other languages besides python
you'll start to notice certain patterns
and certain capabilities of some
languages but not another thus far
within the world of python you and I
have largely been writing code that's
procedural in nature whereby we're
writing procedures we're writing
functions and we're sort of doing things
top to bottom everything is step by step
by step as you would expect in general
from an algorithm but along the way
we've actually dabbled in another
Paradigm known as functional programming
with python whereby we've been able to
pass functions around we even had an
anonymous function some weeks ago and
that's evidence of features of a
functional programming language even
though we've just scratched the surface
thereof today we focus on another
Paradigm and this one in more detail
namely objectoriented programming and
now while some of you might have prior
programming experience and have learned
languages like Java which are by Design
fundamentally objectoriented python
indeed allows you a bit of flexibility
when it comes to how you solve problems
with code but it turns out oop object
ented programming is a pretty compelling
solution to problems that you invariably
encounter as your programs get longer
larger and more complicated so indeed
oop for our purposes is going to be a
solution to a problem that builds on so
many of the lessons past so let's go
ahead and do this let's start by writing
a program very procedurally by opening
up VSS code here I'm going to go ahead
and create a program called student. and
in this program I want to do something
relatively simple initially uh as we
might have done some weeks ago now where
I just ask a user for their name and
maybe in the context of the Harry Potter
Universe their house and just print out
where that student is from and let's
gradually enhance this program by adding
more and more features to it and see if
we don't stumble upon problems that up
until now we might not have had very
elegant well-designed solutions to but
if we introduce explicitly
object-oriented programming as a
programming technique I bet we can clean
up our code and set the stage for
writing even more sophisticated programs
longer programs down the line so in
student. piy let me go ahead and do a
name variable setting it equal to the
return value of input and just prompt
the user for their name like this and
then let me go ahead and do the same for
a house variable and prompt the user for
their house using input like this and
let's do something super simple now
let's just go ahead and print out an F
string that says something like name
from house just so that I can confirm
that the contents of these variables are
indeed as I expect I'm not do any error
checking or trimming or anything like
that for now I'm really just going to
spit back out whatever the user just
typed in all right let me go ahead and
run python of studenty let's use our
go-to like Harry as in Harry Potter from
Gryffindor and when I hit enter now
let's see if I see that Harry from
Gryffindor is indeed the case all right
so I think we have a working program at
this point but let's now introduce some
of those Lessons Learned way back from
week zero where we started writing our
own functions not necessarily because it
solves the problem more correctly I dare
say this is correct as is but it begins
to give us building blocks that we can
extend so as to solve more complicated
programs so let me go back up to
student. and let's go ahead now and do
this let's put the entire logic I just
wrote inside of our typical method
called Main and let me indent those
three lines so that at least they're now
combined into one main method but
instead of using input on line two and
input on line three why don't we go
ahead and assume for the moment that
we've got some function called get name
in the world and let's go ahead and
assume we've got another function like
get house in the world that don't take
parameters but their purpose in life is
by their Nam going to be to get the
user's name and to get their user house
respectively and then I'm going to print
out the exact same F string as before I
of course need to implement these
functions now so let me go lower in my
file and Define a function called get
uncore name nothing in these parentheses
because it's not going to take a
parameter and I'm going to go ahead and
do something like name equals input
quote unquote name just like before and
then I'm going to go ahead and return
name so it's a super simple function but
it's a an abstraction I now have a
function called get name whose
implementation details I don't have to
care about anymore I just know that the
function exists and I can tighten this
up in fact I don't really need a name
variable on line 8 if I'm immediately
going to return that same name variable
on line nine so let me just tighten this
up a little bit even though it doesn't
change the functionality and just
immediately return the return value of
the inputs uh function call here let's
do something very similar now for get
house which will similarly take no
arguments I'm going to go ahead and
return the return value of input this
time prompting the user for their house
and I need one final detail at the very
bottom let's continue our habit of doing
if the name of this file equals equals
quote unquote main then let's go ahead
and actually call Main and recall that
we have that in place so that if this
eventually becomes part of a module a
library of sorts I don't accidentally
call Main blindly I only do it if I mean
to run main from the command line on
this file all right so if I didn't make
any mistakes here let me go ahead and in
my terminal window again run python of
student. enter let's type in Harry enter
let's type in Gryffindor enter and we're
set Harry from Gryffindor seems to still
be working so we haven't really solved
the problem anymore correctly but I've
laid the foundation to maybe now do some
more interesting things because I've
have these building blocks in place
all right but let me propose that we
could be doing this a little bit
differently get name get house is fine
but at the end of the day I'm really
trying to get a student from the user I
want their name and their house not just
one or the other so maybe it would be a
little cleaner still to define a
function called get student and let get
student do all of this work for us now
theoretically get student could call get
name and could call get house but
because these functions are so short I
think I'm okay with just defining one
function called get student that
similarly won't take any arguments but
it's going to do two things it's going
to get the student's name by prompting
them with input as before and it's going
to get the student house by also
prompting them as before and then now hm
I want to return the student but I think
I might have painted myself into a
corner here because I now have two
variables name and house and yet up
until now we've pretty much returned one
or the other we've returned one value so
any suggestions for how we can perhaps
solve this problem that I just created
for myself whereby I want to return
really a student but I currently have a
name variable and a house variable I'd
minimally like to return both of those I
believe that we can return a dictionary
includes the name and the house yeah so
we absolutely could return a dictionary
a dict object in Python whereby maybe
one key is name one key is house and the
values thereof are exactly the values of
these variables we could totally do that
uh I worry that that might be getting a
little complicated I wonder if there's a
simpler way instead any other instincts
even if you're not sure it would work
return both name and house return both
name and house I I like the sound of
that it sounds simple I don't have to
figure out what a dictionary is going to
look like and in fact this too would be
a valid approach even if you've not seen
this before it turns out in Python that
you can kind of return multiple values
but that's a bit of a white lie or we
could take Muhammad's approach of
actually return rning a dictionary and
putting multiple keys there in so here
again we have yet another example of how
you can solve the same problem in at
least two ways and I dare say we're
about to see even more so one way you
could solve this problem whereby you
want to return multiple values would be
to do something like this I could go
ahead and literally return not just name
but I could put a comma and also return
house this is not necessarily something
you can do in other languages if you
have programmed in other languages
before it depends on the language but it
looks like thanks to this comma maybe I
can in fact return two values as
actually proposed well if I'm returning
two values in this way on line 10 how do
I get both values at the same time well
there's a couple of ways let me go up to
my main function I know minimally I'm
going to have to change the get name and
get house to get student but what am I
going to store the return value in I
think I could actually do this and we
have seen this technique before where
you can unpack so to speak speak
sequences of values that are coming back
and indeed consider this to be exactly
that name comma house is some kind of
sequence that I'm returning of values
name comma house so if I want to unpack
those and store the return values in two
separate variables I can in fact use the
commas on the left hand side of my
assignment operator the equal sign to do
just that now to be clear I don't need
to call these variables name and house
here I could simplify this and use just
n here and H here and then I could
return just n and H but I would argue
that's not very uh clear to the reader
as to what's going on so I think in this
case even though it's a coincidence that
I've used the same variable names in get
student and get Main and in Maine it's a
little more readable to someone like me
so I'm going to leave it as is well
let's go ahead and see now if this works
let me clear my screen down here and run
python of student. enter let's again
type in Harry let's again type in
Gryffindor enter and voila we still see
that Harry is from Gryffindor but what
are we actually doing here what are we
actually doing by returning this value
well it turns out that what we've just
done is used a tupple a tupple is
another type of data in Python that's a
collection of values X comma y or X
comma y comma Z it's similar in spirit
to a list in that sense but it's
immutable it's not mutable now what does
that mean a list as we've seen it before
is a data structure in Python that you
can change the values of you can go into
bracket zero for the first location and
change the value there you can go to
bracket one bracket two bracket three
and actually change the values in lists
but if you have no intention of changing
the values of variables and you want to
return effectively multiple values you
don't have to even return it as a list
you can return it as a tle instead just
by using a comma and it turns out we can
make explicit that here's the white lie
I'm not actually returning two values
per se whenever you use a comma in this
way on line nine you're actually
returning one one value which is a
tupple inside of that tupple now are two
values so it's similar in spirit to
returning one list with two things here
I'm returning one tupple with two things
and the mere fact that I've used a comma
and nothing else tells python that I
indeed want to return a tle but there's
more explicit syntax that we can use
instead I can actually more verbosely
put explicit parentheses around the
values of this tupple just to make more
clear to me to the reader that this
isn't two values per se this is one
value with two things inside of it and
what I can actually do then too is I
don't have to unpack this up here so to
speak I can actually go up here and
maybe give a more apt name like student
and I can name the value or rather name
the variable in which I'm storing the
return value of get student as quote
unquote student so maybe this is a
little better design now because I'm
sort of abstracting away what a student
is it's implemented at the moment as a
tupple with two values but at least now
I have a variable called what I mean a
student but there's going to be a catch
on line three I still want to print out
that Student's name and their house but
I don't have a name variable anymore and
I don't have a house and I also don't
have a dictionary as was proposed
earlier so I can't even go at those keys
by name but what a tupple is it's very
similar in spirit to a list but it is
indeed just immutable and what I mean by
that is I can still index into it
numerically by saying student square
bracket Z for the item in the first
location in that Tuple and then over
here instead of house I can say student
bracket one student bracket one is going
to give me the second location in that
tupple let me go ahead and clear my
terminal window again run python of
student. let's type in Harry let's type
in Gryffindor enter and we still have
some working code let me pause here now
and see if there are any questions on
this technique of returning a tupple and
indexing into it in this way I guess
what's a like a actual use case where
you would use a tupple versus you know a
list or something else that's similar
it's a really good question when would
you use a tuple versus a list when you
want to program defensively or in
general when you know that the values in
this variable shouldn't change so why
would you use a data type that allows
them to be changed it just invites
mistakes bugs down the line either by
you or colleagues who are interacting
with your code so tupple is just another
way where you can increase the
probability of correctness by just not
letting anyone yourself included change
the contents therein so it's just
another tool in your toolkit but let's
make clear then what I mean by immutable
again I claim that immutable means that
you cannot change the value well let's
go ahead and try to do this let me go
ahead and run this program once more as
is python of student. let me go ahead
and type in for instance uh how about uh
padma's name and I'm going to go ahead
and say that padma's in Gryffindor as in
the movies and we see Padma from
Gryffindor but technically I went down
this rabbit hole and looking at Harry
Potter more closely technically in the
books Padma I believe was from Ravenclaw
so this is actually a mistake or an
inconsistency between the movies and the
books let's see if we can't fix this
inconsistency in our code so how about
we do this if the student's name that's
inputed equals Padma why don't we
override whatever the uh whatever the
house is and change it to be properly
Gryffindor let me go ahead and do if
student now if I want to get at padma's
name I'm going to have to do student
bracket zero I have to know what
location the name is in in this tupple
but if that in value equals equals Padma
let's go ahead with this if statement
and make a change let's change the
students F uh bracket one value so the
second value if we're zero indexing
let's change it to be another house in
the World of Harry Potter called
Ravenclaw so I'm just fixing maybe the
user's input they watch the movie so
they typee in Padma Gryffindor but mm-
the books it was Padma from Ravenclaw
all right let me go ahead and go down to
my terminal window clear my uh terminal
and do python of student. enter I'm
going to do Harry as well as Gryffindor
just to demonstrate that that is still
working as intended Let Me Clear My
screen again though and run python of
studenty on Padma and I'll put her too
in Gryffindor as in the movies and hit
enter and now I just see a big mess of
errors on the screen some kind of
exception has been thrown and indeed a
type error has happened happened I'm
using a data type wherein there's an
error and what is that error well tupple
object does not support item assignment
it's a little arcany expressed that is
that's not really very user friendly but
if you think about what those words mean
tupple object does not support item
assignment so assignment is copying from
right to left so somehow that's invalid
and here is a manifestation of the
immutability of tuples you cannot change
location zero or one or anything inside
that is a feature that is the design of
a tuple so if I want to override that I
think I'm going to have to use a
different type of data that we've used
before namely a list and that's fine if
you want to enable yourself and
colleagues using your code to change the
contents of that container well we can
go ahead and return not a tupple using
explicit parentheses or no parentheses
just the comma but I can use square
brackets and if I'm using square
brackets on the left and the right this
is indeed explicitly a list same idea
but it's mutable that is to say you can
change the contents of a list so making
no other changes just returning a list
with square brackets instead of a tuple
with parentheses or just the comma let
me go ahead now and run python of
student. enter let me type in Harry and
Gryffindor again that's still working
good to see let me run this once more
and type in Padma and Gryffindor as in
the movies but no now we've corrected it
to be Padma from Raven claw as in the
books
instead any questions now on tupples
versus lists or this idea of
immutability versus
mutability uh can we use a nested tle in
Pyon like a a nested lists absolutely
you can have not only nested lists in
Python where one of the elements in a
list could be another list so you have
some square brackets out here you might
have some other square brackets inside
you can absolutely do the same with a
tupple as well there's no constraint on
the types of values you can put in there
we've not had occasion to do that in
this case I'm just returning a simple uh
simple tupple with two elements but yes
you could absolutely do that too other
questions on tles versus lists okay for
example um when I see the square bracket
um is it mainly used for the list oh a
really good question uh sort of so when
you create a value like a list you use
square brackets and that would indeed be
a visual indicator that this is
definitely a list uh if you instead see
parentheses that's a visual indicator
when creating a value that it's
definitely a tupple however somewhat
confusingly both lists and topples use
square brackets when you access the
contents of them when you index into
them at location zero or location one
you always use square brackets so that's
the distinction there good question
allow me to propose now if I may that we
solve this problem yet another way and
let's see if we're either making things
Better or For Worse than us recall that
dictionaries or dict objects also exist
in python and a dictionary is this
collection of keys and values and the
upside in particular of a dictionary is
that they have better semantics right
you don't just have to assume that a
name is always going to be at location
zero house is always going to be at
location one I mean that's the kind of
thing especially if you had three four
or more values eventually you or someone
is going to get confused and forget what
the order is and you're going to write
buggy code so a dictionary is a little
more powerful and that you can
semantically associate Keys like little
descriptions with the values those keys
and those values respectively so let me
go ahead and do this and we can do this
in a few different ways but let me
propose that we focus on get student
here and let's go ahead and do this let
me go ahead and uh in delete the
implementation of get student as is let
me create a student variable and
initialize it to an empty dictionary and
I can do that with just two curly braces
here and then let me go ahead and set
two keys inside of that dictionary
inside of the student there will be
quote unquote a name key and the value
of that is going to be whatever the
return value of input is when I prompt
the user for their name and then the
house key inside of that same student
dictionary is going to be the return
value of whatever the user types in for
their house and lastly I'm going to go
ahead and return student so now I am
literally returning one thing still but
this time it's a dict rather than a
tupple rather than a list but there's
still two things in it technically four
things if you count the keys and the
values but there's two key value pairs
now my code up here is going to have to
change a little bit and let's simplify
this and remove for instance now the the
Padma if statement just to focus on
what's changing at hand and let me go
ahead now and leave line two alone I'm
still going to have a student variable
that gets assigned the return value of
get student but what I want to do here
now is actually access the keys in
inside of that dictionary not by numeric
index which was for tuples and lists
zero and one but by way of the keys now
normally I might be in the habit as I
personally am of using double quotes
quote unquote name inside of there and
quote unquote house inside of there but
before I even run this code and show you
a mistake see an error on the screen
does anyone want to call out what I have
done wrong here this is just an F string
I just want to print out the value of
the name key the value of the house key
in this dictionary
but your your audio was a little garbled
for us but I think I heard double quotes
and single quotes so I'm going to assume
that indeed you've identified precisely
the issue I'm just going to confuse
python right now even though this is an
F string inside of Double quotes
prefixed with an F I can't actually use
my double quotes inside my double quotes
because that's going to potentially
confuse python indeed if I run this
program now python of student. py and
hit enter I get a syntax error so the
program didn't even run fully it just
couldn't be understood because it got
confused by those double quotes So the
simplest fix here would indeed just be
to use not double quotes but single
quotes around the keys or conversely
flip the double quotes on the outside to
single quotes then use double quotes on
the inside you just want to be
consistent so a subtle detail but again
this is now specific to dictionary
syntax this isn't fundamental to how
we're solving this current problem at
hand all right well let's go ahead and
try this let me go ahead now and run
python of student. let's go ahead and
type in Harry let's type in Gryffindor
and hopefully Harry is back from
Gryffindor no syntax errors no other
errors I think I'm back in business here
and what I do like to be clear about
using a dictionary is that it is
allowing me just better semantics again
I don't have to remember memorize
document that zero is name one is house
instead name is name and house is house
it's just a little clear a little more
expressive so that's generally a good
thing especially if we stored more data
about students than just their name in
their house if you had three Fields four
five 10 different fields no one's going
to want to remember or be able to
remember forever which is zero which is
one which is two and so forth better to
introduce uh names like name and house
in this case but let me tighten this up
further in indeed I'm typically in the
habit of not introducing variables
unnecessarily unless they make the code
more readable and an alternative way to
format the same code would be this
strictly speaking I don't need to create
an empty dictionary then add one key to
it then add a second key to it and then
return that dictionary I can actually
consolidate this all into one statement
if you will let me go ahead and do this
let me go ahead and say name equals
inputs return value house equals inputs
return value and then instead of
returning any variable name student
which I'm going to propose doesn't need
to exist anymore let me just create and
return the dictionary all at once let me
do quote unquote name in lower case here
and then the variable it's storing the
user's name then quote unquote house as
my second key the value of which is
going to be house the variable now is
this better maybe maybe not maybe the
first wave was a little more readable
and that's totally fine to create
variables if they improve the
readability of your code but just know
that you can also create and return a
dictionary on the fly like this so to
speak all in one line and I think it's
arguably pretty reasonable in this why
it's just pretty short I probably
wouldn't do this if it got longer and
longer and longer I might minimally then
start moving my key value pairs to
separate lines but this would just be a
slightly more compact way of doing this
as well but let me propose we do one
more change let's go ahead and introduce
that same special casing of Padma to fix
her house from Gryffindor for instance
to Ravenclaw how do we do this with
dictionaries well dictionaries like
lists are mutable you can change what is
in them just just like you can lists and
how do you do that is just a little
different syntactically so let's go back
into Main and do this fix if the student
variable has a name key that equals
equals Padma then indented go ahead and
change the value of the house key inside
of that student dictionary to be quote
unquote Ravenclaw instead so very
similar in spirit to what we did with a
list but instead of using location zero
and one we're much more clearly
explicitly semantically using quote
unquote name and quote unquote house
because you index into lists and topples
using numbers but you index into
dictionaries using strings as I've done
here all right let me go ahead and run
python of studenty we'll again do Harry
from Gryffindor and I think all as well
let me run it one more time this time
with Padma who in the movies is from
Gryffindor but should really be from
Ravenclaw are any questions then on this
progression from tuples to lists to
dictionaries we haven't necessarily
introduced anything new other than those
tupples which have been available to us
all this time but the goal at the moment
is just to demonstrate this distinction
among these different data types and how
they each work a little bit differently
what if a a combination of lists is
there in a tle so is the list like we
can change the list because tle are imut
but lists are mutable correct you can
change the contents of lists and you can
put most anything you want in them other
lists or strings as I've done integers
or anything else tuples you can do the
exact same thing but you cannot change
them once you've created them a
dictionary is more like a list in that
it is mutable you can change it but the
way you index into a dictionary is by
way of these Keys these strings as we
keep seeing rather than by numbers those
numeric indices
all right well let me propose that there
is yet another way of solving this
problem and indeed I would argue that
there's now an opportunity to hand even
though this program isn't particularly
complicated all I'm doing is collecting
a name from the user and a uh house from
the user you could imagine wanting
longer term to collect even more
information like the students's Patronis
or magical spell or a whole bunch of
other information that might belong in a
student and right now we're just kind of
using these very general purpose data
types in Python a tuple to combine some
values together a list to do the same
but let us change it later a dictionary
which is more powerful because it's a
little more structured it does have keys
and it has values not just values but
you know what this we wouldn't have to
be having this conversation if the
authors of python had just given us a
data type called student right wouldn't
it have been nice if there were just a
type of variable I could create in my
code called student then we wouldn't
have to figure out well do we use a
tuple or a list or a dictionary but
that's pretty reasonable right you could
imagine just a how slippery of a slope
that is so to speak if the creators of a
language had to anticipate all the
possible types of data that programmers
like you and me want to store in your
programs so they just gave us these
general purpose tools but they gave us
another general purpose tool that's
going to allow us to create our own data
types as well and actually give them
names and that uh terminology is a class
a class is kind of like a blueprint for
pieces of data objects so to speak a
class is kind of like a mold that you
can define and give a name and when you
use that mold or you use that blueprint
you get types of data that are designed
exactly as you want so in short classes
allow you to invent your own data types
in Python and give them a name and this
is a primary feature uh of
objectoriented programming to be able to
create your own objects in this way and
in the case of python and classes even
give them some custom names so what does
this mean in real terms well let me go
ahead and come back to vs code here and
let me propose that we introduce a
little bit of new syntax I'm going to go
ahead and clear my terminal window first
I'm going to go to the top of my file
and I'm just going to start a thought
but not finish it yet I'm going to use
this new keyword for classes called
literally class so indeed the new
keyword we're going to have here and if
I go back to our slides here this this
would be the official URL where you can
read up more on this particular feature
of python in the official tutorial class
is a new keyword we can use now this is
coincidentally related to students
because students take classes but it has
nothing to do with the fact that we're
dealing with students class is a general
purpose term in a lot of languages
python among them that allow you to
Define these custom containers with
custom names for pieces of data so let's
go back to VSS code let's use this new
keyword and let me propose that we
create a class called student and by
convention I'm going to use a capital S
here and I'm going to go ahead and with
a colon get to later the implementation
of this class so I'm just going to use
dot dot dot which is a valid placeholder
for now that just indicates to me that
I'm going to come back to implementing
this later but as of now it does in fact
exist I now have a student uh class
defined for me that I can now use in my
code here how am I going to use it well
first of all let me go down to get
student and let me change this code to
no longer use a dictionary but to use
this class I'm going to do this I'm
going to give myself a variable called
student as I've done before but I'm
going to set it equal to Capital student
open parenthesis close parenthesis so
I'm going to do what appears to be
calling a function and that function
student with a capital S notice matches
the name that I gave this class at the
top of my file all right what do I next
want to do I'm going to go ahead and
give this student a name now if if I
were still using a dictionary I would
say student quote unquote name using
square brackets but this is not a
dictionary it turns out classes have
what for now we'll call attributes
properties of sorts that allow you to
specify values inside of them in the
Syntax for that happens to be a DOT
we've seen dots before we've used it in
the context of modules and libraries
more generally this is another similar
INSP Spirit use of a DOT that allows you
to get at something inside of something
else so student. name is going to be the
syntax I use for giving this student a
name and that name is going to be
whatever the return value of name is and
then I'm going to go ahead and say
student.h house to give another
attribute called house and give that the
return value of input here prompting the
user for house and then as before I'm
just going to return student but now
what's really powerful about class and
objectoriented programming more
generally is that I've created this
custom data type called literally
student capital S I've stored one such
student in a variable like I can always
do in a variable called student
lowercase s but I could call it anything
I want I just makes sense to call it
student as well but lowercase for
clarity and then I'm returning that
variable and because of my syntax in
lines 14 and 15 that has the result of
putting inside of that class a name
attribute and a house attribute I just
need to make one more change up here I'm
going to go ahead and remove our Padma
code just so we can focus only on what's
new rather than fixing her house and I'm
going to go in here and change the
syntax that previously was for
dictionaries again dictionaries use
square brackets and then strings in
quotes either single quotes or double
quotes depending on the context here
though I'm going to change this to be
student. name and over here I'm going to
change it to be student. house and
that's just going to be my new syntax
for getting the contents of what appears
to be a class called student let me go
ahead and rerun python of student. by
enter let's type in Harry's name as
before let's put him in Gryffindor
crossing our fingers as we often do and
Harry is indeed from
Gryffindor what though have I done let's
introduce one other bit of terminology
here it turns out that I can create a
class using that class keyword but
anytime you use a class you're creating
what are called objects and here is the
word objects as in objectoriented
programming or oop let me go back to my
code here and even though I haven't
really implemented much of it at all I
literally just left it with a dot dot
dot that's enough code lines one and two
to just invent a new data type called
student capital s that may or may not
have some future functionality as well
that's enough to create a class what
though am I doing on line 11 on line 11
what I'm technically doing is creating
an object of that class so this too is
another term of art you create objects
from classes so if we go back to that
metaphor that a class is like a
blueprint for a house or a class is like
a mold an object is when you use that
blueprint to build a specific house or
something that comes out of in plaster
the mold when you actually use that mold
to create such an object so a class is
again the definition of a new data type
the object is the Incarnation of or
technically instantiation of and another
term for objects would actually be an
instance you have instances of classes
as well so that's a lot of vocabulary
but at the end of the day it just boils
down to this you can Define your own
class which is really your own data type
you can then store attributes inside of
it using this dot notation here and then
you can access those same attributes
using Code like this here and now I have
a proper student data type and I don't
have to kind of hack something together
using a tupple or a list or even a
dictionary I now have a proper data type
called student that the authors of
python didn't give me I gave myself any
questions now on classes this new
keyword class or this idea of these
objects or instances thereof is the
class object mutable or immutable a good
question and we've clearly laid the
stage for having that conversation about
every data type now we will see that
they are mutable but you can make them
immutable so you can get the best of
both worlds Now by writing some actual
code and we'll write more code than the
DOT dot dot in just a bit other
questions on classes or these objects
thereof then what would be the
properties of those glasses uh so at the
moment the properties of or the
attributes of as I've been calling them
thus far would just be name and house it
turns out that there may very well be
other attributes built into classes that
we may see before long but for now the
only two attributes that I care about
are the ones that I myself created
namely name and house are again what I
would call attributes and in a little
bit we're going to start calling those
same attributes more technically
instance variables name and house as
I've presented them here in VSS code are
really just variables called name and
called house inside of an object whose
type is student all right so what more
can we do with these classes well again
online 11 is where we're instantiating
an object of the student class and
assigning it to a student variable we're
then adding attributes name and house
respectively on lines 12 and 13
currently both of those have values that
are technically strings or stirs because
that's what the return value of input is
but those attributes values could
actually be any data type we're just
keeping things simple and focusing on
defining students in terms of two
strings name and house and then on line
14 we're returning that variable we're
returning that object to main so that we
can actually print out who is from what
house well let's go ahead and add a bit
more functionality here because right
now on lines 12 and 13 this is a little
manual and it's a little reckless of me
to just be putting anything I want
inside of this student object it turns
out with classes unlike with
dictionaries we can actually standardize
all the more what those attributes can
be and how what kinds of values you can
set them to so let me go ahead and do
this let me propose that it would
actually be really nice if instead of
doing this here let me go ahead and
simplify my code as follows let me go
ahead and give myself a local variable
called name and set it equal to the
return value of input like we've done
many times now already let me give
myself one other variable for now called
house and set it equal to the return
value of input as well prompting the
user for their house and now instead of
creating a student object from my
student class and then manually putting
the name attribute inside of it and the
house attribute inside of it let me
actually do something more powerful let
me do this let me call that student
function which is identical to the class
name just by defining a class you get a
function whose name is identical to the
class name with the capital letter
included but instead of just doing open
parenthesis close parenthesis let me
pass in the name that I want to fill
this this object with and the house that
I want to put in that object as well and
now let me set the return value as
before to be student equals like this so
what have I done that's different
fundamentally I'm still getting user
input in the same same way I'm using
input on line 11 and input on line 12
and I just so happen to be storing those
return values in local variables but now
now we're setting the stage for the more
powerful features of classes and
object-oriented programming more
generally notice that I'm deliberately
passing to this capital S student
function name comma house I'm passing in
arguments to the function now the
student class is not going to know what
to do with those yet but now I'm sort of
standardizing how I'm passing data into
this student class and ultimately it's
going to give me an opportunity to error
check those inputs to make sure that the
name is valid that it has a value and
it's not just the user hitting enter
it's going to allow me to ensure that
it's a valid house that it's Gryffindor
or Hufflepuff or Ravenclaw or Slytherin
or not just hitting enter or some random
value that the user types in because I'm
passing name and house to the student
class this particular function I'm going
to have more control over the
correctness of my data so let's now go
up to the student class which up until
now I left as just dot dot dot it turns
out that in the context of classes there
are a number of not just uh attributes
or instance variables that you can put
inside but also methods classes come
with certain methods or functions inside
of them that you can Define and they
just behave in a special way by nature
of how python works these functions
allow you to determine behavior in a
standard way they are indeed special
methods in that sense now what do I mean
by this well let me go back to vs code
here and let me propose that I start to
define a standard function called uh
underscore underscore or Dunder as it's
abbreviated in it underscore underscore
and then I'm going to go ahead and do
open parenthesis and then I'm going to
put in here literally the word self more
on that in just a moment but now inside
of this function I'm going to have an
opportunity to customize is this uh
classes objects that is to say this
underscore uncore init method or Dunder
init method is specifically known as an
instance method and it's called exactly
this this is designed by the authors of
python and if you want to initialize the
contents of an object from a class you
define this method and we'll see what
it's about to do here let me go back to
vs code and let me do something like
this self. name equals name and self.
house equals house but I don't want to
just init this object very generically I
want this method called in it to take in
not just self but name comma house as
well now what in the world is going on
because there's a lot of weird syntax
here there's this Dunder init method
double underscore init double underscore
there's all of a sudden this parameter
called self and then there's this new
syntax self. name and self. house now
you're seeing really a manifestation of
objectoriented programming it's not all
that different fundamentally from what
we've been doing for weeks with
dictionaries by adding keys to
dictionaries but in this case we're
adding variables to objects AKA instance
variables to objects now what's going on
let's do this in Reverse let's go back
to the line of code we wrote earlier on
line 15 I am treating the name of this
class student with a capital S as a
function and I am passing in two values
name and house what I've highlighted
here on the screen on line 15 is
generally known as a Constructor call
this is a line of code that is going to
construct a student object for me using
synonyms it is going to instantiate a
student object for me and again how is
it going to create that object it's
going to use the student class as a
template as a mold of sorts so that
every student is structured the same
every student is going to have a name
every student's going to have a house
but because I can pass in arguments to
this student function capital S I'm
going to be able to customize the
contents of that object so if you think
about the real world if you've ever been
on a street or a neighborhood where all
of the houses kind of look the same but
they're might be painted differently
they might be decorated a little bit
differently on the outside all of those
houses might have been built using the
exact same blueprint sort of a mold if
you will but then you can specialize
exactly the finer points of those houses
by painting the outside a different
color or planting different trees you
can style them differently similar uh in
spirit here we have a student blueprint
that's always going to have now a name
and a house but it's up to you and me to
pass in any name in any house that we
want now where is this function the fact
that I'm calling student capital S and
then a parenthesis and a Clos
parenthesis with arguments inside
suggest that there's a function
somewhere in the world that has been
defined with def that's going to be
called well as you might have guessed by
now the function that will always be
called by definition of how python
classes work is a function called double
underscore in it double underscore why
it's a crazy name but it's what the
authors of python chose to just
implement the
initialization of an object in Python
now the only weird thing especially
weird thing I will admit is this it
would be way clearer to me too if the
only two parameters for in it were just
name comma house right that's how we've
defined every function thus far in the
class you just specify the parameters
that you want the function to accept and
indeed that lines up with what I'm doing
on line 15 I am only passing in two
things to the student function but it
turns out that the authors of python
need to give us a little bit of help
here because suppose that you pass in
name and house to this init method and a
method is just a function inside of a
class what are you going to do with the
name in the house like literally where
are you going to put them if you want to
remember the name in the house for this
student you've got to be able to store
those values somewhere and how do you
store them in the current object that
has just been
instantiated well the authors of python
decided that the convention is going to
be that this init method also semi
secretly takes a third argument that has
to come first by convention it's called
self but you could call it technically
anything you want but the convention is
to always call it self and self as its
name implies gives you access to the
current object that was just created
what does that mean again now on line 14
now that it's moved down a little bit
this line here is a Constructor it
constructs a student object but there's
nothing in that object initially there's
no name there's no house but the object
exists in the computer's memory it's up
to now you to store the name and the
house inside of that object how do you
do that well python will just
automatically call this init method for
you and it's going to automatically pass
in a reference to a an argument that
represents the current object that it
just constructed in memory for you and
it's up to you to populate it with
values and what this means is that
inside of your init method you can
literally do self. name to create a new
attribute AKA an instance variable
inside of that otherwise empty object
and put this name inside of it it allows
you to do self. house and store that
value of house now you could call these
things anything you want they could be n
they could be H as before but that's
really not very self uh explanatory much
better to do this kind of convention
self. name equals name self. house
equals house and this is like installing
into the otherwise empty object the
value name and house and storing them in
really identically named instance
variables in the object and again an
object is just an instance of a class
now I know that was a lot of vocabulary
that's a lot of weird syntax so any
questions on this init method whose
purpose in life again is to initialize
an otherwise empty object when you first
create it so what is the difference
between the init method and default
Constructor a good question so in other
languages if you programed before for
instance Java there are functions that
are explicitly called Constructors that
indeed construct an object they
initialize it with values python
technically calls this init method the
initialization method it initializes the
value it's on line 14 uh line 15 now of
my code if I scroll back down that I'm
technically constructing the object it
turns out there's another special method
in Python that we won't talk about in
detail today called underscore
underscore new underscore underscore
that actually handles the process of
creating an empty object in memory for
us but generally speaking you the
programmer don't need to manipulate the
new function it just works for you
instead you define your own init method
here an init function inside of your
class and that method initializes the
contents of the object so there's
technically a distinction between
constructing the object with new and
initializing it within it but in the
world of python you pretty much only
worry about the init method python
generally does the other part for you a
good question others uh what about if
you want to store more than one name or
more than one house a good question if
you want to store more than one name or
more than one house you can do this in
different ways you could create other
attributes technically called instance
variables like self. name one self. name
two but we've seen in the past that that
is not a very good design just to have
multiple variables to store multiple
things maybe instead you have an
instance variable called self. names
plural and you set it equal to a list of
names or a list of houses now in this
case I don't think that really solves
the problem because I'm trying to
implement a student singular so it
doesn't really make sense to have
multiple first names maybe a nickname
maybe a last name so we could add those
to but I don't think we need multiple
names per se and in this case multiple
houses but absolutely you could do that
using some of our familiar building
blocks like lists other questions how
are classes or objects represented in
memory how are classes and objects
represented in memory so the class is
technically just code it is the code on
the top of my file lines one through
four that defines that blueprint that
template if you will um objects are
stored in the computer's memory by
taking up some number of bytes so you're
probably familiar with bytes or
kilobytes or megabytes there's some
chunk of bytes probably all in the same
location in the computer's memory or Ram
where those V where those objects are
stored but that's what python the
program handles for you python The
Interpreter figures out where in the
computer's memory to put it you and I
the programmers get to think and solve
problems at this level python The
Interpreter handles those lower level
details for you how about one final
question on classes and objects now my
question is if we can the same do the
same thing with the dictionary so I to
use classes good question if you can do
the same things as you can with
dictionaries why should you use classes
because we are just scratching the
surface now of what you can do with
classes allow me to go back now to my
keyboard and show you more of what you
can do with classes but in short you can
do much more with classes you can ensure
the correctness of your data much more
with classes you can error check things
and generally you can design more
complicated software more effectively
and we'll continue to see today features
of python and object-oriented
programming more generally that allows
us to do just that so let me propose in
fact that first let's just tighten up
this current implementation which again
has us with an init method that just
declares two instance variables self.
name and self. house which again just
creates those variables inside of the
otherwise empty object and assigns them
values name and house respectively let
me go ahead and just do one little thing
here I don't really need the student
variable let me just tighten this up so
that each time we improve or change the
code we're focusing really on just the
minimal changes alone so I've not
fundamentally done anything different I
just got rid of the variable name and
I'm just returning the return value of
this student function that's
constructing my new object for me so I'm
just tightening things up as we've done
many times in the past well what if
something goes wrong when in creating
this student for instance what if the
user does not give us a name and they
just hit enter when prompted for name
like I don't want to put in my
computer's memory a sort of bogus
student object that has no name right
I'd ideally like to check for errors
before I even create it so I don't
create a nameless student it would just
be weird and probably a bug to have an
object that has no name similarly I
don't want the user to be able to type
in something random as their house at
least in the World of Harry Potter
there's really only four houses at
Hogwarts at least or there's again
Gryffindor and Hufflepuff and Ravenclaw
and Slytherin a list of four valid
houses it would be nice if I somehow
validated that the user's input is
indeed in that list now I could do all
of that validation in my get student
function I could check is the name empty
if so so don't create the student object
is the house one of those four houses if
not don't create the student object but
that would be rather decoupled from the
student itself right get student
currently exists as just my own function
in my student. py file but classes and
really object-oriented programming more
generally encourages you to encapsulate
inside of a class all functionality
related to that class so if you want to
validate that a name exists if you want
to validate that a house is correct that
belongs just uh fundamentally in the
class called student itself not in some
random function that you wrote elsewhere
again this is just methodology because
again if we think about writing code
that gets longer and longer more and
more complicated it should make just
intuitive sense that if you keep all the
house and all of the Stu all of the name
and all of the house related code in the
student it's just better organization
right keep all of the related code
together and that's probably going to
set you up for more success and indeed
that's part of this methodology of
objectoriented programming let me go
ahead now and change my students classes
init method to do this if the name is
blank so if not name and we've seen this
kind of syntax before if you say in
Python pythonic if not name that's like
doing something like this if name equals
equals quote unquote but I can do this a
little more elegantly just say if not
name would be the more pythonic way to
do it well I want to return an error
like I might want to do something like
this print missing name but this is not
good enough it does not suffice to just
print out missing name and then let the
rest of the code go through all right
well what could I do instead in the past
we've seen another technique I could do
cy. exit and I could say something like
missing name and I could go up here and
I could import CIS but this is a really
obnoxious solution to the problem just
because you or maybe a colleague messed
up and called a fun with an invalid name
you're going to quit my whole program
like that's really really extreme of a
response and you probably don't want to
do that if your program's in the middle
of running you might want to clean some
stuff up you might want to save files
you don't want to just exit a program
sometimes in some arbitrary line just
because input was invalid so I don't
think we want to do that either but we
do now have a mechanism for signaling
errors unfortunately I can't do
something like this I could try
returning none and say uh this student
does not exist I'm going to hand you
back none instead but it's too late if
we scroll back down to where I'm
creating the student it's on line 17 now
where I've highlighted this code the
student has already been created there
is an object somewhere in the computer's
memory that's structured as a student it
just doesn't have any values inside of
it but it's too late therefore to return
none that ship has sailed the object
exists you can't just suddenly say nope
nope there is no object there is an
object it's up to to you to Signal an
error and how do you signal an error
well we've actually seen this before but
we haven't had occasion to create our
own errors it turns out in Python
there's another keyword related to
exceptions that python itself uses to
raise all of those exceptions we've
talked about in the past when you've
caught things like value errors or other
such exceptions that come with python
well it turns out you the programmer can
raise that is create your own exceptions
when something just really goes wrong
not wrong enough that you want to quit
and exit the whole program but enough
that you need to somehow alert the
programmer that there has been an error
something exceptional in a very bad way
something exceptional has happened and
let them try to catch that exception as
needed so let me go back to vs code here
and propose that if the user passes in
an invalid name it's just empty so
there's not a name well what I really
want to do is this I want to raise a
value error and we've seen the value
errors before we've created value errors
accidentally before and generally you
and I have tried to catch them if they
happen well the flip side of this
feature of exceptions in a language like
python is that you the programmer can
also raise exceptions when something
exceptional happens and you can even be
more precise you don't have to raise a
generic value error and let the
programmer figure out what went wrong
you can treat value error and all
exceptions in Python like functions and
actually pass to them an explanatory
message like quote unquote missing name
so that at least the programmer when
they encounter this error knows oh I
messed up I didn't make sure that the
user has a name and now what do you want
to do instead well now if you're the
programmer you could do something like
this you could try to create a student
except if there's a value error then you
could handle it in some way and I'm
going to wave my hand with a dot dot dot
at how you would handle it but you would
handle it using try and accept just like
we have in the past and that would allow
you the programmer to try to create the
student but if something goes wrong okay
okay I'll handle it nonetheless so
what's new here again is this raise
keyword that just lets you and I
actually raise our own exceptions to
Signal these errors well let me go back
to my code here and I'm just going to go
ahead and not bother trying or catching
this error for now we'll just focus on
raising it and assume that from our week
on exceptions you could add try and
accept as needed in places let me go
back to the code here and propose that
something else could go wrong with house
right if there is a name we're good but
if we're given a house but it's invalid
we should probably raise an exception
for that too so what if we do this if
house is not in the list containing
Gryffindor quote unquote uh Hufflepuff
quote unquote uh let's see Ravenclaw
quote unquote or uh Slytherin quote
unquote then with my colon let's ra
raise another type of value error but
rather than raise a generic value error
let's pass in an argument quote unquote
invalid house and so here we now see a
capability that we can do with classes
that we can't with dictionaries if you
add an attribute to a dictionary a key
to a dictionary it's going in no matter
what even if the name is empty even if
the house is a completely random string
of text that's not one of these four
houses it's going into that dictionary
but with the class and by way of this
init method you and I can now control
exactly what's going to be installed if
you will inside of this object you have
a little more control now over
correctness and so now let me go ahead
and uh scroll back down to my terminal
window and clear it let me run python of
student. let me type in something like
Harry let me type in Gryffindor enter
and we see that indeed Harry is from
Gryffindor what if I made a mistake
though what if I ran python of student.
and typed Harry as the name but at this
time typed in number four Private Drive
which is where he grew up instead of his
proper Hogwarts house let me hit enter
now and now you see a value error but
this isn't one that python generated for
us per se I raised this error and
therefore if I went in and wrote more
code in my get student function I could
also catch this error with our usual try
except syntax so all we have now is not
just classes in our toolkit but even
more Powers when it comes to exceptions
and not just catching them ourselves but
raising them ourselves too any questions
now on this use of class isn't in it and
now this ability to raise exceptions
when something goes wrong inside of the
initialization so what if user has a
middle name name middle name and last
name how would you fix that a good
question if you wanted the user to if
you wanted the student to have a first
name middle name and last name we could
do this in a bunch of different ways the
simplest though if Let Me Clear My
screen here and let me just temporarily
do this let me propose that the init
method take in a first argument a middle
argument and a last argument and then
what I think I would do down here is
ultimately have first equals first and
then I would do the same thing for
middle and last so middle and middle and
then last and last and then what I would
have to do here is when I actually ask
the user for their name I might need to
really go all out I might need to ask
them first for their first name and
store that in a variable called First
and therefore pass in first I might
similarly need to ask them for their
middle name and store that in a variable
and then pass in a second argument
middle and then lastly if you will let
me go ahead and create a third variable
called last get the input for their last
name and pass that in as well I could
instead just use one input and just ask
them for their whole name so type in
David uh ma enter or David J me all
three of them and maybe I could use
Python split function maybe a regular
expression to tease it apart that's
probably going to be messy because
there's going to be people who don't
have just two or three names they might
have four or five so maybe sometimes
it's better to have multiple prompts but
that's not a problem because with a
class we have the expressiveness to take
in more arguments if we want we could
even take a list if we wanted but I
think we'd probably want to have even
more error checking then not just for
name but for first and then maybe for
middle and then maybe for last so it
just is more and more code though there
would be ways to perhaps consolidate
that too let me undo all of that and see
if there are other questions now on
classes I assume this is classes are
something I might do at the beginning of
a project can I just put them in a
different file and import them into my
project or or or my main code as needed
absolutely a really good question you
could imagine wanting to use this
student class not just in studenty but
in other files or other projects of
yours and absolutely you can create your
own library of classes by putting the
student class in your own module or
package per our discussion in the past
about libraries more generally and
absolutely you can do that and later
today will we see that we've actually
been using classes you and I before in
thirdparty library so you too can
absolutely do the same how about one
more question on classes can you have
optional variables in classes and two
can you have your own error names like
let's be egotistic and say I when AR
raise Eric eror short answer yes so you
can uh these init functions are just
like python functions more generally
even though they're special and that
they're going to get called
automatically by python 4 you but if you
wanted to make house optional you could
do something like this you could give it
a default value in the init functions uh
signature so to speak in that first line
of code on line two and that would allow
me to not have to pass in house in this
case I'm going to continue to always
pass in name and house but you could
make things optional and yes to your
second question if you wanted to have
your own error message like an Eric
error you could actually create your own
Eric error exception and we'll see in a
little bit that there's actually a whole
Suite of exceptions that exist and you
too can invent those as well let me
propose though that we now introduce one
other aspect of this whereby we try
printing out what a student looks like
at the moment if I scroll back down to
my main function I'm still printing the
student's name and house very manually
I'm going inside of the object doing
student. name and I'm going inside of
the object again and getting student.
house just to see where uh the student
is from but wouldn't it be nice if I
could just print the student like I've
been printing for weeks any int or float
or stir or any other data type well
let's see what happens if I just try
printing the student instead of manually
going inside and trying to create that
sentence myself well in my terminal
window let me go ahead and run python of
student. py again let me type in Harry
let me type in Gryffindor and we voila
Harry whoa okay main student object at o
x102 733
e80 well what is going on well if you
were to run the same code you might
actually see something different on your
computer in terms of that number but
what you're really seeing is the
underlying representation as a string of
this specific object in particular
you're seeing where in the computer's
memory it is this number o x102 733 e80
refers to essentially a specific
location in the computer's memory or Ram
that's not really that interesting for
me or you or generally speaking
programmers but it's just a default way
of describing via print what this thing
uh is but I can override this as well it
turns out that there are other special
methods in Python when it comes to
classes not just underscore underscore
in it uncore underscore But continuing
in that same pattern underscore uncore
stir underscore underscore so this too
is a special method that if you define
it inside of your class python will just
automatically call this function for you
anytime some other function wants to see
your object as a string print wants to
see your fun your object as a string but
by default if you don't have this method
defined in your class it's going to
print out that very ugly esoteric
Incarnation thereof where it says main.
student object at Ox dot dot dot well
how can I then Define my own stir
function well here back in VSS code let
me propose that I go in and Define not
just underscore underscore uh in it but
let me Define a second function in this
class here as follows def underscore
underscore stir underscore underscore
there are indeed two even though the
font in VSS code is putting the two
underscore so close it just looks like a
longer underscore there are indeed two
there on the left and the right just
like for in it this one only takes one
argument that by convention is always
called self so that you have access to
it and then indented below that after a
colon I'm going to go ahead and create a
format string and return it so let me go
ahead and return how about something
generic first like a student so I'm not
going to bother even trying to figure
out what this Student's name or house is
I'm just going to always return a
student let me go back now to my earlier
code which has print student on line 16
Let Me Clear My terminal window and
rerun python of student upy enter type
in Harry type in Gryffindor last time I
saw that very cryptic output this time I
see more generically a student you know
more readable but not very enlightening
which student is this well notice that
the uh double underscore stur method
takes in this self argument by default
it's just the way the python authors
designed this method it will always be
passed a reference to the current
student object what do I mean by that
when this line of code on line six is
called print because it's hoping it's
going to get a string is going to
trigger the underscore uncore stir
underscore uncore method to be called
and python for you automatically is
going to pass into that method a
reference to the object that's trying to
be printed so that you the programmer
can do something like this here's an F
string with double quotes as usual I'm
going to use some curly braces and say
print out self. name name from self
house so there's nothing new in what
I've just done it's just an F string an
F on the beginning two double quotes a
couple of pairs of curly braces but
because automatically this stir method
gets past self so to speak a reference
to the current object I can go inside of
that object and grab the name I can go
inside that object again and grab the
house so now when I go back to my
terminal window previously it just
printed out a student but but now if I
run python of student. py enter type in
Harry type in Gryffindor and one more
time hit enter Harry is again from
Gryffindor but if I run this yet again
let's for instance do Draco is from
Slytherin enter Draco from Slytherin now
it's customized to the specific object
that we're trying to print questions on
this function here this thunder stir
method
is there anything else that the uncore
uncore stir method can do um the other
question is what's the difference
between stir and repper a good question
so there are many other methods that
come with python classes that start with
underscore underscore we're just
scratching the surface and we'll pretty
much Focus primarily on these but yes
there are many others and we'll see at
least one other in just a little bit
there is an among the others is indeed
one called uh repper which is a
representation of the Python object
generally speaking the _ uncore rcore
uncore method is meant for developers
eyes it typically has more information
than Harry from Gryffindor it would also
say what type of object it is like a
student capital S whereas underscore
uncore stir underscore uncore is
generally meant for users uh the users
of the program and it's meant to be even
more userfriendly but both of those can
be overridden as you see fit well let me
propose now that we pick up where we've
left off on student and just add even
more functionality but not just these
speci methods like double underscore
init and double underscore stir like
let's create our own methods because
there in lies the real power and
flexibility of classes if you and I as
the programmers can invent new
functionality that's specific to
students for instance uh students at
Hogwarts over the time in in school
learn how to cast a certain type of
spell so when they say expecto patronum
something comes out of their wand that
typically resembles an animal or
something like that it's a special spell
that they have to practice and practice
so let's see if if we can't store not
just a student's name and their house
but also their Patronus what actually
they conjure when using this spell well
let me go ahead and clear my terminal
window and in the top of my code here in
the init method of student let me go
ahead and start expecting a third
argument in addition to self which
automatically gets passed in called
petronis and I'm not going to worry uh
for now on validating the petronis from
an official list of valid patronises or
petroni I'm instead going to go ahead
and just blindly assign it to self.
Patronis equals petronis and we're going
to let the user type whatever they want
for now but I could certainly add more
error checking if I wanted to limit the
patronises to a specific list of them
here let me go ahead now and prompt the
user for this petronis as by in my get
student method uh get student function
defining a variable called petronis or
anything else prompting the user for
input for their petronis and now I'm
going to go ahead and pass in that third
variable here so again similar in spirit
to just adding more and more attributes
to the class I'm going to pass in all
three of these values instead of just
two I'm not going to do anything
interesting with that value yet but just
to make sure I haven't made things worse
by breaking my code let me run python of
studenty I'll type in Harry I'll type in
Gryffindor and it turns out his Patronis
was a stag and hit enter I haven't seen
what his Patronus is in my output
because I didn't change my stir method
yet but at least I don't have any syntax
error so at least I've not made anything
worse but suppose now I want to have
functionality not just for initializing
a student and printing out a student if
my class is really meant to be a student
what I can do is not just remember
information about data about students
what's powerful about classes unlike
dictionaries alone is that classes can
have not just variables or instance
variables so to speak those attributes
we keep creating they can also have
functions built in AKA methods when a
function is inside of a class it's
called a method but it's still just a
function at this point we've seen two
functions already two methods called uh
double underscore init and double
underscore stir but those are special
methods in that they just work if you
define them python calls them
automatically for you but what if you
wanted to create more functionality for
a student so that your class really
represents this real world or maybe
fantasy world notion of a student where
students not only have names and houses
and patronises they also have
functionality they have actions they can
perform like casting a charm a spell
magically could we Implement therefore a
function called charm that actually uh
uses uh their magical knowledge well
let's go ahead and Define our very own
function as follows Let Me Clear My
terminal window scroll back up to my
student class and instead of creating
yet another function that's special with
double underscores I'm going to invent
my own function or method inside of this
class I want to give uh Harry and
Hermione and and all of the other
students the ability to cast charms so
I'm going to define a function that I
can completely on my own called charm I
could call this function anything I want
but because it's a method inside of a
class the convention is that it's always
going to take at least one argument
called self by convention so that you
have access to the current object even
if you don't plan to use it per se all
right let me go ahead and propose that
we Implement charm in such a way that
the method returns an emoji that's
appropriate for each student's petronis
all right how to implement this well
inside of the charm method let's go
ahead and match on self. Patronis which
is the instance variable containing a
string that represents each student's
Patronis and in the case that it matches
a stag for instance for Harry let's go
ahead and return maybe the closest Emoji
this horse here how about in the case of
an otter well in that case let's go
ahead and return oh maybe the closest
match to the otter which might be this
Emoji here and let's see in the case of
a for Fon rather than Herm a Jack
Russell Terrier let's go ahead and
return how about don't have as many
options here why don't we go ahead and
return the cutest available dog in that
case and in the case of
no Patronis recognized as might cover
someone like Draco let's go ahead and
use a default case using the underscore
as as in the past and let's go ahead and
return for this oh what should happen if
someone doesn't have a petronis why
don't we just see a magical wand that
seems to fizzle out as in this case all
right well now rather than just print
the student let's go about printing
their actual Patronis so I'm going to go
down to my main function here I'm going
to still get a student using the get
student function but rather than print
student let's go ahead and declare
expecto patronum printing out just that
as pure text and now let's go ahead and
print out not the student but rather the
return value of their own charm Method
All right so let me go back down to my
terminal window and run python of
student. py and enter name let's start
with Harry he lives in Gryffindor uh
petronis is a stag and let's see expecto
patronum and of course we see the Stag
emoji what about someone like Draco who
at least in the books doesn't have a
known petronis well let's go ahead and
clear my terminal window rerun python of
student. and this time let's type in
Draco for name Slytherin for house and
Patronis is unknown so I'm just going to
go ahead and hit enter and now expect o
patronum and just kind of sizzles
instead questions now on what I've done
by implementing this charm method can we
uh like call a method outside the
function absolutely and we're seeing
that already if I scroll back down to my
main function which is outside of the
class because it's all the way down in
the file it's all left align just like
the class notice on line 28 I'm calling
student. charm and I'm accessing a
method that's inside of the student
object even though my main function is
outside of the
class and what's different between our
init function or method and our stir
method that we've seen before those are
called automatically when you try to
create a student or when you try to
print a student for the first time we're
now seeing a method that I invented
inside of the student class that I can
call anywhere I want and if I'm calling
it outside of the class like I am here I
just use the name of the variable
containing that student object and I
just do charm just like I could access
the individual attributes or in instance
variables inside of that object as well
other questions on classes and this new
method charm in a parentheses you are
you put self supposed to be like a
initializer but like in the top part you
didn't you didn't um Define it the same
way would you have to put the class on
why you didn't put the class right there
so notice the indentation here so on
line one I've of course said class
student colon and then everything below
that is indented at the moment that
means that my init method my my stir
method and this new charm method are all
inside of part of that class by
convention then each of these methods
inside of a class should expect that
python will automatically pass in at
least one argument to every method in a
class and that argument will always be a
reference to the current object the
Harry object or the Draco object that is
currently trying to cast a charm or be
printed so whenever you create a method
inside of a class you should always have
it take at least one argument called
self and then zero or more other
arguments that are entirely up to you in
it for instance takes three more name
house Patronis stir takes zero more
charm takes zero more but the convention
is to always call that default argument
self and python just automatically gives
you access to the current
object other questions how about one
more on classes and charms sir I just
wanted to ask that uh you you have put
the emojis in double quotes So does it
take the Emojis as a form of strings or
something else yes if unfamiliar an
emoji is just a character it's part of a
mapping of numbers to letters known as
Unicode and so whenever you see these
emoji on the screen like the horse or
the otter or the dog here specifically
that's really just like a key from your
keyboard you and I on Max and PCs can't
typically type it because you see
English characters or some other human
language but Emoji are increasingly
available uh via menus and drop down and
in my case copy paste on Macs and PCs
and Android devices and iPhones they are
just characters even though they look
like pictures you can think of it like a
graphical font almost so they're just
text and indeed if you put them between
double quotes or single quotes you can
print Emoji just like you can any other
human character as well well let me
propose now that we remove this Patronis
code just to simplify our world and
focus on some of the other core
capabilities of classes so at the risk
of disappointing I'm going to get rid of
all of these beautiful emoji and charms
and I'm going to go ahead and stop
asking the user now for their petronis
and I'm going to stop passing it into in
it here and I'm going to stop uh doing
this here and I'm going to instead just
go ahead and restore our use of print
student here and I'm going to go ahead
and get rid of petronis down here so
essentially undo all of the fun charm we
just created so we're now back at the
point in the story where we have a
student class with only two methods in
it and stir the first of those takes of
course self as the first argument as it
always will plus two more now name and
house no more Patronis we're validating
name up here we're validating house down
here and then we're assigning name and
house respectively to two instance
variables called name and house also but
we used self to get access to the
current object to store store those
values therein we then still have our
stir method here which takes one
argument by default self and that's it
and that function is going to be called
automatically anytime you want to
convert a student object to a string
just like print might want to do here so
let me go ahead and just make sure I
haven't broken anything let me run
python of studenty I'll type in Harry
I'll type in Gryffindor enter okay we're
back in business gone are the charms and
patronises but at least I'm back to a
situation where I have names and houses
but it turns out at the moment our use
of classes is not very robust even
though we have this mechanism very
cleverly if I may in our init method of
making sure that we're validating name
and house making sure that name is not
blank and making sure that house is a
valid house among those four Hogwarts
houses it turns out that classes will
still let me get at those attributes
those so-called instance variables using
notation anyway let me scroll down then
and try to do this a little
adversarially suppose that on line 16 I
go ahead and call get student which
exists as before and then I store the
return value in a student variable again
on line 16 that will ensure that get
student gets called which calls input
and input and then it calls the student
Constructor which invokes automatically
this init method so by way of how we've
laid out my code we're going to ensure
that name is not blank and house is
definitely one of those four values my
error correction or error checking is in
place but if I'm a little adversarial I
can still circumvent it suppose that
fine I'm G to you're going to require me
to type in Harry and griffindor I'm
going to go ahead and type in student.h
house equals quote unquote number four
private drive and you're not going to be
able to stop me why well it turns out
with classes and objects thereof you and
I can still access those instance
variables using this familiar dot
notation that's how we began the story
of classes just setting these attributes
ourselves but you can also read these
attributes themselves and change them
later if you want and this will
effectively circumvent the if condition
and the other if condition in our init
method because that is only called when
you first create the student object
there's nothing stopping me at the
moment from just changing the house or
the name after so if I now now clear my
terminal window and run python of
studenty I'll still type in Harry and
Gryffindor to meet my requirements that
the house be one of those four but when
it's printed notice I've still
overridden it so it seems that while
classes do allow us a little more
control over the data we're storing it
doesn't necessarily prevent the user be
it or rather the programmer be it myself
or maybe a colleague from still kind of
messing things up so here too in the
spirit of programming a little more
defensively allow me to introduce
another feature of python as well namely
properties so a property is really just
an attribute that has even more defense
mechanisms put into place a little more
functionality implemented by you to
prevent programmers like me and you from
messing things up like these attributes
so again a property is going to be an
attribute that you and I just have more
control over how we just write a little
more code using some python conventions
and how we're going to do that is going
to use in just a moment a feature a
keyword known as app property which is
technically a function property is a
function in Python but we're about to
see some new at syntax that allows you
to decorate functions and this to is a
term of Art in the world of python you
can have decorators which are functions
that modify the behavior of other
functions if you will and we'll leave it
at that without going too much into the
weeds and we'll see by example how you
can use these decor Ator specifically to
define properties so let me go back to
vs code here and let me propose that I
do this I'm going to go ahead and create
how about a property called house as
follows inside of my uh student class
I'm going to go ahead and below my init
method and below my stir method I'm
going to go ahead and Define a function
called house that takes as it always
must one argument at least called self
and what I'm going to do now is return
uh self. house so I'm just going to
define a method called House whose sole
purpose in life is to return the value
of house but I'm going to Define one
other method curiously also called house
but that's going to take into as
arguments two values self as always and
also a value called house and I'm going
to now do this uh I'm going to say self
rather I'm going to do self. house
equals house now what have I done well
let me just temporarily add some
comments here in a moment we're going to
start referring to this generally as a
getter and down here I'm going to refer
to this as a Setter and this is
terminology you frequently see in the
world of java if some of you have
programmed in Java before but as the
names imply a getter is a function for a
class that gets some attribute a Setter
is a function in some class that sets
some value and now even though we're not
done and there's a bit of a mistake in
the code I've already written
intuitively what we're going to do is
this we're trying to prevent programmers
myself included from circumventing my
error checking that I put into place for
name and house how can I do that well we
don't have that many building blocks in
programming we have things like
variables for data and we have functions
for actions well why don't we do this
why don't we somehow require that in
order to access an attribute you go
through some function and let's require
that in order to set some attribute you
go through some function and
conventionally those functions are
called a getter function and a Setter
function and why are we using functions
or in this case methods inside of a
class well once you have functions those
are just actions or verbs that you and I
can create ourselves we can put any
error correction I want in these
functions because it's code that's going
to get executed top to bottom so so how
can I now prevent the user from setting
the house to an invalid value let me
borrow some logic from before rather
than blindly do this just set self.
house equal to the house value that's
passed in let's add our eror checking
there so if house is not in the
following list of Gryffindor or
Hufflepuff or slyther or Ravenclaw or
slythering in just as before let's go
ahead and raise a value error just to
signify that uh-uh something has gone
wrong I'll be more explicit I'll include
a message like invalid house quote
unquote otherwise I'm going to proceed
on now line 21 to set self. houseo house
so I've just copied if you will or
retyped my error checking inside of this
so-called Setter function now why have I
done that well to be clear whenever the
user or the programmer writes code like
this
student. housee equals what's about to
happen magically is python will not just
let the programmer access student.h
housee directly that attribute that
instance variable AKA self. house it's
instead going to magically automatically
call this Setter function for me how
does python no to do that well if it
sees that on the leftand side there is
self. housee where house is the name of
the getter or Setter and then it sees an
equal sign indicating assignment that's
just enough of a visual clue to say wait
a minute I'm not going to let you access
that attribute directly I'm going to use
the setter instead why because the equal
sign means I'm trying to set I'm trying
to assign a value from right to left
into that attribute so what Python's
going to do automatically is call this
function for me and that's amazing
because now I can execute code an
algorithm to check do I want to let the
user the programmer set that attribute
to that value if not I'm going to raise
a value error and you're just not going
to be able to do it if so fine I'll go
ahead and set it for you but in order to
do this we need a little more syntax and
I'm going to get rid of my comment and
I'm going to use that decorator I need
to tell python to treat this method as a
getter and then the Syntax for the
setter is a little different you now say
house. Setter I wish one was getter and
the other was Setter that's not the way
they designed it when you want to define
a getter you just say at property above
the function and you name the function
exactly like you would like the property
to be called quote unquote house once
you do that you can now use a new
decorator that sort of automatically
created for you called at house because
I called it house and then you literally
say at house. Setter and this whole line
on line 17 is a clue to python that here
comes a function whose name is identical
but notice that it takes two arguments
both self so you have access to the
contents of the object and house which
is just going to be a stir that comes
from the programmer from like the human
input return value so that you can set
that value as well but there's one fix I
need to make now here everything else I
think is still good however watch this I
no longer need this error check here why
because if I scroll back down to my code
here I claimed a moment ago that code
like this with uh student.h house equals
is going to automatically get python to
call my Setter for me guess what even up
here in my init method calling self.
housee equals is also going to call my
Setter method which is amazing because
now I can keep all of my error checking
in one place in the setter and it will
now get called either E when I create
the object for the first time because of
in it or even if the you the programmer
tries to circumvent that init method and
change the value of this attribute my
Setter will also get called my Setter
will get called anytime I access do
house but there's one fix I need to make
unfortunately I have collided names
right now if we go up here on line five
this is an instance variable it's a
string inside of myself inside of the
current student object called name and
this is another instance variable called
House unfortunately if I have an
instance variable called name and house
I cannot also have functions called
house they're going to collide you got
to decide do you want the variable to be
called house or do you want the function
to be called House unfortunately you
can't have both because now Python's
going to confuse one for the other so
the conventional fix for this is to do
this to have the setter not store the
value that's passed in in self. house
but to use an almost identical name but
to use a little indicator that you means
you know you're doing this correctly you
typically by convention put an
underscore in front of the instance
variable's name and when you return it
up here you similarly put an underscore
so now technically my instance variable
is called underscore house but my
property
which is a fancier attribute if you will
is called house alone huge amount of
syntax I know but it's a very powerful
feature and again this is why you can
graduate from dictionaries alone and
have so much more functionality at your
disposal let me go ahead and clear my
terminal window and run python of
student. enter name all right let's go
ahead and type in Harry let's go ahead
and type in Gryffindor crossing my
fingers as always and now look inval
house this is a good thing why because
notice in my main function I'm still
trying maliciously if you will to change
Harry's house to not be one of the four
valid ones I'm trying to change it to
his childhood home of number four
private drive but because python knows
that wait a minute you're trying to
assign that is set a value and that
value AKA house is now defined as a
property you're going to have to go
through the setter function instead to
even let you change that value and
because I have this raise value error if
the house is not as intended you're not
going to be allowed to change it to an
invalid value so I'm protecting the data
on the way in through the init method
and I'm even defending the data if you
try to override it there so I think the
only solution for me the programmer is
don't try to break my own code let me
remove that line because it's just not
going to work let me run python of
studenty and again type in Harry type in
Gryffindor enter and Harry is indeed
from Gryffindor if I did something
incorrect like Harry from number four
Private Drive enter we're again going to
see the value error because my code just
doesn't let that value in Via manual
input now or via that adversarial change
all right that was a lot but any
question on
properties uh while we are using gets
and Setters it's just for the purpose so
that we can find that um that fun that
method that function in in our code the
reason that I'm going through the
trouble of defining this getter or
Setter is because I want to make sure
that programmers cannot do things like
this if I'm going through the trouble of
validating the attributes for these
student objects I don't want you to be
able to go in there and just change them
at will I want to have some control over
that object so that you can just trust
that it's going to be correct as
designed so using a getter and Setter
really just enables python to
automatically detect when you're trying
to manually set a value the equal sign
and the dot as I've highlighted here is
enough of a clue to python to realize
wait a minute you're trying to set a
value let me see if this class has a
Setter defined and if so I'm going to
call that and I'm not just going to
blindly assign the value from right to
left so it's just giving me more control
other questions on properties when we
use a gets we just have just one
argument and if we use Setters is always
going to be two arguments is that normal
correct it's always going to be one
argument self for the getter two
arguments for the setter self and
something else and the intuition for
that is if you're getting a value you
don't need to pass anything else in
because you already know the object it's
called student in this case so you're
just going to get the value of that
property but if you want to set the
property to something else you got to
pass in that argument you've got to pass
in the value to which you want to set it
so it's always zero or one however you
see it as one or two because again any
function inside of a class AKA a method
is going to be automatically passed self
so that you have access to that current
object in memory how about one other
question on properties why didn't we use
the same underscore house in init meod a
good question so even though I'm using
the underscore house here in my Setter
and the underscore house here in my
getter I deliberately did not use it up
here the reason for that is that by
using self. house and this equal sign
that's the same pattern that I want
python to recognize I want python to
automatically call the setter even when
I'm passing in the house via the init
method if I were to change this to do
this that would circumvent the setter
and now there's no error checking in in
it whatsoever so it's such a fine line
the only thing standing between us and
error checking or no error checking is
the presence or absence of this
underscore but that's typically the
convention by not using the underscore
there make sure that even that
assignment goes through the setter so
that honestly I don't have to copy paste
the same error checking in two places I
can put it just in the setter so it's
better design and that's why I manually
retyped it at first but then I deleted
it from in it well allow me to propose
that we make one other change to this
file might as well go ahead and Define a
property for name as well and let me go
ahead and do this maybe above the house
property just to keep things uh in the
same order as I defined them earlier let
me give myself another property this
one's going to be called name it's going
to take one argument called self as
always and this one very similarly is
just going to return self. uncore name
so I'm going to anticipate that I'm
going to have to rename name also so
that I don't have that same Collision as
before but now let me go ahead and
Define another uh setter this one for
name so the convention is at name.
Setter why name because the property I
just created is called name so the
getter and Setter sort of work in
conjunction in that in this way if you
will let me go down under ATN name
Setter and Define another function also
called name but the key thing here is
that it's not identical it's not the
exact same function name and the exact
same number of arguments the setter
again takes a second argument and I can
call it anything I want but I'm going to
call it name because that's what's being
passed in and I'm going to air put my
error checking here if not name just
like we used to do let's go ahead and
raise a value error and let's put an
explanatory message like uh Missing name
quote unquote otherwise let's go ahead
and update self. uncore name to equal
name and I don't have to change in it
except to get rid of this duplicate
error checking now because again if I
use self. name equals here and self.
house equals here with no underscore for
both of those assignments are going to
go through my two Setter functions now
before we run this let me go ahead and
remove this adversarial code which we
know won't work because we're catching
it let me go back down to my terminal
window and run python of studenty enter
let's type in Harry let's type in
Gryffindor and that seems to work let's
try though again to run python of
studenty with Harry from number four
privet drive this will not work a value
error with invalid house because that's
not one of the four WS houses and now
for good measure let's run it one more
time and let's not even give it a name
let's just hit enter when prompted I can
type anything for the house I'll go
ahead and still give it Gryffindor enter
now we get another value error but this
one is for missing name so we seem now
to have all the more of a defense
mechanism in place to ensure that name
is as we expect it's got to have some
value that's not blank and house is as
we expect it's got to have one of those
four values but at the risk of bursting
everyone's bubble and making you wonder
why did we just go through all of that
unfortunately python really focuses on
conventions not hard constraints and by
that I mean this if I go back into my
main function after I've gotten a
student online 30 and I try to
adversarially do something like this
student. housee equals quote unquote
number four Private Drive we know this
won't work because my Setter for house
is going to catch this watch again again
python of
studenty uh let's type in Harry let's
type in Gryffindor which will at least
pass our check that's induced by in it
but line 31 is going to trigger the same
Setter to be called and we're going to
raise a value error saying invalid house
unfortunately and if some of you are
already thinking a little adversarially
tragically look what you can do you can
change house to beore house why well the
instance variable is now called
underscore house the property is called
house no underscore but the underlying
attribute implemented as an instance
variable is still called underscore
house and tragically python of student.
let's type in Harry let's type in
Gryffindor which is correct but Watch
What Happens now oh my God we slip
through so what was the point of all of
this emphasis from me on doing things
the right way the python iic Way by
having this getter and Setter well
unlike languages like Java that just
prevent you from doing things like this
python itself allows you to specify that
certain instance variables can be public
and accessible to anyone's code or
protected or private which means that no
one else should be able to change these
values in the world of python it's just
the honor System it's not baked into the
language itself that there's a notion of
visibility public or private or even
somewhere in between protected instead
you're on the honor system and the
convention generally is if a instance
variable starts with an underscore
please don't touch it like just don't
like that's on you if you touch that
variable and break things the underscore
is meant to signify a convention that
this is meant to be private but it
really just means please don't touch
this sometimes if there's two
underscores which you can use two that's
an even greater effort by programmers to
say really don't touch this but
technically speaking there's nothing
stopping you or me from circumventing
all of these mechanis Ms these
properties these Getters and Setters
were ultimately just on the honor System
not to do so when we see instance
variables prefixed with one or perhaps
even two underscores all right so this
is a lot all at once this introduction
to object-oriented programming but it
might come as quite a surprise that even
though we might had have identified oop
by name in weeks past we've all been
using classes and objects for weeks now
in this class in fact if you think back
on one of the very first things we did
in this class we used integers and just
got integers from the user but if you
haven't already if you go and dig into
the documentation for integers which
again lives at this URL here you would
actually find that int itself is and has
been for weeks a class and in fact this
is the signature of the Constructor call
for an INT whereby you pass in X like a
number quote unquote 50 or quote unquote
something else you pass in optionally
the base 10 for decimal two for binary
or anything else and that int function
will actually return to you all this
time an object of type int that is to
say int is a class it is a template a
blueprint for creating integers in
memory and anytime you and I have
converted a string for instance to an
INT you and I have been creating an
object of type int that was calling
apparently the underscore underscore in
it underscore underscore method that
someone else the authors of python wrote
to give us back that proper integer
besides that if you can believe it stirs
strings in Python have been classes
since the first week of this class as
well if you look up the documentation
for a stir which lives at a similar URL
there you will find that when you
instantiate that is create a stir it
takes optionally a parameter called
object here the default value of which
is just quote unquote which allows you
to create in effect an empty string a
blank string string if you will but
anytime you and I have created stirs or
even used explicitly this stir function
you are getting back an object of type
stir anytime you and I have forced a
string to lowercase per the
documentation using syntax like this you
and I have been taking an object of type
stir and forcing it all to lowercase by
calling a method called Lower a method
that the authors of python built into
the stir class but it's been there from
the gecko so this notion of method is
not even new today you would have been
doing it for this long if you've ever
called strip to remove the leading and
the trailing Whit space from a string in
Python you are calling another method
that came with python written by the
authors of python and even though we
didn't call it a class at the time a
stir all this time has been a class and
instances of strings are themselves
objects and those objects come therefore
with these functions built in AKA
methods that allow us to do things like
force to lowercase and strip Whit space
from the beginning and end let's do
another list anytime you've created a
list either uh either syntactically with
square brackets or literally with l i s
open parenthesis closed parenthesis
which is also possible you have been
using a class if you go to the
documentation for list at this similar
URL here or more specifically the
tutorial on lists here in Python you
will see that a list is and has been
since the early weeks of this class A
Class itself and that clist class takes
as part of its uh initialization in
optional iterable something that can be
iterated over like one comma 2 comma
three or some list of values and you can
then get back a list containing those
same iterable values if you've ever
appended something to a list in this
class as I have myself in the past
you've been using a method called aend
that comes with the list class that per
the X takes an argument that allows you
to append something to the current list
AKA self in the context of that method
we can do this all day long if you've
used a dictionary or a dict in Python
I've actually all this time been calling
them dict objects and that's for a
reason dict itself is a class in Python
if you pull up its official
documentation here and you'll see that
it is defined indeed as itself a class
and that class comes with methods as
well and so anytime we've manipulated
dictionaries we've been in underneath
the hood using all of those same methods
and in fact we can see this if we're
really curious let me go back over here
to VSS code and let me go ahead and
create a new file that very simply does
something like play around with data
types and let me go ahead and create a
new file for instance called say uh
type. piy just so that I can poke around
inside of some values and in type. pi
I'm just going to go ahead and do this
I'm going to print out whatever the type
is of say the number 50 and this is a
function you've not necessarily seen me
use already and it's not one you would
frequently use in your own code there
are other ways to te detect if you need
to what the type is of a variable but in
this case type of 50 is just going to
tell me and then print out what the data
type is of that value now hopefully all
of us could guess that 50 is indeed
going to be an integer that is an INT
but we can see it in this way and this
too is what's powerful about knowing a
bit of programming if you want to know
the answer to a question just try it out
like am here so let me go ahead and run
python of type. py enter and there it is
when you print out the type of the
number 50 you'll see on the screen in
this cryptic syntax class quote unquote
int this is not something that you
probably want to show to the user but if
you yourself just want to poke around
and see what's going on or maybe use
that information somehow it's certainly
at your disposal to use with this type
function for that let's change it around
a little bit instead of passing is the
argument to type 50 as an INT let's type
something also familiar like hello comma
World in double or single quotes let me
go back to my terminal window clear the
screen and run python of typey again and
now voila there it is all this time a
stir is also a class we can do this a
few more times for instance let's go
ahead and change hello world to just an
empty list open square bracket close
square bracket and this is starting to
look a little cryptic but again notice
what I'm doing in square brackets is an
empty list we've done that before that
is the sole argument to this new type
function and that's just being passed to
the print function so that the return
value of type is the argument to print
so if I now run this code python of
type. piy there it is a list is a class
two you might recall that I said that
you can also create an empty list by
literally doing list open parenthesis
close parenthesis this is a bit of an
inconsistency as we can now identify
that int and stir and Now list they're
technically all lowercase and I went to
Great Lengths of creating my student
class to have that capital S that's a
convention because int and stir and list
and others come with python they decided
to make their built-in data types even
though their classes all lowercase but
the convention the recommendation in the
python Community when creating your
classes is indeed to capitalize the
first letter as I did in something like
student capital S but list open
parenthesis closed parenthesis is
identical to really just two empty
square brackets if I clear my screen and
run type dopy again you see the exact
same thing the class is called list
let's do one more let me change list to
be not square brackets but curly braces
we've done this before anytime I've done
two curly braces with nothing in between
this of course is an empty dictionary or
a dict object in Python well we can see
that now let me clear my screen run
python of type. enter and there it is
class dick it's been there this whole
time we just didn't call it a class
until today I can similarly do this one
explicitly instead of two curly braces
let's write out dict with two
parentheses now we have a lot of
parentheses again like with list but
this is just making even more clear that
the type of a dict object is indeed the
class dict itself so this is to say that
as new as a lot of today's ID and syntax
might be you've actually been using it
perhaps unbeknownst to you for weeks now
we now just have terminology to describe
what it is we've been doing all this
time and you now have the expressiveness
with some practice to create your own
classes inside of which are your own
instance variables perhaps wrapped with
those properties and your own instance
methods but it turns out there's other
types of methods in the world thus far
I've been deliberate in calling all of
our variables instance variables and all
of our methods uh instance methods it
turns out there's other types of
variables and methods out there and one
of those is called class methods it
turns out that sometimes it's not really
necessary or sensible to associate a
function with objects of a class but
rather with the class itself an instance
or an object of a class is a very
specific Incarnation thereof again on
that neighborhood that has a lot of
identical looking buildings but they're
all a little bit different because of
different paint and such sometimes times
you might have functionality related to
each of those houses that isn't distinct
or unique for any of the houses it's
functionality that's going to be exactly
the same no matter the house in question
same in the world of object-oriented
programming sometimes you want some
functionality some action to be
associated with the class itself no
matter what the specific objects own
values or instance variables are and for
that we have a keyword called at class
method this is another de cator really
another function that you can use to
specify that this method is not by
default implicitly an instance method
that has access to self the object
itself this is a class method that's not
going to have access to self but it does
know what class it's inside so what do I
mean by this well let me go back to VSS
code here and let me propose that we
create a new file this time implementing
the notion of a the Sorting Hat from the
World of Harry Potter as well to stay on
theme I'm going to go ahead and run code
of hat. py and in hat. py let's
implement the notion of this Sorting Hat
if unfamiliar in the books and in the
films there is literally a pointy hat
that when a student put it on their head
that Sorting Hat so to speak decides
what house the student is in whether
it's Gryffindor or something else so
let's Implement and code this notion of
a Sorting Hat such that when we pass to
the Sorting Hat the name of a student
like quote unquote Harry this Sorting
Hat implemented in code will tell us
what what house that student should be
in all right well let's go ahead and do
this in hat. py first let's go ahead and
define a class called hat and then let's
get back to implementing it itself and I
find this to be a helpful technique not
just with teaching but when writing code
like I know I want a ha class I don't
necessarily know what I want it to do
yet so I'm going to create this sort of
placeholder dot dot dot so I'll come
back to that let's now try to use this
class as though it existed and from
there I perhaps can realize exactly what
functionality that class needs to have
to support my use case let me go ahead
and create a variable called hat in all
lowercase and instantiate a hat object
so no matter what the Hat class ends up
looking like this is the common Syntax
for instantiating an object of a certain
class in the past we saw student all
lowercase equals Capital student open
parenthesis closed parenthesis and then
eventually we added in things like name
and house for now let's assume that the
hat is much simpler than a student and
it only has sorting capabilities so I'm
not going to even pass any arguments
there too indeed let me assume that the
Sorting Hat has one Function One method
inside of it called sort and so if I do
hat. sort quote unquote Harry let's
propose that that prints out what house
that student should be in so that's it
I'm going to encapsulate that is tuck
away inside of a hat class all of this
requisite functionality and I'm going to
print out on the screen what hat uh what
house Harry belongs in all right now I
think I need to get into the weeds of
actually
initializing this class well let me go
ahead and do this if I don't care to
parameterize hat I just want to for
instance uh sort values let's go ahead
and Define this function sort first so
let's define sort as taking a first
argument self which is always going to
be the case when defining an instance
method as before but the sort method
clearly takes one argument from the
programmer me namely the student's name
and again we've seen this dichotomy
before even though I'm trying to pass in
one argument when I Define the method
it's got to take that many arguments
plus one more self which is always going
to be automatically passed in by python
first all right what do I want to do
well let's go ahead and do something
like this uh print quote unquote or
rather print this name how about quote
unquote is in quote unquote some house
I'm going to again use some placeholder
code for myself because I'm not quite
sure how to finish implementing this
Sorting Hat but I think that's enough to
just test where my code is at now let me
go ahead and run python of hat. py and
hit enter and it looks like indeed Harry
is in some house we're not done yet
because it's clearly not doing anything
interesting but it at least is running
correctly with no errors well let's go
ahead now and decide where uh what house
Harry should actually be in by
introducing a bit of Randomness and
choosing a house randomly well I can do
this in a few ways let me go ahead and
do this I need to have a list of houses
somewhere so where can I put that I
could solve this problem in different
ways let me propose that I do this let
me Define a method called in it as I've
done before that takes in self but no
other arguments and whenever the Sorting
Hat is instantiated let's do this let's
create a houses instant variable plural
that equals this list Gryffindor comma
Hufflepuff comma uh Ravenclaw comma
Slytherin so the exact same list that
we've used before and I'm storing it in
an instance variable inside of this
class I'm not taking any arguments
Beyond self in it but I just need this
list of values somewhere for instance so
what can I do here well let me go ahead
and replace some house with the actual
house well what could I do here well I
want to put a house there well let's go
ahead and create a variable called house
and if you think back to our discussion
of libraries in the random module there
is a function called choice that if you
pass in a list of choices like self.
houses that will pick a random house out
of those four and then on line seven I
can pass it in if I want to tighten this
up let me just go ahead and highlight
that code get rid of the variable is
technically unnecessary and because the
line of code is still pretty short I'm
okay with just putting it all in one
line but I could certainly use the
variable like I did a moment ago so what
have I done in my init function I have
defined a initialization of the object
that stores and self. houses the list of
four houses and then in sort I'm
accessing that same list but I'm
randomly choosing the set of houses
there now why have I done it in this way
this to is General convention anytime
you have a list of things that who knows
maybe we'll change over time places like
Harvard have constructed new houses over
the years so you might have to change
the list of available houses it didn't
happen in seven books or eight films of
Harry Potter but you could imagine maybe
Hogwarts eventually has a fifth house so
there's generally some value in putting
list of constants toward the top of your
file toward the top of the class so it's
just obvious what the list of values is
you don't want to necessarily tuck it
away in some function like sort
especially if you might want to use that
function in sorry if especially if you
want to use that list in multiple
functions not just sort but if I kept
adding to this class you might want to
use that same list of houses in multiple
functions so let's keep it in the object
Itself by storing it in self. houses all
right well we're about to change the
course of history here perhaps let me do
python of hat. and I think we're about
to assign Harry to one of those four
houses
randomly huh name error name random is
not defined well wait a minute where did
did I go wrong here thinking back to our
class on libraries why did my code break
and not tell me where Harry is to be you
do not import the random Library exactly
if the random library or module is
something I want to use I need to tell
python that at the top of my file so let
me go up here and do import uh random
and then below that let me go ahead and
clear my terminal window and try again
python of haty crossing my fingers
seeing where hair is going to end up and
okay Harry as of now is officially in
Hufflepuff despite what everything
you've read or seen well let's run this
again let me clear my window and run
python of hatai and now he's in
Ravenclaw that's consistent with using
random let's clear that and run it again
he's still in Ravenclaw but that could
happen even though there's four choices
let's do it again Hufflepuff back in
Hufflepuff we can't seem to get the
right answer so to speak now he's in
Gryffindor albeit randomly so we seem to
have a program that based on these
Limited Test seems to indeed be
assigning Harry to a house randomly now
I'm somewhat lazily just letting sort
print out this value I could do
something else like return a string and
then let me on line 13 do the printing
for me but for now I think we have an
example of a class called hat that
nonetheless applies some of our lessons
learned thus far today where I've
created a class because a Sorting Hat is
frankly well a I was about to say real
world entity but really A Fant FY World
entity and indeed that's a perhaps
common puristic or mental model to have
when should you use a class to represent
something in your code very often when
you're trying to represent some real
world entity or fantasy world entity
like a student which is something in the
real world like a Sorting Hat which okay
doesn't exist but hats certainly do so
quite reasonable to have a class for hat
and that's not always the case that
classes represent real world entities
but indeed we've seen thus far that int
and stir and list and dict these are all
structures that you might have in the
real world we have integers and strings
of text and other things so it rather
makes sense to represent even those
things more technically using a class as
well you could use just a dictionary to
represent a student or a hat but again
with classes come all this and even more
functionality but I honestly am not
using classes in really the the right
way here here why well in the World of
Harry Potter there really is only to my
knowledge one Sorting Hat and yet here I
have gone and implemented a class called
hat and again a class is like a
blueprint a template a mold that allows
you to create one or more objects
thereof now most of my programs thus far
have been pretty simple and I've just
created one student but certainly if I
spent more time in wrote more code you
could imagine writing one program that
has a list of students many more
students than than just the one we keep
demonstrating yet it would be a little
weird it's a little inconsistent with
the real or the Fantasy World of Harry
Potter to instantiate one two three or
more sorting hats there really is just
one really one Singleton if you will
which is a term of Art in a lot of
contexts of programming so let me
propose that we actually improve the
design of the Sorting Hat so that we
don't have to instantiate a Sorting Hat
because right now this is kind of
allowing me to do something like hat one
equals hat hat two equals hat hat three
equals and so forth I don't really need
that capability I really just need to
represent the Sorting Hat with a class
but I don't really need to instantiate
it why because it already exists I need
just one so it turns out in Python that
up until now we've been using as I keep
calling them instance methods writing
functions inside of classes that are
automatically p a reference to self the
current object but sometimes you just
don't need that sometimes it suffices to
just know what the classes and assume
that there might not even be any objects
of that class so in this sense you can
use a class really as a container for
data Andor functionality that is just
somehow conceptually related things
related to a sorting hats and there's
this other decorator or function called
class method that allows us to do just
this so let me go back to my code here
and let me propose that if I'm not going
to instantiate multiple houses I don't
really need this this in it method
because that's really meant to
initialize specific objects from that
blueprint that template that mold so let
me get rid of this but if I get rid of
this I no longer have access to self but
that's okay because it turns out in
addition to their existing class methods
there are also what we might call class
variables and class variables exist
within the class itself and there's just
one copy of that variable for all of the
objects thereof they all share if you
will the same variable be it an INT or
stir or in this case a list so what I've
done here is Define inside of my hat
class in a class variable called houses
I don't say self because self is no
longer relevant self refers to specific
objects I want a variable inside of this
class AKA a class variable that equals
that list because it's inside of this
hat now class I can use that list in any
of my functions I've only got one now
called sort but if I had more it would
be accessible to all of those methods as
well and with sort it also doesn't
really make sense to sort within a
specific sorting ha because again there
I only want there to be one so I can
actually specify that this is a class
method by saying at class method and I
don't pass in self anymore I actually by
convention pass in the a reference to
the class itself it's typically written
as CLS y well if you wrote C ass that
would actually conflict with the keyword
class that we keep using up here so the
world realized that oops we uh can't
reuse that same phrase here so let's
just call this class this is useful in
some context including this one why well
we notice what I can now do I can now
change self to be just class why because
house is now not an instance variable
accessible via self. houses it is now a
class variable accessible via class
ouses or technically CLS do houses in
this case but now the final flourish is
this now I don't have to instantiate any
hat objects as I used to on here line 13
I can just use functionality that comes
with this class so I'm going to delete
that line Al together I'm going to
capitalize the Hat on this new line 13
and just say hat. sort quote unquote
Harry so what have I done I've not
bothered in intiating an object of type
hat I am just accessing a class method
inside of the Hat class that you know
what is just going to work this is how
class methods work you use the name of
the class capital letter in all do
method name passing in any arguments you
want python is going to automatically
pass in some variable via which you can
refer to that class in that function
that you've implemented inside of that
class so that I can do something like
this it's not that I want a variable
called houses locally in this function I
want the variable called houses that's
associated with this current class so I
can still access this same list that I
defined on line six and now if I go back
down here to my terminal and run python
of haty enter Harry is still in
Hufflepuff once more Harry is still in
Hufflepuff once more Harry is back in
Gryffindor at least
randomly questions now on these class
variables or these class methods which
are in contrast with instance variables
and instance methods and the one thing
at least that's a little strange here is
that even though there's a decorator
called at class method there is not one
called at instance method a method is
just automatically a so-called instant
method when you define it without any
decorator can you have a class inside
another class you can you can Define one
class inside of another generally
speaking this isn't done but there are
cases where it can be helpful especially
for larger more sophisticated programs
so yes it is possible good other
questions the question was about the
self do houses when you when we remove
it we uh and we pass data the variable
is created itself why we remove the S so
in the previous examples both of the Hat
demonstration and also all of the
student demonstrations we were uh create
creating a student object by calling
student capital S open parenthesis
closed parenthesis with eventually name
and a house passed in and then we were
using the d uh the Double underscore
init method to initialize the self. name
and the self. house instance variables
therein to those respective values in
this latest version of the Sorting Hat I
haven't bothered with self anywhere only
because conceptually I don't need or
want there to be multiple hats in the
world I'm just using the class is kind
of a container to bundle up this list of
houses this sorting functionality maybe
eventually I'll add more functionality
to it but that's it and so sometimes you
can use objectoriented programming in
this somewhat different way when you
want there to be functionality but it's
not specific to any one specific hat
it's specific to the Sorting Hat
itself how about one other question now
on these class variables or methods just
another way of using objectoriented
programming but to solve somewhat
different problem well what's the
difference between the class head and I
know like a function of hat a good
question so why are we using a class at
all and not just having a file called
hat. py with a variable called houses
and a function called sort like why are
we adding this complexity in this
particular case we don't necessarily
need to I could absolutely go in here I
could get rid of the class I could uh
undo this indentation I could could get
rid of this decorator and I could get
rid of hat Dot and I could just do this
and additionally let's see let's get rid
of class here let's get rid of class
Here and Now run python of haty enter
and it still works put Harry in the
wrong house but that's what we have what
happens randomly that's fine too what
we're introducing today by way of
object-oriented programming is just a
different way of modeling the world it's
not really compelling with an example
like this frankly that's relatively
simple it's not very complex there's not
much functionality honestly the version
that we just typed up these 10 lines
this is fine this solves this problem
but as our code gets longer as we start
collaborating with other people as the
problems we're trying to solve with code
get more sophisticated you're going to
find that your code gets messy quickly
and you're going to find that you have a
huge number of functions for instance in
one file and some of them are related to
each other but some of them are not well
at that point wouldn't it be nice to
just organize them a little differently
and in the World of Harry Potter let's
have a class for student let's have a
class for Professor let's have a class
for the Sorting Hat let's have a class
for something else and so once your
world gets much more complicated than
some of the demonstrations we do here in
class when we want to focus on
individual ideas object-oriented
programming is just a way of
encapsulating related data that is
variables related functionality that is
methods inside of things that have names
these things are called classes so it's
just another way to solve problems and
when we focused on libraries a couple of
weeks back back that too was another
solution to the same problem you could
Define your own modules or packages put
some of your data Endor functionality in
there and that's fine too and sometimes
which one you should use overlaps if
you're familiar with vend diagrams the
overlapping region might mean that you
could use a class you could use a module
or a package you could just use a single
local file over time you'll develop an
instinct and maybe even a personal
preference for which tool to
use all right let me propose now that we
apply this same idea of a class method
to clean up one other thing as well let
me close hat dopy and reopen student. py
as we left it earlier and let me go
ahead and simplify it just a little bit
uh I'm going to go ahead and get rid of
the properties not because there's
anything wrong with them but just
because I want us to focus on some of
the key ideas when we began with this
program so I'm going to go ahead and
keep main as well I'm not going to
adversar try to change Harry's uh
address there I'm going to instead go
ahead though and just print the student
but this is the thing I want to focus on
here this in our previous student
examples was kind of a missed
opportunity to clean up my code well
what do I mean by that well up here at
the top of this file even though I've
simplified it by getting rid of the
properties and all of that error
checking because I want to focus on the
essence of this class now just the
students's name and the house and the
printing thereof this is by nature of
classes and object-oriented programming
theoretic Al all of my student specific
functionality that is to say if I have
functionality and data related to a
student you the programmer my colleague
would assume that it's all bundled up
encapsulated so to speak inside of the
student class and yet if you scroll down
further what is this like there's a
function called get student that just
exists elsewhere in this file that
prompts the user for a name prompts the
user for a house creates the student
object and then returns it like that's
not wrong like it works and we saw many
many times it kept working but this is a
little weird right because what if this
is a function that helps you get a
student helps you get the name of a
student and the house of a student why
isn't that functionality in the class
itself after all as my code gets more
and more complicated and does more
things I'm going to be looking at the
student class for all student related
functionality I'm not going to be
scrolling down expecting that oh maybe
there's some other student functionality
just kind of randomly later in this file
so it's not wrong but this is again
evidence of maybe bad design not so much
with this small program but this is an
example again of code smell like
something smells a little off here like
this is probably going to get us in
trouble by separating related
functionality so again it's a design
principle not a correctness concern but
class methods allow us to address this
too let me go ahead and do this I'm
going to delete get student altogether
leaving only main as my other function
here and inside of my student class I'm
going to do this I'm going to define a
function even more simply called get and
by nature of how class methods work it's
going to take in the name of the class
itself or reference there too as an
argument and I'm going to move the
functionality from get student into the
student class and I'm going to do this
name equals input quote unquote name uh
house equals input quote unquote house
and then what this function is going to
do is return a new student object by
calling class which again is just an
automatically passed in reference to the
class itself passing in name and house
and I will admit this syntax seems a
little strange that now I'm calling CLS
and I'm passing in these arguments but
let me do one final fix here let me go
to the top of this function and more
explicitly say this is a class method
this solves a potential Chicken and the
Egg problem so to speak whereby one
needs to come before the other
potentially so what am I doing here
inside of my student class I now have a
function called get it is I shall claim
a class method what does that mean it
just means I can call this method
without instantiating a student object
first there in lies the potential
Chicken and the Egg problem and if
unfamiliar that's an expression meaning
well did the world have chickens first
that laid eggs or was there an egg that
then Bor uh yielded the chicken but how
did the egg get there it's this sort of
weird circular problem and that's what
we're facing here it would be weird if
you had to create a student object in
order to call get in order to get
another student object like that sounds
messy let's just get a student via a
class method that by definition does not
require you to create a student object
first just like the Hat in its final
form we use the Hat class to just say
hat Capital H do sort we didn't need to
create a hat first we just used the
class itself so what am I going to do
here now let me go down to Main and
instead of saying get student notice
what I can now do student. get and
everything else can stay the same all
I've done now is I've migrated all of my
logic from get student which was this
own Standalone function but clearly
related to students by name I've moved
the same code really to inside of the
student class in a more simply named
function called get but I could still
call it get student if I want it just
seems a little redundant to call it get
student in a student class so I'm
simplifying so I have a method called
get but I'm calling it a class method to
avoid that chicken in the egg problem I
want to be able to call get without
having a student object in my universe
already and the syntax for that is at
class method the convention is to give
this method at least one argument by by
convention called CLS for class which is
just going to be a reference to the
class itself lines 11 and 12 are
identical to what they've always been
and get student the only new syntax here
is this but this again is one of the
features of object-oriented programming
you can now
instantiate a student object by just
using CLS that's passed in I technically
could use student capital S but it turns
out I'm doing what's more conventional
because this will both solve and avoid
problems down the line with more
complicated code this line here on line
13 just means create an object of the
current class what class is that well
whatever CLS is well that by definition
of how it all works is going to be
student and I want you to initialize it
as always with name and house so now
scrolling down my code is this and this
is just nice to read you did perhaps
have to acquire a taste for this and I
sound a little odd saying this is nice
to read but indeed student. just tells
me what's going on I'm going to get a
student I don't need a separate function
written by me called get student in the
file itself the get functionality is
built into the class all my student
related code now is together so let me
go down to my terminal window and run
python of student. enter let's type in
Harry let's type in Gryffindor and we're
back to where we began but but but
everything related to students now is in
this here class the only other thing in
the file is Main and this conditional
that we always use to avoid accidentally
executing main when we're making a
module or a package or the like so again
a solution to a problem not a big one in
the case of a relatively small program
but one that you will eventually
encounter as your programs get longer
and longer with more and more entities
to
represent questions now on this use of a
class method does the does the class
have to be defined before the main
function in terms of the order of the of
the program really good question so when
in doubt let's try this so let's try to
change the order let's move main to the
top which I've often encouraged so let's
go ahead and above the class do this and
notice now that technically line two is
mentioning student which does not exist
until line six and Below let me go ahead
and clear my terminal and run python of
studenty so far so good Harry Gryffindor
okay uh indeed Harry's from Gryffindor
the reason Michael it does not matter in
this case is because we're not actually
call main until the very end and just as
in the past that means that python has a
chance to read everything top to bottom
left to right so everything exists I
would say generally classes are defined
at the top of the file however it would
be even maybe cleaner to move the
classes definition to its own file and
then import it so essentially to make
reusable code by putting it into your
own module or package so that not just
this program but many others can use
that definition of student as well other
questions now on classes class methods
or the like I wanted to ask is there a
way to um like declare all the all the
possible all the possible attributes of
the class because it looks so
inconsistent um well so my takeaway
there is this is Python's approach to
these principles different languages
like Java just take a different approach
but have very similar features the
syntax just tends to vary and this is
how the python Community chose to
implement this idea the right mental
model ultimately is that these instance
variables instant methods belong to or
operate on specific objects a specific
student a specific hat class variables
and class methods operate on the entire
class itself or in turn all objects of
that class which we've not seen them a
demonstration of but it's sort of a
higher level concept so it turns out
besides these class methods which are
distinct from those instance methods
which to be fair do not have their own
decorator they just are by default
instance method there's yet other types
of methods you can have in classes in
Python they tend to be called Static
methods and they too come with another
decorator called at static method which
is a rabbit hole we won't go down but
realize that there is yet other
functionality that you can leverage
within object-oriented programming but
what we thought we'd do is focus really
on some final core features that you see
not just in Python but other languages
as well and perhaps one of the most
compelling features of objectoriented
programming that we haven't yet used
explicitly though it turns out we've
seen implicitly over the past weeks is
this notion of inheritance it turns out
via object-oriented programming there's
actually an opportunity to design your
classes in a hierarchical fashion
whereby you can have one class inherit
from or borrow attributes that is
methods or variables from another class
if they all have those in common so what
do I mean by this here well let me
propose that we Implement uh over in vs
code here a brand new file called
wizard. let me go ahead and run code of
wizard. py and then let's start as
before defining a class called student
and let's go ahead and first Define the
underscore uncore init method which of
course is minimally going to take an
argument traditionally called self and
in this case let's also have it take as
before a name and a house and then in
this init method let's go ahead and
assign the instance variables self. name
equals name and self. house equals house
let's assume that there's some other
functionality in this class as well dot
dot dot but let's move on now to
implementing the notion of a a professor
in The Wizarding World as well so for
this class let's call it
professor and a professor let's say is
also going to have its own
initialization method so underscore
underscore in it it's going to take self
as always as the first argument uh a
professor also has a name so we'll pass
that in second two and even though some
professors are heads of houses let's
assume that a professor is really
identified by their name and their
subject area the class that they teach
so we'll call this third argument
subject now as before let's go ahead and
assign self. name equals name and let's
assign self. sub equals subject here and
as before let's assume that there's some
more functionality associated with
professors as well well what do you
notice already here in my definitions of
St students and
professors typically we're a bit
reluctant to allow for any redundancy in
our code and here I feel like my init
method is taking a name for students my
init method is also taking a name for a
professor and I have these identical
lines of code like self. name equals
name and this is only going to get
exacerbated if I now go and add some
error checking so for instance How about
if uh if not name we should probably be
in the habit of raising something like a
value error in an explanatory message
like missing name and you know what if a
professor is missing their name I should
probably copy paste that code down here
and that's where Red Flag should be
going off whereby as soon as you start
copy pasting code there's probably a
better way so that we can write the code
once and perhaps reuse it in some way
and here too object-oriented programming
offers a solution it turns out that
object-oriented programming in Python
also supports inheritance whereby you
can Define multiple classes that somehow
relate to one another they don't need to
exist sort of in parallel in this way
there could actually be some hierarchy
between them so for instance in The
Wizarding World we could argue that both
a student and a professor are at the end
of the day Wizards so maybe what we
should really Define is a third class
for instance called wizard that has any
of the common attributes for students
and professors alike and for now we've
kept it relatively simple the only thing
they have in common is a name and a name
in student and Professor respectively so
why don't we minimally factor that out
first all right so let me go ahead here
and just to keep things organized at the
top of my file let's define a third
class called Wizard and a wizard will
have its own initialization method so
decore uncore init underscore uncore and
self as always and a wizard let's say
for now is only going to be initialized
with their name in this way and now I'm
going to go ahead and do some of that
error checking so if not name we'll
raise a value error in the Wizard class
otherwise we'll go ahead and do self.
name equals name and heck dot dot dot
maybe some other functionality as well
but not a subject which is specific to
professors and not a house which I've
claimed is specific to students now I
think we can begin to maybe remove some
of the redundancies in our other classes
here so for instance down with student
why don't I go ahead and remove this
error checking here and remove this
error this assignment of self. name
equals name because I'm already doing
that in Wizard and similarly down here
in Prof Professor why don't I do the
same let's get rid of the error checking
let's get rid of self. name equals name
because I'm again I'm doing that already
up there for Wizard as well but at the
moment even though they're all in the
same file I haven't told python that a
student is a wizard and a professor is a
wizard so I really need to link these
two together and the way you can
prescribe inheritance whereby one class
should inherit from another or
conversely one class should descend for
another from another we can do this I
can say class student but before the
colon I can go in and say in parenthesis
a student inherits from or is a subass
of wizard which conversely is the super
class of the student class so this just
means that when I Define a student class
go ahead and inherit all of the
characteristics of a wizard as well and
I'm going to do the same thing for Prof
for Professor so parenthesis wizard
after the class name professor and
that's going to give me access to some
of that same
functionality but because my student
class and my professor class still have
their same init methods those are the
methods that are going to get called
whenever I create a student in code or I
create a professor in code I need to
somehow explicitly say that I also want
to use the functionality in the Wizard
classes init method and the way to do
this in Python is is as follows let me
go into my init method for student and
let me call Super with no arguments
which is a reference to the super class
of this class so if this class is
student the super class that is the
parent class is Wizard so super open
paren closed paren will have the effect
of accessing the super class and then
I'm going to go ahead and explicitly
call its init method and I'm going to
pass to the Wizards init method the name
that the students init method was passed
and I'm going to go ahead and do the
same down here in Wizard this is one
line of copy paste but I think I'm okay
with it here because it's still allowing
me to do all of the name assignment and
the error checking up in the Wizard
class instead I think we're okay now by
just calling super. init for both
student and Professor alike now
admittedly this syntax is definitely out
there the fact that we're calling super
and parentheses and dots and underscore
underscore on the left and the right of
in it here but it's just a combination
of these two ideas super open
parenthesis closed parenthesis is a way
of programmatically accessing a current
classes parent class or super class and
underscore uncore init of course is just
referring to now that class's own
initialization method now per the dot
dot dots there could be a lot more going
on in these classes but what's nice now
is that wizard as a class is taking care
of all of the assignment of a Wizard's
name whether that wizard is a student or
a professor and it's even doing some
error cheing to make sure that the name
was actually passed in meanwhile student
is inheriting all of that functionality
and using it by calling the super
class's own init method but it's
additionally taking the house that's
presumably passed into the student
Constructor function and assigning it to
its own instance variable self. house
and similarly Professor are we storing
in self- thought subject the subject
that was passed into there that one as
well now how might we use these classes
well we'll continue to wave our hands
with a little bit of detail here but if
at the bottom of this file or any other
file that Imports this one I could now
write code like this I could create a
student variable and assign it the
return value of the student Constructor
call and maybe that student is named
Harry and that student's house for
instance might be Gryffindor and
meanwhile I might do something like this
professor equals professor over here and
notice the lowercase s on the left
capital S on the right same for
Professor on the left lowercase and
uppercase on the right respectively
Professor quote unquote seus and how
about defense against the dark arts will
be his subject and meanwhile if we want
more generically just a wizard who at
the moment
is neither student nor Professor
teaching classes actively we could even
do that we could do wizard equals wizard
in capital W on the right hand side of
the equal sign because it's the name of
the class and someone like Albus passing
in only albus's name not a house not a
subject because in this case he's known
only as a wizard meanwhile with each of
these calls this line of code here will
ensure that the init method for the
wizard class is called this line of code
here will ensure that the init method of
the student class and in turn the init
method of the super class wizard is
called and then lastly on this final
line of code will this syntax ensure
that the init method of the professor
class is called which in turn calls the
init method of the super class as well
any questions now on this idea of
inheritance which is a key feature of a
lot of
objectoriented programming languages um
so is there any situation where because
uh from what I've seen so far A lot of
times there's like a lot of nesting if
you do subar does it go one up is there
any situation where you know it's nested
in another class as well um above wizard
let's say a really good question if you
were to have a super super class so your
hierarchy is even taller than the two
levels of uh hierarchy that we currently
have absolutely but what's nice about
object-oriented Pro what's nice about
inheritance as the name implies is just
as you might have inherited certain
traits as a human from your grandfather
and Grand mother or your
great-grandfather or great-grandmother
some of those properties can actually uh
trickle down to you so to speak in the
context of code as well so when you
descend from another class that is when
you subclass a a super class or a super
super class you actually do inherit all
of the functionality not just from one
level above you but from two or three so
you can indeed access some of that
functionality as well and you can even
override it if you want some of these
classes to behave a little bit
differently than others other questions
on inheritance so it's kind of similar
to the last one but can you have like
two parents on the same level a really
good question so there are ways to
implement uh um descendants from
multiple parents and there's different
ways to do this not just in Python but
other languages we've kept things simple
here though by having a single uh
inheritance path a good question how
about one more question on inheritance
can we have multiple arguments in super
doubleit yes but in this case I'm only
passing in name on line 18 and I'm only
passing in name on line 10 why because
on line two when I Define the init
method for the wizard class I only
expect a single argument but I could
absolutely have under common
functionality like I could add in a
petronis if both students and professors
have patronises that can come out of
their wands I could have two arguments
instead we've been using this feature of
object-oriented programming now for
quite some time in the form of
exceptions indeed if you look at the
official documentation for exceptions in
Python you'll see that there's not even
the ones we've seen in class like value
error and others there's any number of
others as well but they are all
themselves hierarchical in nature this
is just a subset of the available
exceptions that come built into Python
and you can actually as a programmer
create your own exceptions as well but
as this chart here uh captures
hierarchically all exceptions we've seen
thus far actually descend from or
inherit from Super classes already so
for instance at the bottom of this list
here is value error which we've seen
quite a bit and if you follow the line
straight up on this asky rendition of
this chart you'll see that value error
has a parent class or super class called
exception and the exception class
meanwhile has a parent class called base
exception why did the authors of python
do this well it turns out that whether
you have a uh value error or a key error
or an assertion error or any number of
others there's a lot of functionality
common to all of those types of errors
that you want uh all that you want a
programmer to be able to use and so it
turns out that the authors of python
decided you know what let's not have a
dozen or more different classes that all
just have copy pasted similar
functionality let's create this
hierarchy so that even though the
exceptions toward the bottom of this
list are very precise they at least
inherit that is borrow some very common
fun fun ality up above so it turns out
that when you use the try and the accept
keyword in Python generally speaking
we've tried to catch very specific
exceptions like value error but
technically you could capture the parent
or even the grandparent exception for a
given exception especially if you're not
necessarily sure which one is going to
get raised or better yet there could be
many exceptions that get raised but you
want to handle them all the same and you
don't want to necessarily enumerate them
in parenthesis separated by commas you
want to say you want to handle all
exceptions of a certain super class in
much the same way so this has been
latent this whole time anytime we've
seen or used or caught or now raised
exceptions and built into python is this
hierarchy and if you were to invent your
own exception generally you wouldn't
want to start from scratch you would
want to descend from that is subclass
one of these existing exceptions and add
your own twist on it your own
functionality as well well there's one
final feature of object-oriented
programming that we'd like to share with
you today in that it will perhaps be
quite the eye opener is what you can
really do now that you have classes at
your disposal and this too surprise has
been a feature you and I have been
taking for granted for weeks now this
has just worked but it's been
implemented in a way that you can now
leverage yourself it turns out that
Python and some other languages too
support this notion of operator
overloading whereby you can take very
common symbols like plus or minus or
other such syntax on the on the keyboard
and you can Implement your own
interpretation thereof plus does not
have to equal addition and minus does
not have to equal subtraction and in
fact you and I have already seen another
context in which plus means something
else plus has not always in Python meant
addition per se what else has python
used Plus for concatenation for
concatenation for joining two strings
for adding to a list can you use plus as
well so plus has actually been funny
enough overloaded by the authors of
python for us and so we can use the same
symbol in much the same way as addition
but with different data types to solve
slightly different problems well let me
propose that we go back over to VSS code
here and let me go ahead and create a
new Final file called vault. py so code
of vault. py and let me propose that we
implement the idea of a vault at grots
keeping on theme wherein there's a bank
in the World of Harry Potter and within
this Bank uh family and individuals have
vaults containing all sorts of money in
The Wizarding World and the type of
money that exists in the World of Harry
Potter are coins called gallions and
sickles and canuts and those are in
descending order of value and so inside
of a vault might be a whole bunch of
coins gold silver and bronze essentially
each in those denominations tucked away
so how can I go about implementing first
of all the idea of a vault so that I can
store for instance for Harry Potter how
much uh coinage is in his family's Vault
or for Juan resley the same let me go
ahead in Vault up high and first create
a class called Vault essentially meant
to represent a bank vault perfect
another real world or fantasy world
entity that I want to represent with
code I could use a tupple or a list or a
dictionary but again I'm going to get a
lot more functionality with classes and
we'll see one final flourish with
operators inside of this Vault class
let's go ahead and do this let me Define
my init method taking its first argument
of self and let me Define uh three
arguments to this when you create a
vault in my code here I want to be able
to initialize it with some number of
gallions some number of sickles and some
number of conuts I want the use the
programmer to be able to pass in one or
more of those values ideally but they
can be optional so I'll give them
defaults so let's go ahead and Define a
parameter called gallions whose default
value will be zero sickles whose default
value will also be zero and canuts whose
default value will be zero as well so
the programmer can pass in one or two or
three or heck even none of those and
they'll all have some implied defaults
how do I want to remember those values
that are passed in well let me do this
self. gallion equals gallion and self.
sickles equals sickles and self. canuts
equals canuts and so I could add some
error checking especially if you don't
pass in a number I could turn these into
properties to do even more validation
but let's keep it simple and as always
Focus only on the new ideas so I'm just
going to trust that these values were
passed in and I'm going to immediately
assign them to these instance variables
what now do I want to do well let's come
up with a way of printing out what is in
someone's Vault ultimately but first
let's do this let's create a a vault for
The Potters by creating via assignment a
new Vault and let's say that the Potters
have 100 gallions 50 sickles and 24
canuts all right and that's in that
Vault and let's print out for instance
Potter all right let's run this code and
see how it works now let me go ahead and
run python a vault. pi enter
okay seems to work no syntax errors or
anything else but this is not very
enlightening how do I fix this thinking
back to what we've done before you have
to use the underscore underscore s
exactly I need to use one of those
special methods that comes with classes
and Define for myself how I want a vault
to be printed as a string so let me go
ahead and do that let me Define the stir
method taking in self as its sole
argument here and let's just return a
very simple string that just reveals
what's in the vault so I'm going to
return a formatted F string uh inside of
which is self. gallan and then the word
uh gallion so I know which those are uh
then let's do self. sickles and let's
output the word sickles and then lastly
let's output self. canuts and then
canuts here so I know in this string
just how many of each of those uh coins
I have in this particular family's Vault
all right let me go ahead and run python
of vault. changing nothing else except
the stir method and now we see indeed
that Harry has 100 gallions 50 sickles
and 25 canuts all right well let's do
one thing more here below that let's go
ahead and Define a Weasley variable and
Ron never seemed to have quite as much
uh money in the vault as did Harry so
let's say that the Weasley Vault will
have 25 50 and 100 so I'll just reverse
the order of those denominations uh
rather than Harry's 100 5025 and now let
me go ahead and print Weasley like this
and let's go ahead and clear my terminal
window run python of vault. this time
that stir method will be invoked twice
once for each of those Vault objects and
we'll see indeed that the first one for
Harry's got 50 and 25 respectively
versus Ron's 25 50 and 100 respectively
but now let's do something interesting
suppose that you wanted to combine the
contents of two vaults be it Harry's and
Ron's or any other two people how would
you go about doing this in code well if
I wanted to combine the vaults for
someone I could do this well I could do
gallion equals let's do potter. gallion
uh plus Weasley do gallion that gives me
a variable called gallion that has the
sum of Harry and Ron's gallion let's
next do sickles equals potter. sickles
plus Weasley do
sickles and then lastly let's do canuts
equals potter. canuts plus Weasley do
canuts I've got three variables what can
I now do with these values well let's
create a third a new Vault uh total will
be the name of this variable equals a
new Vault capital V notice and now let's
pass in those three new variables
gallions sickles and canuts and that's
it and let's print out this total Vault
so we should now see three vaults one
for Harry for Ron and the combination
the addition of the two let me go ahead
and rerun python of vaulty and there we
have it uh what was 10050 25 and 25 50
and 100 combined through addition now is
125 100 125 so pretty straightforward
using techniques from weeks ago where
we're just declaring a few new variables
and doing some addition but wouldn't it
be cool if I could do something like
this wouldn't it be cool if I could just
somehow not manually create my own Vault
and do all of this annoying math up here
what if I could just do Potter plus
Weasley and get rid of all of this logic
here like wouldn't it be nice if I
overload the operator no we know as plus
just like stir does just like list does
to allow me to add two vaults together
on the left and the right well it turns
out in Python and through operator
overla there is a way to do just this if
you consult the documentation there are
there's this and so many other special
methods that come with classes the third
one we see here is this one here
underscore uncore add underscore
underscore and you see that it very
generically is described in the
documentation as working for any object
be it a vault or a stir or a list or
something else by convention it's going
to take a first argument called self and
then it's going to take some other
argument by convention called Other Self
in effect is going to be referring to
whatever object is on the left of a plus
sign other is going to be referring to
whatever is on the right hand side of a
plus sign thereby giving us a way of
describing in code the operand on the
left and the operand on the right of the
operator Plus in between that is to say
if I go back to vs code here what I'm
trying to do is Implement support for
this well let me try without writing any
other code just yet python a vault up
high enter type error unsupported
operand types for Vault and Vault that
is to say python at this moment does not
know what it means to add two vaults
together right you and I might have an
instinct probably want to combine the
gallions and the sickles and the canuts
respectively python doesn't know that it
just knows that you have a new class
called Vault but let's teach python to
do this let me clear my terminal window
let me scroll back up to the class
itself where at the moment I only have
two special methods in it and stir but
let's add this third all right let me go
into the class here and Define
underscore uncore addcore underscore and
then specify its first parameter as self
as before and then a second parameter
for this particular method called by
convention other now as always I could
name those parameters anything I want
but I'm going to stick with convention
Here and Now inside of this method am I
going to have to now add together the
contents of two vaults well what two
vaults well if we scroll down to our
goal at hand the goal of course is to
add this Vault plus this other Vault
Potter plus Weasley respectively well it
turns out in Python that when you do
overload an operator like Plus what's
going to happen automatically as soon as
python sees that is it's going to call
that underscore underscore ad underscore
underscore method and it's going to pass
into it to our arguments whatever the
operand is on the left Potter in this
case and whatever the operand is on the
right Weasley in this case and those
values are going to get passed in as
self and other respectively what that
means is that we can access their
contents up here in our implementation
of AD as follows let me go ahead and
Define a local variable called gallion
and set that equal to for instance the
sum of self. gallions whatever's in uh
Potter's vault in this case plus
whatever is in Weasley's vault in this
case which would be other do gallion let
me do the same for sickles self. sickles
plus other do sickles and let me lastly
do that for canuts so self. canuts plus
other. canuts but at the end of the day
I'm going to need to return a brand new
bigger Vault that contains all of those
contents together and if we ultimately
want to assign that bigger Vault to a
variable like total here on the left we
better indeed return a value from this
ad method so I'm going to go ahead and
give myself a brand new vault as by
returning Capital vault which of course
is going to call My Vault function into
which I can now pass some of those
initialization arguments well how many
gallion sickles and canuts do I want
this brand new Vault to contain well I
want it to contain this many gallions
this many sickles and this many canuts
so ultimately what we're doing in this
implementation of ad is adding together
those gallion sickles and canuts passing
them to the Vault function so that we
get a brand new bigger Vault and return
that all together so now I've defined
this new special method called add that
should now just make Plus work for two
vaults all right let's see let me run
down to my terminal window python a
vault up high and hit enter and voila
now we've implemented an overloaded
operator plus to do what you and I as
humans would hope would be the case when
you add two vaults together but I've now
written the code more specifically to
teach python what it means concretely to
add two vaults together and it's with
very similar code in effect underneath
the hood that python is doing this for
two strings to concatenate them together
to joining to lists into a new list with
lists and so many other classes as well
any questions now on operator
overloading or this example here how
would you go about creating a function
for adding a student and a vault for two
two separate classes how would that be
possible
let me see what happens here I don't
know off hand let's do this let's create
a stir and see what happens if I add
Potter plus a stir stir object yeah okay
so it would work I'm just figuring this
out as I go here Eric so just to re be
clear what I did was I just changed
Weasley to stir just to see what would
happen when I add a vault plus a stir
and it will work theoretically why
because so long as the type of value on
the left has an add method implemented
other can be any type that you want you
just have to decide and code what it's
going to mean conceptually to add a
vault plus a string which in this case
probably doesn't make any sense at all
but it's possible it's going to be the
operand on the left and I'm inferring
that I did not know the answer a moment
ago I'm inferring that because what I
got was an attribute error here on line
11 because python did not like this
other gallion didn't work but I could
make it work by figuring something out
really good question didn't know that
one myself other questions on
operator overloading can you define new
operators in Python I don't think so
there is a very long but precise list of
operators that you can overload I do not
believe you can assign arbitrary
characters to be operators in Python uh
let me defer to Carter in the chat to
revoke okay I'm seeing two of my
colleagues are saying no not possible so
I'm going to go with my first instinct
no otherwise that'd be kind of cool you
could make Emoji do whatever you want to
how about one final question on operator
overloading
is that the only operation you can do uh
is a far as like can you do a
subtraction as well you can you can do
so many others let me um if Carter you
don't mind pulling up this URL here so
this link here special method names in
today's slides you'll see a long list of
all of The Operators that you can
overload you can do less than equals
than plus equals minus equals pretty
much any symbol you've seen me type on
the screen can be overloaded in the
context of
classes so even though today we focused
entirely on object-oriented programming
this is a technique that we've been
using really since the first week of the
class because indeed those ins those
stirs those floats those lists those
dictionaries and so much more were
already underneath the hood this whole
time classes and objects thereof but you
now as a programmer have the ability to
create your own classes with your own
instance or class variables with your
own instance or class methods with your
own properties and even with your own
custom behavior for operators so
ultimately you can absolutely continue
using those simple tles or lists or
those dictionaries or other structures
as well but object-oriented programming
and with it classes and now these
objects is just another tool in your
toolkit and dare say as your code gets
more sophisticated and your problems get
bigger you'll find that being able to
model these real world or even fantasy
world entities with classes and related
data and functionality will ultimately
just allow you to Define code that's not
just correct but ever well designed as
well this was cs50
[Music]
[Music]
all right this is cs50's Introduction to
programming with python my name is David
me and over these past many weeks have
we focused on functions and variables
early on then conditionals and loops and
exceptions a bit of libraries unit tests
file AO regular Expressions
object-oriented programming and really
Etc and indeed that's where we focus
today is on all the more that you can do
with python and programming more
generally Beyond some of those
fundamental concepts as well in fact if
you start to flip through the
documentation for python in all of its
form all of which is as always
accessible at docs. python.org you'll
see additional documentation on Python's
own tutorial in library uh its reference
it's how to and among all of those
various documents as well as others more
online you'll see that there's some
tidbits that we didn't quite touch on
and indeed even though we themed these
past several weeks of around fairly
broad topics that are rather essential
for doing typical types of problems in
Python it turns there's quite a number
of other features as well that we didn't
necessarily touch on that didn't
necessarily fit within any of those
overarching Concepts or might have been
a little too much too soon if we did
them too early on in the course and so
in today our final lecture will be Focus
really on all the more that you can do
with python and hopefully wet your
appetite for teaching yourself all the
more too for instance among Python's
various data types there's this other
one that we haven't had occasion to yet
use namely a set in mathematics a set is
typically a collection of values wherein
there are no duplicates so it's not
quite a list it's a bit more special
than that in that somehow any duplicates
are eliminated for you well it turns out
within python this is an actual data
type that you yourself can use in your
code and via the documentation here
might you be able to glean that it's a
useful problem if you want to somehow
automatically filter out duplicates so
let me go ahead and go over to VSS code
here and let me go ahead and show you a
file that I created a bit of in advance
whereby we have a file here called
houses. and in houses. I already went
ahead and whipped up a big uh list of
students inside of which is a number of
dictionaries Each of which represents a
student's name and house respectively
now this is a pretty sizable dictionary
and so it lends itself to iteration over
the same and suppose that the goal here
was quite simply to figure out well what
are the unique houses at Hogwarts in the
World of Harry Potter it would be nice
perhaps to not have to know these kinds
of details or look them up online here
we have a set of stud students albeit
not exhaustive with all of the houses
but among these students here what are
the unique houses in which they live
well I could certainly as a human just
eyeball this and tell you that it's well
Gryffindor Slither and Ravenclaw but how
could we go about doing it
programmatically for these students as
well well let's take one approach first
here let me go into houses. and let me
propose that we first how about create
an empty list called houses in which I'm
going to accumulate each of the houses
uniquely so every time I iterate through
this uh list of dictionaries I'm only
going to add a house to this list if I
haven't seen it before so how do I
express that well let me iterate over
all of the students with for student in
students as we've done in the past and
let me ask a question now so if the
current student's house and notice that
I'm indexing into the current student
because I know they are a dictionary or
dict object and if that student's house
is not in my houses list then indented
am I going to say houses. append because
again houses is a list and I'm going to
append that particular house to the list
then at the very bottom here let me go
ahead and do something somewhat
interesting here and say for each of the
houses that I've accumulated in I could
just say houses but if I just say houses
what was the point of accumulating them
all all at once I could just do this
whole thing in a loop let's at least go
about and sort those houses with sorted
which is going to sort the strings Al
alphabetically and let's go ahead there
in and print each of the houses let me
go ahead now in my terminal window and
run python of houses. and hit enter and
there we have it Gryffindor Ravenclaw
Slytherin in alphabetical order even
though in the list of dictionaries up
here technically the order in which we
saw these with was Gryffindor Gryffindor
Gryffindor slitherin Ravenclaw so indeed
my code seems to have sorted them
properly so this is perfectly fine and
it's one way of solving this problem but
it turns out we could would use more
that's built into the language python to
solve this problem ourself here I'm
rather Reinventing a wheel really the
notion of a set wherein duplicates are
eliminated for me so let me go ahead and
clear my terminal window and perhaps
change the type of object I'm using here
instead of a list which could also be
written like this to create an empty
list let me go ahead and create an empty
set whereby I call a function called set
that's going to return to me some object
in Python that represents this notion of
a set wherein duplicates are automatic
eliminated and now I can tighten up my
code because I don't have to use this if
condition myself I think I can just do
something like this inside of my Loop
let me do houses. add so it's not a pend
for a set it's a pen for a list but it's
add to a set per the documentation then
let me go ahead and add this current
student's house and now I think the rest
of my code can be the same I'm just now
trusting per the documentation for set
in Python that it's going to filter out
duplicates for me and I can just blind
add add add add all of these houses to
the set and any duplicates already there
will be gone python of houses. and enter
and voila we're back in business with
just those three there as well let me
pause here to see if there's any
questions now on this use of set which
is just another data type that's
available to you another class in the
world of python that you can reach for
when solving some problem like this how
can we locate an item in a set for
example find Griffin door in the oh how
do you find an item in a set you can use
very similar syntax as we've done for a
list before you can use syntax like if
Gryffindor in houses then and you can
answer a question along those lines so
you can use in and not in and similar
functions as well other questions on set
okay what happens if you have a similar
house name let's say instead of
slithering it is maybe an O instead of
an I will the fall Loop look throughout
each of those um letters in the house
name uh it would compare the string so
if Slytherin appears more than once but
is slightly misspelled or misc
capitalized if I heard you right those
would appear to be distinct string so
you would get both versions of Slytherin
in the result however we've seen in the
past how we can clean up users data if
indeed it might be messy we could force
everything to uppercase or everything to
lowercase or we could use capitalize the
function built into stirs or title case
that would handle some of the cleanup
for us in this case because the data is
not coming from humans using the input
function I wrote the code in advance
it's safer to assume that I got the
houses right but that's absolutely a
risk if it's coming from users allow me
to turn our attention back to some of
the other features here that we can
leverage in Python if we dig further
into the documentation and read up more
on its features well in some language
there's this notion of global variables
whereby you can define a variable that's
either local to a function as we've seen
many times or if you put a variable
outside of all of your functions perhaps
near the top of your file that would
generally be considered a global
variable or in the world of python it
might be specific to the module but for
all intents and purposes it's going to
behave for a given program as though it
is global however it turns out that if
you do this when solving some problem
down the line whereby you have multiple
functions and you do have one or more
variables that are outside of those
functions you might not be able to
change those variables as easily as you
might think so indeed let me go back to
vs code here and in just a moment I'm
going to go ahead and create a new file
how about called
bank.pay let's go ahead and implement
the notion of a bank wherein we can
store things like uh money in various
forms and let me go ahead and do this
let me go ahead and Implement a very
simple bank that simply keeps track of
my total balance the number of dollars
or cents or whatever I might be storing
in this bank and I'm going to give
myself a very iable called balance at
the top which is an integer a set to
zero now let me go ahead and Define a
main function as we often do and inside
of my main function let me go ahead and
print out quote unquote balance and then
print out the value of balance itself
passing to print as we've often done
more than one argument so that they get
uh separated by a single white space And
now since I have a main function really
setting the stage for doing more
interesting things soon let me go ahead
and do our usual if the name of this
file equals equals underscore uncore
main then go ahead and call Main so this
is a terribly short program but it's
perhaps representative of how you might
solve some future problem in Python
whereby you have a main function that's
going to eventually do some interesting
stuff and at the top of your file you
have one or more variables that are just
useful to keep there because then you
know where they are and perhaps not just
main but other functions can access them
as well so let's see when I run this
program python of bank.pay I would hope
based on my own in thus far then I'm
going to see that my current balance is
zero that is to say even though the
balance variable is defined on line one
hopefully I can still print it on line
five inside of main even though balance
was not defined in my main function here
we go hitting enter and voila balance
zero so it does seem to work even if you
declare a variable in Python outside of
your functions it appears that you can
access it you can read the value of that
variable even inside of a function like
Maine well let's get a little more
adventurous now because this program
really isn't solving anyone's problems
let's go ahead and Implement more of a
bank like the ability to deposit money
into the bank and to withdraw money from
the bank thereby giving me some more
functions that might very well need to
access that same variable Let Me Clear
My terminal window here and let me go
ahead and pretend for the moment that I
have the ability to deposit say $100 or
100 coins whatever the unit of currency
is here and then maybe I want to
withdraw straight away 50 of those same
dollars or coins and now let me go ahead
and just print out at the bottom of main
what my new balance should be so that in
an Ideal World once I've deposited 100
then withdrawn 50 after starting at zero
I'd like to think that my new balance on
line 8 should indeed be 50 all right but
I haven't implemented these functions
yet so let's do that as we've done in
the past down here I'm going to go ahead
and Define another function deposit I'm
going to say that it takes an argument
called n for number of coins or dollars
or the like and I'm just going to do
this I'm going to go ahead and say
balance plus equals n thereby changing
the value of N I could do it more
verbosely balance equals balance plus n
but I'm going to use the shorter hand
notation here instead and now let's
Implement withdraw so Define a function
called withdraw it to is going to take a
variable uh an argument n for number of
dollars or coins and now I'm going to go
ahead and subtract from balance using
minus equals uh n as well and I'm still
going to call Main if the name of this
file is main so what have I done I've
just added not just one but three
functions total all of which apparently
need to access balance by uh printing it
incrementing it or decrementing it as
we've seen here all right let me go
ahead and focus on these three functions
here let me go back to my terminal
window and run python of bank.pay and
hit enter and wow seems like we've
introduced some number of problems here
and what are these problems well Unbound
local error is perhaps the first time
we've seen this one here local variable
balance rep referenced before assignment
and that's a bit misleading definitely
confusing right because I absolutely
assigned balance of value on the top of
my code and indeed if I scroll back up
nothing has changed or been lost up
there it's definitely been assigned a
value and now on line uh 12 it would
seem that when deposit is called I'm
just trying to access that variable
again so intuitively what might explain
this error message Unbound local error
what is python telling us there that
python can or can't do when it comes to
these so-called Global variables that
are at the top of my file uh so if you
want to change this V variable you
should uh write in inside the function
Main and the global variable
unchangeable yeah so
if you want to change the value it might
need to be local to the function if you
are trying to change a global variable
though in a function it clearly does not
work so it's okay to read a global
variable read meaning access it and
print it and so forth but apparently you
can't write to a global variable in the
same way from within one of these
functions all right well maybe the fix
is to do this let me clear my terminal
window in that error and maybe I could
just do this let's get rid of the global
variable and let's go ahead and put it
for instance inside of
main might this now work well let me try
this now python of bank.pay
enter that alone did not solve it I
still have an Unbound local error this
time though it's for a different reason
it turns out now that balance on line
two is by definition a local variable a
local variable is one that exists in the
context of a function at least in this
case a global variable is the opposite
one that does not for instance at the
top of my file so here is another
distinction in Python if you declare a
variable in a function like main just as
I've done on line two with balance it is
indeed local to that function deposit
and withdraw do not have access to that
same variable why because it's local to
Main and so you would think now we're
kind of stuck in this vicious cycle well
maybe the solution then is to move uh
balance globally so all three functions
can access it but clearly where we began
as oena noted we can't therefore change
it so what turns out the solution to
this problem in Python is ironically
exactly this keyword here it's a little
different as you might have seen if you
programed before in other languages but
there's indeed a keyword in Python
called Global that allows you to tell a
function that hey this is not a variable
that's local to you I mean it to be a
global variable that I want you to edit
so if I go back to VSS code here
clearing my terminal window to get rid
of that error let me go ahead and undo
the change I just made and put balance
back at the top of my file but this time
time what I'm going to do is I'm going
to inform my two functions that need to
change the value of balance that it is
indeed Global by typing Global balance
again here as well as here Global
balance I still leave the same lines of
code now on lines 13 and 18 that
increment and decrement balance but this
now use of keyword Global is a little
bit of a clue to python that oh okay
it's not a local variable this is not a
bug that you've introduced you mean for
to edit this variable up above so now
let me go ahead in my terminal window
and run python of bank.pay I'm hoping to
see that my balance is 0 + 100 minus 50
is 50 and indeed it now is it starts off
at zero per my first print statement on
line five but it ends up at 50 total at
below that on line eight let me pause
here to see if now there's any questions
on these Global or local variables what
happens when you declare a variable
globally and as in the same variable
globally and in a function a good
question you're always thinking about
the so-called Corner cases so if you
declare a variable both globally like at
the top of your file and then an
identically named variable inside of a
function same name the ladder Will
Shadow so to speak the former that is
you'll be able to use the ladder that is
the local variable but it will have no
effect on the global variable
temporarily python will only know that
the local variable exists so in general
the rule of thumb is just don't do that
not only might it create bugs in your
code because you don't quite change what
you intend to change it's also perhaps
uh nonobvious to other readers as well
other questions on globals or locals
okay what if we decide to add balance as
an argument inside the main function
yeah another good Instinct but in this
case that also is not going to solve the
problem because if you pass in a
variable like balance to each of the
function functions and then change it
within that function it's only going to
be changing in effect a local copy
thereof it's not going to be changing
what's outside of those functions so I
think we actually need a better way
altogether and in fact allow me to
transition to perhaps a modification of
this same program recall that we looked
most recently at this notion of
objectoriented programming whereby you
can model real world entities for
instance a bank and you can model and
encapsulate information about that real
world entity for instance like someone's
account balance so let me propose that
we actually do this let me start from
scratch with bank.pay get rid of the
global variable Al together and actually
use some objectoriented code let me
define a class called account to
represent someone's bank account and
then let me go ahead and initialize with
my init method which again takes by
convention at least one argument called
self let me go ahead and initialize
every person's bank account to some
value like zero now how can I do that
well I'm going to go ahead and do self.
balance equals 0 thereby giving me an
instance variable called balance
initialized for this account to zero but
I'm going to proactively remember how we
also introduced this notion of
properties which might otherwise collide
with the names of my instance variables
so just by convention I'm going to do
this I'm going to rename this instance
variable proactively to underscore
balance to effectively indicate that
it's private even though that's not
enforced by python it's just a visual
clue to myself that this is something
that really I should not or other code
should not touch just functions in this
class now let me go ahead and do this
let me go ahead and Define an actual
function called balance that really is
going to be a property whose purpose in
life is just to return self. balance and
I'm going to go explicitly and say this
is indeed a property of this class now
let me go ahead and reimplement those
other two functions deposit and withdraw
but in the confines of this class so I'm
going to say Define uh deposit it's
going to take in an argument self as
always but an additional One n a number
of dollars or coins to deposit and how
do I now manipulate this well I'm going
to do self doore balance plus equals n
and now down here I'm going to do def
withdraw self n just like for deposit
but here I'm going to do self. balance
minus equals n and now if I go down
below this class I'm going to go ahead
and and Define myself a main function
just so I can try this now out I'm going
to go ahead and create an account object
by calling the account Constructor that
is the name of the class with two
parentheses if I'm not passing in any
arguments to in it I'm going to go ahead
now and print out as before the balance
of my account but to do that I'm going
to access the property of that account
like this and I'm going to go ahead now
and say deposit another $100 or coins
with deposit 100 and I'm going to go
ahead like before and also now
immediately withdraw for whatever reason
50 of the same and now I'm going to
print One Last Time balance followed by
account. balance again accessing that
property and for this whole thing to
work of course I need one of these if
name equals equals uncore main then go
ahead and call Main now before I run
this you'll see that it rather escalated
quickly I had a very simple goal at hand
to implement the notion of a bank and I
was able to implement that perfectly
fine ultimately by declaring balance to
be Global but then to tell each of my
functions that it is indeed Global but
that's not really the best form of
encapsulation we have at our disposal
now right per our focus on
object-oriented programming if we're
trying to implement some real world
entity like an account at a bank that's
what classes allow us to do and it
allows us to solve that same problem
perhaps a little more cleanly certainly
if we're going to accumulate more and
more functions or methods over time so
if I didn't make any mistakes here if I
run python of bank.pay and hit enter now
you'll see that it just works just fine
because in the world of classes in
Python these so-called instance
variables are by definition accessible
to all of the methods in that class
because we're accessing them all by way
of that special parameter self so which
way to do it for a reasonably small
script wherein you are simply trying to
implement uh a script that has some
Global uh information like an account
balance that you then need to manipulate
elsewhere the the global keyword is a
solution to that problem but generally
speaking in many languages python to
some extent among them using Global
variables tends to be frowned upon only
because things can get messy quickly and
it be can become less obvious quickly
exactly where your information is stored
if some of it's up here some of it's in
your function so generally the rule of
thumb is to use Global variables
sparingly though technically speaking in
Python these Global variables are
technically local to our module if we
were indeed implementing a library and
not just a program so in short try to
use Global variables sparingly but when
you do there is a solution to these same
problems questions now on globals or our
reimplementation of the same idea but
using full-fledged objectoriented
programming uh I just uh would like to
ask uh what this property does what this
property does so if I go back to VSS
code here you'll see that this was a
Technique we looked at in our lecture on
object-oriented programming whereby a
property is a instance variable that's
somehow protected it allows me to
control how it can be read and written
so in this case I only have what's
called generally a Setter and sorry in
this case I only have what's generally
called a getter and there's no mention
of the word getter here this is just
what app property means that function
balance will allow me recall to use
syntax like this where I can pretend as
though balance is indeed with no
underscore an instance variable but I
can now prevent code like mine in main
from trying to change balance because I
do not have a Setter I would not be able
to do something like account balance
equals a th000 to just give myself
$1,000 doll or coins because I have not
defined a Setter so again per our focus
on object-oriented programming these
properties just allow me some finer
grain control some languages allow you
to Define variables that are so to speak
constant that is once you have set a
value to them you cannot not change the
value of that variable and that tends to
be a good thing because it allows you to
program defensively just in case you
accidentally or someone else
accidentally tries to modify the value
of that variable if you have declared it
in some language as a constant it cannot
be changed or usually cannot be changed
without great effort unfortunately in
Python we're again on the sort of honor
System here where we have conventions to
indicate that something should be
treated as though it's constant but
that's not actually enforced by the
language so for instance let me let me
go back here to vs code and let me
create a new file for instance called
meow. pie and let's see if we can't
implement the notion of a cat meowing on
the screen so I'll do code of meow. py
and in meow. pie let me go ahead for
instance and Implement a very simple
program that just has a cap meowing
three times so how about this for I in
the range of three go ahead and print
out quote unquote meow all right well
we've seen in the past how we can clean
this up a little bit for instance if I'm
not actually using I I might as well
pythonic just change the name of that
variable to underscore even though that
has no functional effect here but here
we have this three sort of randomly
hardcoded that is typed explicitly into
my code and it's totally not a big deal
when your code is only two lines but
imagine that this is a much bigger
program with dozens or even hundreds of
lines and imagine that one of those
lines just is a three in there somewhere
like you're never going to find that
three very easily and it's going to be
very easily overlooked by you or
colleagues or others that you've
hardcoded some magic value like a three
right there in your code so it tends to
be best practice not just in Python but
other languages as well anytime you have
what is essentially a constant like a
number three that shouldn't ever change
is to at least let it Bubble Up surface
it to the top of your code so that it's
just obvious what your code's constant
values are and so by that I mean this at
the top of this file it would probably
be a little clear to colleagues and
frankly me tomorrow after I've forgotten
what I did today to Define a variable
like meow and set it equal to three and
then instead of hardcoding three here or
even lower in a much bigger program let
me just go ahead and pass in that
variable's value to my Loop so that now
it's just kind of obvious to me that
meow is apparently the number of times
to meow and if I ever want to change it
the only code I have to change is at the
very top of my file I don't need to go
fishing around or figure out what's
going to break what do I need to change
I just know that I can change these
constants up at the top the problem
though with Pip Pyon is that python
doesn't actually make variables constant
it's indeed a convention in Python and
some other languages to at least
capitalize your variables when you want
to indicate to the world that you should
not touch this it is constant but there
is literally nothing in my code
preventing me from saying you know what
today I feel like four meows instead
like that would work in other languages
though there's typically a keyword or
some other mechanism syntactically that
would allow you to prevent line three
current Cy from executing so that when
you tried to run your code you would
actually get an error message explicitly
saying you cannot do that so python
again is a bit more on the honor System
when it comes to these conventions
instead now it turns out there's other
types of constants quote unquote that
python uh typically manifest and in fact
let me go ahead and change this around a
little bit let me delete this version of
meow and let me introduce again a class
from our discussion of object-oriented
programming like a class representing a
cat another real world entity
recall that within classes you can have
not just instance variables but class
variables that is variables inside of
the class that aren't inside of self per
se but they're accessible to all of the
methods inside of that class here too
there's a convention but not enforced by
python of having class constants whereby
inside of the class you might want to
have a variable that should should
should not be changed but you just want
to indicate that visually by
capitalizing its name so for instance if
the def number of meows for a cat is
meant to be three I can literally inside
of my class but outside of any of my
defined methods just create a class
variable all capitalized with that same
value and then if I want to create a
method like uh meow for instance which
as an instance method might take in self
as we know and then I might have my Loop
here for underscore in the range of and
now I need to access this the convention
would be to say cat. meow to make clear
that I want the meow variable that's
associated with the class called cat
then I'm going to go ahead and print out
one of these meows and now at the bottom
of my code outside of the class let me
go ahead and do something like this let
me instantiate a cat using the cat
Constructor notice this is important per
our discussion of oop the class is
capitalized by convention but the
variable over here is is lowercase and I
could call it just C or anything else
but I kind of like the symmetry of
calling it little cat here and big cat
so to speak over here and now if I want
this particular cat to meow that default
number of three times I can just do cat.
meow like this and that method meow is
going to per line five access that class
constant but again it's constant only in
the fact only in the sense that you
should not touch that not that it's
actually going to be enforced by the
language all right let me go ahead then
and run this with python of meow STP and
there it is three of our meows meow meow
it turns out that python is
uh dynamically typed language that is to
say it's not strongly typed whereby when
you want an INT you have to tell the
program that you are using an INT you
don't have to tell the program that you
are using a stir or a float or a set or
anything else generally speaking to date
you and I when we're creating variables
we just give a variable a name we
frequently assign it using an the equal
sign some other value and honestly
python just kind of dynamically figures
out what type of variable it is if it's
uh quote unquote hello world the
variable is going to be a stir if it's
50 the integer the variable is going to
be an INT now in other languages
including C and C++ and Java and others
it's sometimes necessary for the
programmer to specify what types of
variables you want something to be the
upside of that is that it helps you
detect bugs more readily because if you
intend for a variable to store a string
or an integer but you accidentally store
an integer or a string the opposite or
something else Al together your uh
language can detect that kind of mistake
for you when you go for instance to run
the program it can say no you've made a
mistake and you can fix that before your
actual users detect as much in Python 2
here it's again more of a friendly
environment where you can provide hints
to python itself as to what type a
variable should be but the language
itself does not strongly enforce these
rather you can use a tool that will tell
you whether or not you're using a
variable directly but it's typically a
tool you would run as the programmer
before you actually release your code to
the world or if you have some kind of
automated process you can run this kind
of tool just like you could reformat or
lint your code with some other program
before you actually release it to the
world so how might we go about using
these so-called type penss well they're
documented in the usual place in
Python's own documentation and it turns
out there's a program that's pretty
popular for checking whether or not your
code is adhering to your own typ pins
and that program here is called mypie
and it's just one of several but this
one's particularly popular and can be
easily installed in the usual way with
Pip install mypie and its own
documentation is at this URL here but
we'll use it quite simply to check
whether or not our variables are indeed
using the right types so how can we go
about doing this all right let me go
back here to vs code clear my terminal
window and in fact erase meow. Pie as it
currently was and let's Implement a
different version of meow that quite
simply has a function called meow that
does the actual meowing on the screen
and then I'm just going to go ahead and
call that function down toward the
bottom I'm not going to bother with a
main function just for Simplicity so
that we can focus as always only on
what's new so here we are defining a
function called meow it's going to take
a number of times T meow for instance n
for number and inside of this function
I'm going to do my usual for underscore
in the range of n Go ahead and print
quote unquote meow So based on our
earlier code I think this is correct not
bothered defining the variable as I I'm
instead using the underscore because I'm
not using it anywhere but I think I now
have a working function whose purpose in
life is to meow zero or one or two or
three or more times well let's use this
function again not bothering with main
I'm just going to keep my function at
the very top because there's only one
and I'm going to write my code uh here
on line six so I'm going to give myself
I'm going to ask the user for a number
and I'm going to go ahead and prompt
them in the usual way for that number of
times to meow and now I'm going to go
ahead and call meow on that number now
some of you might see what I've already
done wrong but perhaps I myself don't so
let me go into my terminal window and
run python of meow. py the goal being to
prompt me this seems to be working I'm
going to type in three and I would
expect now the meow function to print
out meow three times enter but no
there's some kind of type error here
stir object cannot be interpreted as an
integer why might that
be why might that be because the input
function returns a string instead of an
in exactly the input function returns a
string or a stir not an INT so in the
past of course our solution to this
problem has just been to convert the
string to an INT by using the int
function but now let me start
programming more defensively so that
honestly I don't even find myself in
this situation at all let me go ahead
and do this let me add what's called a
type hint to my function that explicitly
specifies for meow what type of variable
should be passed in I'm going to go
ahead now and change the very first line
of my code and my function to specify
that n colon should be an INT and this
is a type hint the fact that I've added
a Col in a space and the word int is not
creating another int or anything like
that it's just a hint an annotation so
to speak to python that this variable on
the left called n should be an INT now
unfortunately python itself doesn't care
because again these type hints are not
enforced by the language and that's by
Design the language itself in the
community prefers that python be
dynamically typed not so strongly typed
as to require these things to be true
but if I run meow. py type in three
again the same error is there but let me
go about trying this mypie program an
example of a program that understands
typ hints and if I run it proac actively
myself can find bugs like this in my
code before I or worse a user actually
runs and encounters something cryptic
like this type error here let me clear
my terminal window and this time run my
Pi space meow. so I'm going to run my
piie on my program but I'm not running
python itself when I hit enter we'll see
this all right we see now that my pie
found apparently an error on line seven
error argument one to meow has
incompatible typ stir expected int so
it's still an error message but mypie is
not a program that my users would use
this is a program that you and I as
programmers would use and because we
have run this code now before we for
instance released this program to the
world I can now see even before the code
is called or run oh I seem to be M using
my argument to meow wrong I had better
fix this somehow well I can actually go
about in uh hint adding typ hints even
into my own variables here so as to
catch this another way too if I know on
line six that I'm creating already a
variable called number and I know
already that I'm assigning it equal to
the return value of input I could give
my pi and tools like it another hint and
say you know what this variable called
number should also be an INT that is to
say if I now start getting into the
habit of annotating all of my variables
and arguments to functions maybe my Pi
can actually help me find things quite
quickly as well before I get to the
point of running python itself let's go
ahead and try this again my piie of
meow. Pi and hit enter and this time
notice that my Pi actually found the
mistake a little more quickly notice
this time it found on line six that
error incompatible types and assignment
expression has Type stir variable has
Type int so before I even got to the
point of calling meow line six via this
typeint when used and analyzed by mypie
has helped me find oh wait a minute I
shouldn't be assigning the return value
of input to my variable called number in
the first place why mypie has just
pointed out to me that one returns a
stir I'm expecting an INT let me fix
this now instead all right so let me
clear my terminal window and now let me
do what most of you were probably
thinking I should have done in the first
place after all of these weeks but now
let me go ahead and convert the return
value of input to an integer for today's
purposes I'm not going to try to catch
any exceptions or the we're just going
to assume that the user types this in
properly and now let me go ahead and run
my piie of meow. pie having not only
added two typeint to my argument to my
function to my variable down here on
line six and I've also now fixed the
problem itself let me go ahead and run
my piie and success no issues found in
one source file now it's more reasonable
for me to go and run something like
python of meow and just trust that when
I type in three at least I'm not not
going to get a type error that is I
didn't mess up as a programmer with
respect to the types of my variables why
because when I wrote the coder in the
first place I provided these annotations
these hints that inform tools like my
piie that my intention had better line
up with what the actual code does let me
pause here and see if there's now any
questions on tight pins or my pie is it
common or how common is it for those to
be used or is it just that it's more
used in more complex code
um where it's more difficult to ensure
that you're actually uh using the
correct type in the way that you're
using the variables it's a good question
and it's rather a matter of opinion
python was designed to be a little more
versatile and flexible when it comes to
some of these details partly for uh
writeability to make it easier and
faster to write code partly for
performance so that the program like
python doesn't have to bother checking
these kinds of details we can just get
right into the code the reality though
is that uh strong type checks do tend to
be a good thing for the correctness of
your code why because programs like
mypie can find before your code is even
run if there's already known to be an
error and it tends to be good for
defensive programming um so the the
situation essentially is that within the
python ecosystem you can uh annotate
your types in this way you can use tools
to use those typin but to date python
itself does not enforce or expect to
enforce these conventions in larger code
bases in professional code bases
Commercial Code bases probably depending
on the product uh project manager or
depending on the engineering team they
may very well want themselves to be
using typ pins why if it just decreases
the probability of bugs in fact let me
propose now that I imagine a situation
where instead of expecting that meow
prints meow meow meow some number of
times suppose that I accidentally uh
assume that the meow function just
returns returns meow some number of
times we saw for instance when focusing
on unit tests that it tends to be a good
thing to have functions that return
values be it an INT or a string rather
than just having some side effect like
printing things out themselves so
perhaps I'm still in that mindset and
I've just assumed mistakenly for the
moment that meow returns a value like
meow or meow meow or meow meow meow a
big string of some number of meows
rather than just printing it itself as
it clearly does at the moment on line
three and therefore suppos that I
accidentally did something like this
rather than just getting the number and
passing it to meow suppose I did this uh
suppose I declared a number of a new
variable called meows the type of which
I think should be stir and suppose again
I assume accidentally that meow returns
to me a string of those meows so that I
myself can then print them later this
would be a little more conducive
arguably to testing my meow function why
because I could expect that it's return
rning meow or meow meow or meow meow
meow separated by new lines returning a
stir that I could then assert equals
what I expect it to be in something like
a unit test I'm not going to bother
writing any unit tests now but let's
just suppose that's the mindset I'm now
in and so on line seven I'm assuming
that I want to assign the return value
of meow to a new variable called meow's
which I've annotated with this type hint
as being a stir just so we can see
another variable this one's not an INT
but to stir instead well let me go ahead
and run this code now python of meow.
enter typing in three and you'll see a
curious bug meow meow meow none well why
is that well it turns out at the moment
my meow function only has a side effect
it just prints out meow some number of
times it doesn't explicitly return a
value as it would if there were
literally the return keyword there by
default then when a function in Python
does not explicitly return a value it's
implicit return value is effect none and
so what we're seeing here is this on
line 8 because I'm
assigning the return value of meow which
is none to my meow's variable line three
is what's still printing meow meow meow
and line eight is what's now incorrectly
printing none because I accidentally
thought that meow returns a value but it
doesn't so its return value is
effectively none so I'm printing very
weirdly the word none at the bottom so
how could I go about catching this kind
of mistake too like I might make this
mistake but maybe with less frequency if
I'm in the habit of annotating my code
with this new feature called co uh typ
Pence what you can do here is this let
me clear my terminal window to get rid
of that artifact and up here let me
additionally specify with some funny
looking syntax that my meow function
actually by Design returns none so you
literally use this arrow notation in
Python when hinting what the return
value of a function is you would do this
after the parentheses a space a hyphen a
greater than symbol like an arrow and
then another space and then the type of
the return value for now it's indeed
going to excuse me return none but now
at least I can catch it like this if I
now run not python but my P on my code
which would be a habit I'm now getting
into if using typ hints check that I'm
using all of my types correctly before I
even run my program we'll see that now
my Pie has found on line seven that meow
quote unquote does not return a value
and my Pi knows that because I have
proactively annotated my meow function
as having none as its return value so
now my piie can detect that I should now
realize oh wait a minute I'm being uh
foolish here ma meow clearly does not
return a value I should not be treating
it like it does on line seven let me go
about actually fixing this now so how do
I go about fixing this well let's
practice what we preached in our focus
on unit tests having a function like
meow not have side effects like printing
itself but let's have it return the
actual string and I can actually do this
kind of cleanly let me uh clear my error
message in my terminal window here let
me get rid of the loop here let me say
this time that okay fine meow is going
to return a value an actual stir or
string so I've changed none to stir and
now I can implement this in any number
of ways maybe even using a loop but
recall that we have this syntax in
Python which will I think solve this
problem for us if I want to return a
string of n meows what I can actually do
recall is this return quote unquote meow
back sln times that number n so it's
kind of a clever oneliner avoids the
need for a for Loop or something more
involved than that to just say multiply
meow back sln against itself three times
ENT or end times in this case in general
so that I get back a big string of zero
meows One Two Three or many more meows
instead I think now my code on line six
is actually correct now I've changed
meow to behave the way I was pretending
to assume it always worked so I'm
storing in meow's plural a variable
that's of type stir because now meow
does have a return value of type stir
itself per this typ hint as well all
right let me go ahead now and print
meows but because each of my meows comes
with a a trailing new line the back
slash n I'm going to proactively fix
what would be a minor aesthetic bug and
I'm just going to avoid outputting an
extra new line at the end of those uh
three so if I run python of meow. py now
type in three there's my meow meow meow
and now no mention of none questions now
on typ hints and these annot and mypie
and using them to defensively write code
that just decreases hopefully the
probability of your own bugs in the
return there is a in return there is a
double quotes that have meow
sln why the program don't take it as a
strange why does the program not take it
as a a a strange see so so recall that
um early on in the class we looked at
plus as a concatenation operator that
allows you to join a string on the left
and the right multiplication is also an
overloaded operator for Strings whereby
if you have a string on the left and an
INT on the right it will multiply the
string so to speak by concatenating or
joining that many meows all together so
this is a feature of object-oriented
programming an OB an operator
overloading as we saw it uh in the past
other questions on typ Pence or mypod
can we not type cast this data type of
the you know of this variable number no
you still and let me correct the
terminology it wouldn't be called type
casting in this context uh because it's
not like C or C++ where there's an
equivalence between these types you're
technically converting on line five a
stir to an INT you do still have to do
this because my piie for instance would
yell at you if you were trying to assign
a stir on the right to an INT on the
left you must still use the int function
int it's self is still a function it's
not a type hint but the word int is
being used in another way now in these
type hints so this int is still a
function call as it always has been this
syntax on the left is another use of the
keyword int but in the form of these
type hint so you still have to do the
conversion
yourself all right let me propose that
we transition to another feature of
python that's worth knowing especially
since it's one that you'll see in the
wild when you see code or libraries that
other folks have written namely
something known as a dock string or
document strings it turns out in the
world of python there is a standardized
way per another pep python enhancement
proposal this one 257 that essentially
standardizes how you should document
your functions among other aspects of
your code and so for instance let me go
back to my uh meow. py file here and let
me propose that we now start documenting
this code too so that I know what the
meow function does and in fact the
standard way of doing this using dock
string notation would be as follows to
comment this function not above it as
you might be in the habit of doing with
code in general but actually inside of
it but instead of commenting it like
this with the usual hash comment sign
like meow n times it turns out that when
you're formally docking when you're
formally documenting a function like
meow in this case you don't use regular
inline comment so to speak you use this
syntax instead you use triple quotation
marks either double or single then you
write out your comment meow and times
and then you write the same again at the
end so either three double quotes at the
start and the end or three single quotes
at the start and the end and python has
built into it certain tools and certain
assumptions that if it detects that
there is a comment using this dock
string format triple quotes on the left
and the right it will assume that that's
indeed the doc mentation for that
function and it turns out in the pyth
python ecosystem there's a lot of tools
that you can then use to analyze your
code automatically extract all of these
document strings for you and even
generate web pages or PDFs of
documentation for your own function so
there's these conventions via which if
you adhere to them you can start
documenting your code as for other
people by generating automatically the
documentation from your own code without
writing something up from scratch man
manually now it turns out if your
function uh does take arguments and
perhaps does a bit more there are
multiple conventions for how you can
document for the human programmers that
might be using your function whether
it's you or a colleague or someone else
on the internet to actually use these
doc strings to standardize the
information they're in so you might see
this instead using these same triple
quotes above and below now you might see
your one sentence uh one sentence
explanation of the function meow
meow and times uh sometimes depending on
the style in use it might actually still
be on the first line but with a blank
line below it but I'll keep everything
uniformly indented and this is a
convention used by some popular python
documentation tools as well you would
say syntax like this Pam n colon and
then a description of what n is number
of times to meow then colon Type n colon
int which just indicates that the type
of n is an integer then if this function
could actually raise an exception you
can document that too and actually it's
not really well it's arguably my mistake
here if n comes in as an argument and is
not in fact an INT maybe it's a float or
a string or something else the
multiplication sign here is not going to
work it's not going to multiply the
string it's going to trigger what I know
from experience to be a type error so
I'm going to go ahead and proactively
say in my own documentation that this
function technically if you use it wrong
could raise a type error even though I'm
hinting up here with this annotation
that you should pass in an INT again
python doesn't enforce that so if you
pass in a float this might in fact raise
this function a type error and so that
might happen if n is not an INT and then
lastly I might say for clarity sake for
other programmers this function returns
a string of n meow one per line and the
return type of that value R type is
going to be
now all of this syntax here as I've used
it is not python per se this is a
convention known as restructured text
which is a form of markdown like
language that's used for documentation
for websites for blogs and even more but
it's one of the popular conventions
within the world of python to document
your own functions so this does not have
anything to do fundamentally with type
hints type hints are a feature of python
what I'm doing here is just adhering to
a third party convention of putting in
between a Python doc string from the
start to the end a certain standard
format so that these third-party tools
can analyze my code for me top to bottom
left to right and ideally generate
documentation for me it can generate a
PDF a web page or something else so that
I or my colleagues don't need to not
just only write code but also manually
create documentation for our code we can
keep everything together and use tools
to generate the same for us any
questions now on these dock strings
which again are a Convention of
documenting your own code often
following some standard syntax yeah so
when you say like you would document it
and put it in a PDF is the purpose of
doing this to kind of like publish it
and share your function so other users
can use it absolutely in the past when
we have installed some thirdparty
libraries for instance cow a few weeks
back call that I showed you what
functions it had but if you read the
documentation you might actually see
that uh it was documented for us by the
author of that program now I don't
believe they were using this particular
syntax but it was definitely useful for
you and me to be able to read some web
page or PDF telling us how to use the
library rather than wasting time reading
through someone else's code and trying
to infer what functions exist and how to
use them it just tends to be much more
developer friendly to have proper
documentation for our own code or
libraries as as well other questions
yeah um when with Doc strings when you
when it's used to generate like a PDF or
whatever does it does it include uh any
of the code so if you're referencing in
the in your in your comment uh if you're
referencing the code in the comment
itself might not make sense without
seeing the code does it does do these in
include it short answer you can do that
not in the convention I'm using here but
there's actually a clever way to write
in your doc strings sample inputs to
your functions and Sample outputs for
your functions and if you use a
different tool that we've not discussed
that tool will run your code using those
sample inputs it will check that your
outputs match your sample outputs and if
not the program will yell at you saying
you've got a bug somewhere so this is
just another way where you can use doc
strings to not only document but even
catch errors in your code this has been
a lot and there's a bit more to go why
don't we go ahead here and take a five
minute break and we resume we'll take a
look at yet another feature of python
yet another library to write code faster
all right suppose we want to modify this
meow program to actually take its input
not from the input function and the
blinking prompt but from the command
line recall in our discussion of
libraries that you could use something
like cy. RGV to get at commandline
arguments that a human has provided when
you're running your program so why don't
we whip up a version of meow that uses
commandline arguments instead of again
input so I'm going to go ahead and
delete what we've done here thus far and
let me propose that we import CIS as
we've done in the past and let's do this
how about if the user does not type any
command line arguments then my program
will just meow once just so that it does
something visually interesting otherwise
let's also give the user an option to
specify how many times I want the cat to
meow so let's start simple let's first
of all go ahead and do this if the
length of cy. argv equals equals 1 that
is the user only typed the name of the
program and nothing else after the uh in
their command then let's go ahead and
just print out one meow like this uh
else for now let's go ahead and print
out something like this else go ahead
and print out let's say usage for the
program which will be usage of meow. py
just so that the user knows that the
program itself is called meow. py all
right now let me go down to my terminal
window and start to type python of meow.
and at this point notice that the length
of cy. argv should indeed be one why
well python the name doesn't end up in
cy. arv at all ever but meow. Pi the
name of the file does and it's going to
go in cy. argv 0 but that's only one
element so the length of this thing is
one there's nothing more to the right so
when I hit enter now we should see
indeed one meow if I don't cooperate
suppose I do something like meow's three
enter then I'm going to see a reminder
that this is how you use the program and
this is a common convention to literally
print out the word usage a colon then
the name of the program and maybe some
explanation of how to use it so I'm
keeping it very simple but let's be a
little fancier what if I really wanted
the user to type in maybe not three but
something more sophisticated and in fact
when uh controlling programs from the
command line it's very common to provide
what are often called switches or Flags
whereby you pass in something like
dashn which semantically means this
number of times then off in a space and
then something like the number three
this still allows me to do other things
at the command line if I want but the
fact that I've standardized on how I'm
providing command line arguments to this
program with dashn three is just a more
reliable way now of my program knowing
what does the three mean it's a little
less obvious if I just do meow. ppace 3
well what does the three mean at least
with syntax like dn3 especially if
you've read the documentation for this
program ultimately oh dashn means number
of times got it it's a way of passing in
two additional arguments but that have
some relationship between them so how do
I modify my program to understand- N3
well if I'm using CIS like this I could
do this L if the length of cy. argv
equals this time three because notice
there's one two three things at my
prompt so cy. arv 0 1 and two three
things total separated by spaces if
equals 3 and let's be safe and cy. arv
bracket 1 equals equals DN then let's go
ahead and do this let's go ahead and
convert uh cy. arv of
two to an integer and assign it to a
variable for instance called n and then
let's go ahead and do this for uh
underscore in the range of n let's go
ahead and print out some of these meaps
now there's still an opportunity maybe
to consolidate my print lines with meow
but for now I'm going to keep these
ideas separate so I'm going to handle
the default case with no arguments up
here as before and now more
interestingly I'm going to do this to be
clear I'm going to check if the user
gave me three command line arguments the
name of the program- n and a number if
indeed the second thing they gave me in
cy. arv of1 equals equals uh dasn then
I'm going to assume that the next thing
CIS V of two is going to be an integer
and I'll convert it to such and store it
in this variable n and now just using a
loop I'm going to print out meow that
many times all right so it's kind of a
combination of our earlier focus on
Loops our earlier focus on command line
arguments just creating a program that
allow me to claim is representative of
how a lot of command line programs work
even though we've typically not used
many like this but it's very common to
configure a program one you're about to
run it at the command line with
something like these command line
arguments like dashn or Dash something
else now I'm going to go ahead and hit
enter and I think I should see indeed
three meows by contrast if I do two at
the end I should see two meows if I do
one I should see one meow and frankly if
I just omit this all together I should
see one meow as well because that was my
default case earlier and now let me
allow us to uh assume that this program
eventually gets more more complicated
right let's imagine a world where I
don't want to support just dasn maybe I
want to support- a and-b and- c and d d
and a whole lot of others or heck at
that point I should maybe give them
words so maybe it's Das Dash number it's
indeed a convention uh in Computing
typically to use single dashes with a
single letter like n but use double
dashes if you're actually using a whole
word like number so the command line
argument might be dhn or maybe it's Das
Das number but you can imagine just how
complicated the code gets if now you
want to support dn- A- B- C and so forth
you're going to have to be checking all
over the place and what if they come in
a different order you're going to have
to check is dashn first or is it second
or is it third or is it fourth I mean
this just becomes very painful very
quickly just to do something relatively
simple like allow the user to pass
command line arguments into your program
well this is why as always there exist
libraries and another library that comes
with python that's probably worth
knowing something about is this one here
called ARG parse in fact with a lot of
the tools I myself or cs50's team writes
in Python we very frequently use arars
whenever they are more complicated than
a lot of our class demos and a little
more similar to this one where we want
to allow the user to pass in
configuration options at the command
line and by supporting things like dashn
or- a or- b or- c arars is a library
that per its documentation just handles
all all of this parsing so to speak this
analysis of command line Arguments for
you automatically so you can focus on
writing the interesting parts of your
program not the command line arguments
part so how might we use this well let
me go back to vs code here let me clear
my terminal window and let me propose
that I rewrite this using not CIS but
actually using ARG parse and I'm going
to start a little simple and then build
back up so let me throw all of this away
for now and instead import ARG parse uh
ARG parse stands for argument parser to
parse something means to read it uh kind
of pick it apart to analyze it so this
is indeed going to do just that for me
now let me go ahead and do this and for
this Library it's helpful to know a
little object-oriented programming like
we all now do I'm going to create a
variable called parser I could call it
anything I want I'm going to set it
equal to the return value of ARG parse
dot ARG you parser with a capital A and
a capital P A Constructor for a class
called argument parser that comes with
python itself within in this Library
here now I'm going to configure this
argument parser to know about the
specific command line arguments that I
myself want to support in my program so
I'm going to do this parser do addore
argument so that's apparently a method
in the parser object I'm going to add an
argument of- N Easy enough now I'm going
to go ahead and actually parse the
command line arguments I'm going to do
args or I could call the variable
anything I want parser dop parse ARS and
by default parse ARS is going to
automatically look at cis.org V for me I
don't need to import CIS myself I can
leave the argument parser uh its code to
import CIS look at cy. argv and figure
out where dashn or anything else
actually is and what's nice now because
this line of code here results in the
parser having parsed all of the command
line arguments I now have this object in
this variable called args inside of
which are all of the values of those
command line arguments no matter what
order they appeared in not such a big
deal when I've only got one because it's
only going to go in one place at the end
but if I've got- n- A- B- C you could
imagine them being in all different
orders they definitely don't have to be
alphabetical the user should be able to
type them in any order they want that's
better for usability ARG parser is going
to figure all of that out for me and all
I have to do now is this if I want to
iterate over that many uh numbers of
arguments and that many Ms rather I can
do this 4core in the range of the int
conversion of args do n so dot is the
syntax we kept using to access things
like properties inside of an object and
that's what args is it's an object
returned by the parse ARS function form
me I'm going to go ahead now and print
out quote unquote meow this many times
so it's not super simple like these are
three new lines of code I need to write
and rather understand but it's already a
little simpler and more compact and my
if and my L if and my ores and my ANS
and all of that Boolean logic it's
handling a lot of this for me so if I
didn't make any mistakes let me run
python now of meow. enter and I did make
a mistake here I did make a mistake
what's what's wrong here now what's
wrong well I definitely didn't run it
the way I intend so
dhn3 enter so it does work but if I
don't cooperate this actually seems to
be a worse version if I don't pass in
dhn and a number it just errors with a
type error int must be a string none is
what came back so there's clearly an
error here but the library is more
flexible I can actually provide some
documentation on how to use this thing
so how do I know how to use this well
typically it's conventional in Python
and in a lot of programming environments
to run a program with a special argument
DH or Das dashel and almost always I
will claim you'll then see some kind of
usage information indeed that's what I'm
looking at now I just ran python of
meow. space- I'll do it again let me
clear my screen and this time do d-el in
English enter and I see the same thing
it's not very useful at the moment it
just shows me what the usage is up here
and this is kind of interesting this is
a standard syntax Inu Computing and
we've kind of seen it in Python's
documentation before this just means
that the program's name is of course
meow. pie square brackets as almost
always in documentation means it's
optional so I don't have to type-h but I
can I don't have to type-n and another
value but I can and then down here is
some explanation of these options and
more verbally showing me that I can also
do Dash dasel and not just Dash but this
is so generic this has nothing to do
with my program this is not going to
help my users when I actually release
this software for the world so let me go
ahead and improve it let me add a
description to my argument parser that
the humans will see meow like a cat
quote unquote is going to be the value
of this named parameter called
description and let me also add a help
parameter to my dashn argument that just
explains what dashn means number of
times to meow quote unquote I'm not
going to change anything else but I am
going to go back to my terminal window
and run python of meow uh I'm going to
run python of meow. py-h or equivalently
d-el and now notice that this is a
little more user friendly if I scroll up
we still see the same usage but there's
a quick sentence in English of
explanation that this program meows like
a cat and if I look at the options now
oh that's what N means it's the number
of times to meow and this capital n a
middle variable if you will is just
indicating to me that I need to type a
number by convention after the lowercase
dasn so it would be nice though all that
said if my program still didn't just
break when I run it without any command
line arguments right ideally my program
would handle this just like my manual
version did when I used cy. Arvy myself
so we just need to add a little more uh
functionality to this library and if I
read the documentation I'll see that add
argument takes yet another named
argument if you want you can specify a
default value for dashn for instance one
and I'll do that there and you can
further specify that it's got to be an
INT and what this will additionally
allow me to do is if I tell AR parser to
make sure that the value of dasn is an
INT I don't need to do the conversion
manually I can just trust down on line
seven that when I access the property
called n inside of my args object it's
going to be automatically an INT for me
and again this is the value of a library
let it do all of the work for you so you
can get back to focusing on the
interesting project at hand whatever
problem it is you're trying to solve
like in this case granted not that
interesting but meowing like a cat let
me go ahead now and run python of meow.
and hit enter this time no arguments and
now it meows why because I specified
that if I don't as a user specify dashn
it's going to have a default value of
one apparently and I don't have to
convert that value from a stir to an INT
because I told AR parser please just
make this an INT for
me any questions now on AR pars were
really this principle of just
Outsourcing the commodity stuff the
stuff that everyone's program eventually
needs to do so that you can focus on the
juicy part yourself what does ARS that
end contain what does args do n contain
it contains the integer that the human
typed after a space after
dashn good question other
questions yeah did uh uh the the when
you specify the type um for the
argument uh what happens if does that
basically handle the ex C if if the user
inputs a string in this case a really
good question suppose that the human
does not type a number and therefore not
an INT well let's see what happen so
python of meow. dasn dog where dog is
obviously not a number enter and voila
we see an automatically generated error
message little cryptic admittedly but
I'm seeing a reminder of what the usage
is and a minor explanation of what is
invalid about this and again this is
what allows you this is what allows me
to like focus on writing actual code we
care about and just letting the library
automate some of this stuff for us all
right well allow me to propose now that
we take a look at one other feature of
python that we've seen before but it
turns out we can use it even more
powerfully as our programs become more
sophisticated and the problems we're
trying to solve themselves become more
involved let me go ahead and re uh turn
to vs code closing out meow. and
creating a new file for instance called
unpack. so code of unpack. py and let me
just remind us like what we mean by
unpacking because this is actually a
feature of python that we've seen before
for instance suppose that I write a
program that prompts the user for their
name like David Space men wouldn't it be
nice if we could C of sort of split the
user's name into two separate variables
and when we've done this in the past
we've done it in a few different ways
but one of them involved unpacking a
single value uh that comes back from
that like a list or uh some other data
structure and putting it immediately
into two variables so let's do this here
let me go ahead and call uh the input
function asking someone what's your name
question mark then let me go ahead and
just split a little naively on a single
space so I'm assuming that the only
users at the moment are people like me
David Space men no middle names no
multiple names it's just one and two
which itself could be buggy for other
users but for now I'm keeping it simple
just to remind us that I can now unpack
that return value with something like
first underscore last equals the return
value of input and now I can go ahead
and do something like this like printing
out with an F string hello comma and
then in curly braces first if I just
want to greet myself or any other user
as hello David without the last name and
frankly if I'm not using the last name
recall that a python convention is just
to name it underscore to make clear that
you know you're not using that value but
it does need to be there because you're
unpacking two values at once so if I run
this it won't be all that unfamiliar I'm
just going to run now python of unpack.
I'll type in David maen which has a
single space and there we have it hello
comma David well it turns out that
there's other ways to unpack values and
there's other features that python
offers especially when it comes to
defining and using functions and this is
slightly more intermediate functionality
if you will that's useful because you
can start to write even more elegant and
Powerful code once you get comfortable
with syntax like this so let me go ahead
and propose that we not just play with
Hello uh uh hello names anymore but
instead do something maybe involving
some coinage again so maybe not dollars
and cents but maybe again as in the past
some gallions and sickles and canuts
with among which there's a mathematical
relationship as to how many of those in
the Wizarding World equal each other and
let me go ahead and do this let me
Define a simple function called total
that just tells me the total value of
someone's vault in grots The Wizarding
Bank based on how many gallan sickles
and canuts that they have which again
are currencies from The Wizarding World
as opposed to our actual human world so
this total function might take a
variable like gallions and sickles and
canuts like this and then it's going to
return the formula which I admittedly
had a look up myself and it turns out
that the formula for converting gallions
and sickles to Kuts would be this
gallions times 17 plus sickles then
times all of that by 29 and then add in
the individual canuts not sure in what
detail this came up in the uh books or
movies but here we have it the official
formula all right now let's go ahead and
do this let me go ahead and call the
total function with just some sample
inputs suppose that someone like Harry
has 100 gallions 50 sickles and 25
canuts let me go ahead and print that
out on the screen all right well if
total returns an integer which I think
this arithmetic expression will do let
me go ahead and store uh rather pass the
return value of total to print and then
just for clarity let me write canuts at
the end so I know that the unit of
measure here is indeed canuts in total
all right now let me go ahead in my
terminal window and run python of
unpack. and hit enter and it turns out
mathematically that if I got my math
correct 100 gallions plus 50 sickles
plus uh 25 canuts equals in total
50775 canuts just avoiding having to use
our own human currency here but I'm not
doing anything along the lines of
unpacking at least just yet let me
propose now that I do this just for the
sake of discussion let me propose that I
leave the total function as is but let
me go ahead and just store all of my
coins in a list so coins in order from
left to right 100 50 25 it just because
for whatever purposes in this story I
have all of my coinage in a a list in
this order kind of a a purse or wallet
of sorts well how can I pass this in
well I'm not going to hardcode the same
values twice just for the sake of
discussion how could I pass in the
individual elements of a list to my
total function well of course I could
treat this list as I always do uh using
numeric indices by doing coins bracket
zero coins bracket one coins bracket two
so this is old school stuff with lists
if I've got a list called coins and
there's three elements the indices or
indexes of those elements are zero 1 and
two respectively from left to right so
all I'm doing here now is passing in the
first element from that list as gallions
the second element of that list as
sickles and the third element of this
list as my canuts and that lines up with
of course the signature of this function
which as total expects that I've passed
in those three things in that order left
to right all right let me go ahead and
run just to make sure I haven't broken
anything unpack. piy and hit enter and
the math still checks out but this is
getting a little verbose a little
verbose and wouldn't it be nice if I
could just pass the list of coins to
this total function wouldn't it be nice
if I could just say something like this
coins but let me pause and ask the group
why would this not actually work as
is it technically is passing in all
three but why would I get some kind of
error when I run this Eric uh because
you are passing a list to gallion yeah
I'm passing a list to gallion and
nothing for sickles and canuts and
notice those don't have default values
there's no equal signs on that first
line of code code which means Python's
not going to know what value should be
assumed there so it just seems like it's
not going to work plus it's the wrong
type as Eric notes it's a list and it's
not an integer as it was before so let's
actually run this incorrect version
python of unpacked High enter type error
and that is probably what you might
expect like I'm messing up with the
types here and I I'm required to pass in
two positional arguments sickles and
canuts that were not even passed so I've
definitely aired here but it certainly
seems fortunate if the only solution to
this is to do what I previously did
which is index into the first element
index into the second element index into
the third like you can imagine with
bigger fancier functions that take even
more arguments this is going to get very
verbose and honestly very vulnerable
potentially to just mistakes typos on my
part but here too is where you can do
what's known again as unpacking a value
in Python right now a list is kind of
packed with multiple values my current
list has these three values one 100 50
and 255 respectively but they're all
packed up in this one list wouldn't it
be nice if I could unpack that list just
like I previously unpacked the return
value of the stir classes split function
into multiple things too and indeed I
can do just that python actually allows
me to pass in not coins but Star Coins
so if you use a single asterisk at the
beginning of your variable that will
unpack it and it will take one sequence
in this case coins of size three and
explode it if you will unpack it into
three individual arguments no commas are
needed python just handles this for you
but the effect of passing in Star Coins
is to pass in the individual members of
that list which in this case are going
to be 100 50 and 25 respectively which
is perfect because now it's going to
line up with gallions sickles canuts
respectively so now when I run python of
unpack. py we're back in business and
the math checks out but I've kind of
cleaned up my code by just introducing
this new symbol which we've used of
course in other context for
multiplication and the like but now it's
also used for unpacking in this way
questions on what we've just done it's a
single operator but it's already quite
powerful because it allows us to take a
data structure and unpack it and pass it
in
individually does that work for um uh
tles sets dicks dictionaries as well
tupples
yes sets I don't know R Shin I don't
know if order is
preserved no oh is that no it does not
or you know you're
checking order is not preserved so it
wouldn't work with
set does not work with set does not work
with set sorry I'm verbally Googling
here just to save us some keystrokes so
it would work for um enumerations that
where order is indeed preserved and
we'll see another example in a moment
where it actually can be used in a
different way for dictionaries which
nowadays do preserve order other
questions on unpacking in this way yes
hi hello uh can you use unpacking to get
the value uh for example 10 + 50 +
25 uh instead of a for Loop and then
result plus short answer no if you want
the individual values you should be just
indexing in this case into those
specific locations um this is returning
multiple values the equivalent of a
comma separated list so you would use
the earlier approach if you cared about
the individual locations how about one
other question on unpacking what if uh
we have declared we we declar some
default values and if you use this Aster
coins will it over right or will it uh
skip it good question if I heard you
right what if for instance the list has
four values like this here and you're
still unpacking it when it's only three
that's expected well let's try it python
of unpack. piy enter another type error
this time it takes three positional
arguments but four were given so the
onus is on us as the programmer not to
do that in this case so potentially
fragile but avoidable if I'm controlling
the contents of this list in fact let me
propose now that we take a look at
another variant of this whereby we use
not just position IAL uh arguments
whereby we trust that the first is
gallions the second is sickles the third
is canuts suppose that we actually
passed in the names as we're allowed to
do in Python and then technically we
could pass them in in any order and
python would figure it out using named
parameters instead well how might I do
this well it's going to be a bit of a
regression at first so let me get rid of
this list here let me change this now to
just manually pass in the values I care
about gallions I want to still equal 100
sickles I want to equal 50 and nuts I
want to equal 25 so this is old school
parameter pressing it's no longer
positional I'm explicitly specifying the
names of these arguments but that's just
going to work because that's exactly
what the names of these parameters are
in my total function as before let's
make sure I nonetheless did not break
anything let's run python of uh of
unpack. piy enter and there we have it
still
50775 canuts well once you start giving
things names and values names and values
that probably should bring to mind one
of our most versatile data structures in
Python and even other languages that of
a dictionary remember that a dictionary
is just a collection of key value pairs
names and their respective values so
this kind of opens up an opportunity
what if I did this what if I actually
had for some reason in my program on a
variable as before called coins but
instead of making it a list of three
values like before what if it's a proper
dictionary so what if it's gallions
quote unquote colon 100 for 100 of those
sickles quote unquote and 50 of those
and Kuts quote unquote 25 of those each
of those separated by uh colons and let
me fix my square brackets to this time
be curly braces which recall is the
symbol we use for dictionaries or dict
objects in Python so now I have a
dictionary called coins not a list it's
a collection of keys and values three
keys gallions sickles canuts and three
values 100 50 25 respectively if I were
to now pass these individual values into
my total function I could do it as
always with my dictionary so I'm doing
it old school now coins is the name of
my dictionary I index into it not with
numbers like with lists but with words
so gallions strings like this uh coins
quote unquote sickles in square brackets
there and then lastly coins square
brackets quote unquote canuts so it's
getting it's verbose again like this is
not maybe the best road to go down but
we'll backpedal in a moment this is just
how if you happen to have all of your
coins stored in a dictionary you could
pass the gallion sickles and canuts into
your function respectively let's make
sure I didn't break anything let's rerun
python of unpack. py and we're still
good now how could we get to a situation
like this well as always imagine this
program is a little longer than this one
here and somehow you're using a
dictionary maybe just to keep track of
someone's purse or wallet like how many
coins of each type that they have and as
such it's perfectly reasonable to use a
dictionary but then you want to print
out the total and darn it if that total
function does not expect a dictionary so
you cannot just do something nice and
simple like pass in coins for reasons we
saw earlier that would be a type error
total expects three arguments three
integers you can't just pass in a
dictionary but if that's the data
structure you're using to store the
person's purse or wallet well it's kind
of unfortunate that we have this clash
between these data types well here's
what we can do we can't pass in coins
because watch if I try doing that and
run python of unpack. we're getting
another type error missing two required
positional arguments sickles and canuts
I have to pass in three things but
wonderfully python allows you to unpack
dictionaries as well for a dictionary
you don't use a single as risk you use
two and what this syntax has the effect
of doing is passing in three values with
names it has the effect of passing in
gallion equals 100 comma sickles equals
50 comma canuts equals 25 and so it has
the similar effect to the list unpacking
but that just passed in the values 100
50 25 separated by commas in effect when
unpacking a dictionary it passes in the
keys and the values separated
conceptually with equal signs just like
our function expects so if I now run
python of unpack. again we're still good
but we've tightened our code up again
and now I'm giving myself yet another
option I can either store a Wizard's
purse or or uh wallets in their uh in a
list as we did earlier or I can store it
a little more vers uh with even more
specificity using a dictionary instead
and so do be clear let me rewind star
star coins is the same thing if I rewind
a little bit to our first example of
named arguments is equivalent to what
I've highlighted here when you unpack a
dictionary it passes in all of the keys
and all of the values much like this
syntax here but let me tighten it up and
go to where we left off questions now on
unpacking can we have a in this
dictionary uh can we have instead of
having a con
name value pair can we have a variable
number of you know name value pairs
short answer yes you can have more than
three key value pairs as I have here but
it's not going to work unpacking it if
the total function is expecting only
three so if I were to add something here
like let me introduce pennies to The
Wizarding World and suppose I have one
penny for instance and now I run this
same code python of uh unpack. piy where
back to a type error again whereby I got
an unexpected keyword argument pennies
because that is not expected by the
total function we will see in just a
moment wonderfully a solution though to
that but for now it does not work other
questions on unpacking with dictionaries
or lists in list in list values we gave
the same number of arguments and we
declared a default value in the function
now if you use this as trick will it
overwrite that value or will it skip it
skip that default value a good question
if you if we did have default values up
here for instance equals 0 equals 0
equals zero the upside of that recall
from our discussion of arguments to
functions a while back is that now you
don't have to pass in all of those
values they will default to those zeros
therefore you could pass in fewer than
three values either using a list or a
dictionary that's unpacked in this
scenario I deliberately did not do that
because I wanted us to encounter this
specific error in this case but you
could absolutely go back and add those
defaults so it turns out that this
single asterisk or this double asterisk
is not only used in the context of
unpacking that same syntax is actually
used as a visual indicator in Python
when a function itself might very well
take a variable number of arguments that
is to say a function can be vartic which
means that it doesn't necessarily have
to take say three arguments specifically
even if they do or don't have default
values it can take maybe zero or one or
two or three and it turns out the Syntax
for implementing the same idea is quite
similar in spirit in fact let me go back
to vs code here and let me propose that
we start over with this code and get rid
of our notion of gallions and sickles
and canuts and do something just a
little more generic just so that we've
seen the Syntax for this suppose that I
Define a function as follows Define a
function let's call it f and that
function is not going to take a specific
number of arguments but a variable and
so I'm going to go ahead and use this
syntax here star args which indicates
that this function is indeed very adic
it takes some variable number of
positional arguments positional in the
sense that they go typically from left
to right but I don't know how many just
yet I want to support suppose that I
additionally want to support some number
of keyword arguments that is named
parameters that can be called optionally
and individually by their own name well
the convention syntactically here would
be to use two stars and then K W ARS I
could call args or KW args anything else
that I want but a convention you'll
frequently see in Python's own
documentation is that when you have
placeholders like this for some number
of arguments and some number of keyword
arguments um the world tends to use args
and key uh KW args well inside of this
function let's do something super simple
just for now let me go ahead and print
out literally quote unquote positional
just to indicate to myself while
wrapping my mind around what's going on
here what the positional argument arents
are and let me quite simply print out
those args this is not something you
would typically do you don't typically
just take in these arguments and print
them no matter how many there are I'm
just doing this diagnostically for now
to show you how the syntax works now let
me go ahead at the bottom of my file and
I won't bother with a main function this
time so we can focus only on this
function f let me go ahead and just call
F with three arguments I'll use the same
arguments as before but I'm didn't
bother giving them names just yet like
gallions and sickles and canuts and the
like so what do I have a program that no
matter what calls this function f but it
first defines F at the top of the file
is taking some number of positional
arguments some number of named arguments
and for the moment I'm just printing out
the positional ones let me go ahead and
in my terminal window run python of
unpack. piy and hit enter and you'll see
that the positional arguments passed in
are apparently this a sequence 50 25 but
notice this if I clear my terminal
window there and pass something else
like five a fourth argument previously
if I try to change the number of
arguments I'm passing in to my total
function which was only defined as
taking three I would have gotten a type
error some visual indication that no you
can't pass in more or fewer arguments
than is actually in the function's
definition but now watch if I run python
of unpack. Pi this time passing in 15 25
and five a fourth argument all four of
those went through just fine I can get
rid of all of those but one for instance
now rerun my program after clearing my
screen and now I'll see just one
argument here and even though there's a
comma and nothing after it this is
actually the syntax when seeing a a
tupple in effect whereby The Comma just
indicates this is indeed a list but
there's only one element therein well
let's get a little more curious too let
me go ahead and Rewind here to where we
started with just those three values and
this time let me go ahead and print out
my named argument so to speak which is
args but KW args again the positional
args in this syntax come first the named
arguments KW ARS come second uh that's
uh what python prescribes so now let me
go ahead and not pass in just these
numbers let me go ahead and pass in
actually named arguments so let me do
something now more specifically like
gallions equals 100 and sickles equals
50 and canuts equals 25 I'm not going to
bother doing any math with total I just
want to poke around right now at this
functionality of having a variable
number of arguments and what's neat now
is if I run python of unpack. and hit
enter no problem what KW args is is
automatically a dictionary that contains
all of the named arguments that were
passed to my function which is to say
when designing your own functions if you
want to support more than one argument
maybe more than two or three or four
maybe a variable number of arguments
indeed you can support both a variable
number of positional arguments that are
just value comma value comma value or
any number of named arguments where you
actually put the name of the parameter
equals the value and then maybe a comma
and some more of the same so now it
turns out we have seen this before uh in
some of the functions we've used to date
we didn't necessarily see it called args
or necessarily see it called KW ARS but
we have seen at least one example of
this in the wild recall our old friend
print which we've been using now for
weeks and when we first looked at the
documentation for print way back when it
looked a little something like this the
first argument to print was objects and
I waved my hand at the time at the
asteris that was at the start of that
variable name but then we had sep for
separator the default value of which was
a space we had n the default value of
which was a new line and then some other
named arguments that we waved our hands
at then and I'll again do now but what
you can now perhaps infer from our
emphasis on these asterisks today the
single stars or the double stars is that
you know what this is the convention in
Python's documentation to indicate that
print takes a variable number of
arguments so if we were to look at the
actual implementation of the print
function implemented by Python's own
authors it might very well look
something like this deaf print and then
the first argument would be star objects
thereby indicating that print takes a
variable number of arguments the next
one of which might be sep equals quote
unquote either using double quotes or as
in the documentation single quotes too
the next one of which might be end the
default value of which is a new line and
then some of those other named arguments
that we've not looked at as well and
then maybe inside of the print function
implemented by the authors of python
maybe there's a for Loop like for object
in objects that allows them to iterate
over each of those variable number of
objects and print each of them and this
is why in programs past you and I have
been able to do just print open
parenthesis close parenthesis with
nothing inside or you and I have been
able to print out something like Hello
World a single string inside of those
parentheses or you and I have been able
to do a single string hello and then
another string quote unquote World
thereby passing in two arguments or even
more so we've long had this ability to
use vartic AR uh functions whereby you
can pass in a variable number of
arguments what you now have via this
args and KW ARG syntax but again they do
not need to be called that is the
ability using that star or two stars to
implement those kinds of functions
yourself my own F function a moment ago
did not do anything all that interesting
but it hints at how you could if in the
future you have a use case for taking
zero or one or more of either type of
argument any questions
now on these types of
arguments what will happen if you print
quarks and the argument is
like a list ah so what would happen if
you print the argument like it's a list
so I think we saw that if I roll back in
my history here to when I had that F
function which I called f just to be
very generic just so we could play
around with the syntax this is what I
had here so this is a um I passed in 100
comma 50 comma 25 that gets
automatically stored in args and when I
run it you can actually see that
sequence of values by running python of
unpack up high there is that sequence
all in the form of one single variable
I'm printing it just for Diagnostic
purposes this is not really a useful or
pretty program but it hints at how we
can access that whole sequence of values
other
questions on this approach here can we
pass kws from one function to another
function absolutely you can pass either
of those to another function which you
might want to do if you want to wrap
another function provide some additional
functionality but still pass in all of
the supported arguments to the
underlying function as
well all right how about this next it
turns out that a few other tools we can
add to your toolkit relate to the types
of programming models that python
supports we started out quite some time
ago focusing really on procedural
programming in Python whereby we wrote
code top to bottom left to right
defining some functions or if you will
procedures along the way defining Vari
and having side effects and assigning
values as needed but we then eventually
introduced or really revealed that
python is also very much object oriented
and a lot of those variables a lot of
those types that we were using all that
time were in fact objects objects that
were uh came from certain classes and
those classes were templates of sorts
blueprints via which you could
encapsulate both data and functionality
therein well we also saw along the way
some hints of a third Paradigm of
programming that python also to some
extent it support
which is known as functional programming
whereby functions are ever more powerful
in that they tend not to have side
effects no printing or changing of State
globally but rather they're completely
self-contained and might take as inputs
and return values and that's generally a
paradigm we saw when we started sorting
things particularly with functions like
our sort function or Lambda function
when we passed in the function we wanted
to use to sort a list way back when well
it turns out python has other fun
functionality that is reminiscent of
functional programming and indeed is a
powerful way to solve problems a little
more differently still let me propose
this let me propose that I whip up a new
program here in vs code by closing our
unpack. and this time creating another
program called yell suppose the goal at
hand is to implement some program that
allows the user to pass in input and
then it yells the response by forcing
everything to uppercase my apologies to
those with with headphones there I'll
I'll modulate so let me go ahead and run
code of yell. pi and within yell. Pi
let's go ahead and Implement a program
that really does just that let's go
ahead and Define a main function up here
and let's assume for the moment that
this yell function already exists and
yell something like this is cs-50
properly capitalized not in all caps now
let's go ahead and implement this yell
function with deaf yell it's going to
take for now a single uh word or phrase
uh and let's go ahead and I'll call it
phrase here and I'm going to go ahead
and just print out the phrase. uper so
phrase. upper is going to force the
whole thing to uppercase and as usual
down here if the name of this file
equals equals quote unquote uh main then
let's go ahead as always and call Main
so let's just run this but for the most
part it should be fairly straightforward
when I run python of yell. py this is
cs50 is yelled on the screen all right
that's nice but it's not great that yell
only expects a single uh expects a
single phrase wouldn't it be nice like
print if I could pass in one phrase or
two or three or really multiple words
more generally but as individual words
themselves so let me retool this a
little bit and change yel to take in not
a phrase but how about something like a
list of words so that ultimately I can
call Yell like this uh quote unquote
this inside of a list quote unquote this
inside of a list and quote unquote cs50
inside of a list I'm not going to bother
with typ pen answer annotations for now
but I'll just assume that yel has been
defined now is taking a list of words as
defined here but now I want to force
them all to lowercase so I don't quite
want to do something as simple as this
like for word in words I could for
instance print that given word and maybe
end the line with nothing right now but
I think if I do this python of yell. no
that's that's not right I haven't forced
anything to uppercase so let's fix this
well let's go ahead and do the following
let me go ahead and accumulate the
uppercase words as follows let me create
a variable called uppercase and
initialize it to an empty list using
square brackets or or more verbose list
syntax and now let me go ahead and
iterate over each of those words in
Words and for each of them let's go into
our uppercase list append to it the
current words uppercase version so this
is a way of creating a new list called
uppercase that is just appending
appending appending to that list each of
the current words in the loop but
uppercased instead and now just let me
go ahead and print out the uppercase
list this isn't quite right let's see
what happens here python of
yelpy okay it's not quite right because
I don't think I want those quotes or
those square brackets what am I seeing
I'm actually printing a list but but but
here's where some of our unpacking
syntax now can be useful I don't have to
change my approach to this problem I can
just unpack uppercase by adding a single
star and now let me go ahead and rerun
python of yelpy and now it's actually
just English there's no remnants of
python syntax like the quotes and the
commas and the square brackets I've now
unpacked this is cs50 as three separate
arguments to print so already now this
unpacking technique would seem to be
useful well it's a little unfortunate
that I now need to call Yell though with
a list of values in this way this is
just not the norm or at least it's not
nearly as user friendly as something
like the print function where I can pass
in zero or one or two or three or any
number of arguments why are you making
me for your yell function pass in only a
list well we can do better let's adopt
some of the new conventions we've
learned and let's go ahead and get rid
of the list by removing the square
brackets and let's just pass yel three
arguments now I don't want to do
something like change the definition of
words to take in like word one word two
like that's not going to scale and it's
not going to handle different number of
words but we have a technique now we can
say star args which will allow the yell
function to accept any number of
arguments and just for specificity let's
not call it generically arcs let's name
it something a little more
self-explanatory like star words this
just means I have a variable number of
words being passed in now I think I've
made a marginal Improvement let me run
this again python of yell. py this is
cs50 is in all caps but is just a little
better right because now I can treat yel
just like I've long treated print pass
in as many things as you want and print
will deal with it now my yell function
is just as powerful it would seem and
better still it also forces everything
to uppercase well it turns out python
comes with this function called map
whose purpose in life is to allow you to
map that is apply some function to every
element of some sequence like a list so
for instance if we want to force to
Upper case each of the words this is
cs50 in the list of words that's been
passed in well we essentially want to
map the uppercase function to each of
those values so using map in Python can
I do just that let me go back here to vs
code and let me propose now that I
reimplement this as follows I get rid of
all three of these lines here getting
rid of uh that Loop in particular let me
still declare a variable called
uppercase but let me set it equal to the
return value of this new function called
map map takes two arguments here in this
case the name of a function that I want
to map onto a sequence of values well
what function do I want to apply to
every word that's been passed in well it
turns out thanks to my knowledge now of
object-oriented programming I know that
in the stir class there is a function
called upper we've usually called it by
using the name of a string variable Dot
Upper open paren close paren but if you
read the documentation for the stir
class you'll see that the function is
described indeed as stir. uper I'm not
using parentheses open and close at the
end of stir. uper because I don't want
to call it now I want to pass this
function to the map function so that map
can somehow add those parentheses so to
speak and call it on every one of these
words and this is what map does quite
powerfully and is an instance indeed of
functional programming whereby I'm
passing to this map function another
function not calling it I'm just passing
it in by a reference of sorts and what
map is going to do for me is iterate
over each of those words call stir.
Upper on each of those words and return
to me a brand new list containing all of
those results together in one list it
completely obviates the need for me to
do this more manually using that list
I'm still going to print the whole thing
using star uppercase so that if I get
back a three a list of three uppercase
words I'm going to unpack them and print
them all out so let's run this again
python of yelpy enter and voila it's
still working but the code now is even
more tight uh even tighter than before
so it turns out there's another way we
can solve this problem in a way that's
even more pythonic or at least quite
common and that's using a feature known
as a list comprehension and it's a a big
phrase if you will but it refers to the
ability in Python for you to very easily
construct a list on the fly without
using a loop without calling a pendant a
pend but to do everything in one dare
say elegant oneliner so how can I go
about using this notion of a uh of a
list comprehension well let me go ahead
and do this in yelpy in vscode here let
me go ahead and change my Approach as
follows instead of using map which is
perfectly fine and correct in this way
let me just show you this other way as
well a list comprehension is the
opportunity to create a list like this
using square brackets like this but
inside of those square brackets to write
a python expression that in effect is
going to dynamically generate a brand
new list for you using some logic you've
written and the approach I might take
here is this if I want to store in this
list the uppercase version of every word
in that word list I can do this word.
uper for word
inword now this is a mouthful but I dare
say python programmers love this
capability of being able to Define on
the fly a list inside of which is any
number of values that you would
ordinarily at least as we've done it
construct with a loop and again calling
a pend and a pend in a pend but that
usually takes two three four or more
lines this list comprehension that that
I've highlighted here is now an
alternative way to create the exact same
thing a list inside of which are a whole
bunch of uppercased words which words
for each word in the words list that was
passed into yell is what ends up in this
list questions on this syntax here it
definitely takes a little bit of getting
used to because you've got like this
value on the left this function call
here you've got this Loop inside of the
square bracket
but if you become accustomed to reading
the code in this way from left to right
this means give me the uppercase version
of the word for each word in my words
list questions here on list
comprehensions uh can you do conditional
so also like if else or uh combine if L
if else indeed you can and let me come
back to that where we'll see an
opportunity to do things conditionally
but for now I'm just upper casing every
word in the list a good question other
questions yeah um is is this is this
functional programming or u i mean this
particular thing where you saying words
do upper for word in word not
necessarily this is more of a feature of
python I would say yeah map was uh one
uh very specific incarnation of thereof
our use of Lambda and passing it in as a
key attribute to the sort fun sorted
function a while back was an example and
we're about to see uh one other so we
can even use these list comprehensions
to filter values in or out of our
resulting list so in fact in vs code
here let me close yel up high and close
my terminal window and let me create a
new program here whose purpose in life
maybe is to take a same list of students
as before with a shorter version thereof
and just filter out all of the students
in Gryffindor so let me go ahead and
create a file called gryffindors dopy
I'm going to go ahead and copy paste
from before really my list of students
at least hermion Harry Ron and Draco
from the start here just so that I can
focus on uh one student who happens not
to be from Slytherin and what I'm going
to do here now if I want to filter out
only the Gryffindor students let me go
ahead and do this let me create another
variable called gryffindors which is
going to equal the following list and
this is going to be a bit of a longer
line so I'm going to proactively move my
square brackets onto two separate lines
and I'm going to create now a list
comprehension I want to do this I want
this new list called gryffindors to
contain every students's name for each
student in the students list but but but
if the students house equals equals
quote unquote Gryffindor so this is
nearly identical in spirit to what I
just did earlier to create a list
comprehension out of each of the words
passed to my yell function but here I'm
doing so conditionally and so I'm
borrowing inspiration from our focus on
Loops borrowing some inspiration from
our focus on uh conditionals combining
that into this same square bracket
notation so that what gryffindors
ultimately is is zero or more students
names and the names that are included
are the result of iterating over each of
those students and only including in the
final result these students whose house
happens to be Gryffindor so when I go
ahead and run this with python of
gryffindors dopy and hit enter you'll
see huh nothing actually happened here
well that's because I didn't finish the
program let me go and actually finish
the program with this how about for each
Gryffindor in Gryffindor plural and
better yet so that it's sensible that I
did all of this work in advance let me
go ahead and sort all of those names
with our familiar sorted function let's
go ahead now and print out each of these
gryffindors so now notice if familiar
with the books and the movies you'll
know that only three of these four
students are actually in Gryffindor and
if I run python of Gryffindor dopy there
we see Harry Hermione and Ron but now in
sorted order as well so that's just one
way we can solve this same problem using
not just a list comprehension but a list
comprehension that has this conditional
therein but there's yet other ways to
solve this same problem too and we come
back to some functional features of
python in addition to functions like Map
There's also this one called filter that
can be used to achieve the same effect
but with a more functional approach if
you will let me go back to vs code here
and with the same example let me do this
let me leave the original list up above
as before including Draco who's not in
fact from Gryffindor and let me
temporarily Define a function called is
Gryffindor that takes in as uh value
something uh like a student s and then
let's do this let's go ahead and say if
s quote unquote house equals equals
Gryffindor then go ahead and return
true otherwise go ahead and return false
now we've seen before conditionals like
this that are a bit unnecessarily
verbose I don't need to have a
conditional if I'm already asking a
Boolean question up here so I can
actually tighten this up as we've done
in the past and just return does the
student's house equal equal Gryffindor
either it does and it's true or it
doesn't and it's false I don't need to
explicitly return true or false I can
just return the value of that Boolean
let's go ahead now and do this I'm going
to create as before a variable called
gryffindors a list for all of my
Gryffindor students that equals to this
time the result of calling filter filter
takes at least two arguments here one of
which is the name of a function to call
is Gryffindor and I'm going to apply
that function to each of the elements of
this sequence here so similar in spirit
to map I'm passing in a function that's
going to be applied to each of the
elements in the sequence but map returns
one value for each element in the
sequence that's how we forced all of the
words to uppercase but if I want to
conditionally include a student in my
resulting gryffindor's list I can use
filter instead filter expects its first
function to be not something like stir.
upper but a function that returns true
or false tell me whether or not I should
include or not include the current
student from the final list and the
question being asked is do they live in
Gryffindor we're checking the
dictionary's house key for that answer
and so ultimately I think we'll be left
with something quite similar for
Gryffindor in the sorted ver let's do
for Gryffindor in gryffindors let's go
ahead then and print out the current
students Gryffindor name it's not going
to be sorted just yet but when I run
this version here python of Gryffindor
stpy and hit enter we're back in
business it's unsorted but we have
Hermione Harry and Ron but not Draco and
if you recall from a few weeks back if
we want to sort even a list of
dictionaries we can still do that too I
can call sort
on Gryffindor plural and I can pass in a
key and that key can have a Anonymous
function AKA a Lambda function that
takes in a student as input call it s
and then Returns the value s quote
unquote name if my goal is to sort by
indeed uh students own names if I go
ahead now and run python of griffindor
dopy I see the same list of students but
this time it's sorted so here we've seen
two approaches to this particular
problem of Gryffindor students whereby
we can either use something like a list
comprehension and inside of that list
comprehension do a bit of filtration
including an if conditional as I did or
we can take a more functional approach
by just using this filter function
passing into it the function that I want
to make these decisions for me and then
include only those for whom true is
returned any questions on either of
these two approaches uh yeah I just had
a question that if we write the code
like the previous version where
everything is stuffed into one light
what the if we check for the style of
the code then won't it have a don't it
have a problem with it because it's less
readable so would a formatter like black
have a problem with the style of some of
this code the previous one where the
everything was stupped into one line oh
a good question would something like
black have a problem with this code well
let me rewind to that version which was
using the somewhat
longer uh list comprehension
which looked like if we go far enough
back give me a few more undos which
looked like this ultimately let me go
ahead and run black on gryffindors dopy
and you'll see that I actually it
reformatted ever so slightly but I
proactively fixed this myself had I done
this and done it on just one line but I
knew that black might not like that it
would have fixed it for me so I just
proactively fixed it before writing the
code myself how about time for one other
question on gryffindors high in this
approach of using a list comprehension
or filter yeah when when using filter
instead of calling the function is
Ginder can you use it ER right there
inside filter can you use the function
is Gryffindor so you don't want to call
it like this because you don't want to
call it then you want filter to call the
function for you if that's what you mean
so I pass it in only by its name
instead no I me
if you can write the return as house
equals equals the inside F yes indeed in
fact so recall that we indeed used these
Lambda functions way back when when we
wanted to pass in a quick and dirty
function anonymously to allow sorted to
filter by a different key of a
dictionary we can do that here I can
actually take the essence of this is
griffindor function I can change the
name of this function in my filter call
to be another Lambda function passing in
an argument like s and returning exactly
that I can now delete my is Gryffindor
function all together and now when I run
python of gryffindors dopy I still get
the same answer and I've not bothered
defining a function only to then use it
in one and only one place well let me
propose too that we equip you with one
other tool for your toolkit namely
dictionary comprehensions as well and
admittedly the syntax is starting to get
even weirder but as you get more
comfortable with all of these Primitives
and others these are just tools that you
can optionally but perhaps powerfully
use to solve future problems down the
road and with a dictionary comprehension
we have the ability to create on the fly
a dictionary with keys and some values
without having to do it sort of old
school by com creating an empty
dictionary and creating a for Loop and
iterating over that Loop and inserting
more and more keys and values into the
dictionary we can rather do it all at
once so in fact let me go back to vs Cod
here and let me propose now that I do
this let me go ahead and initially do it
the oldfashioned way here as follows let
me go ahead and simplify and get rid of
the houses Al together so that we can
focus for now just on a list of students
names I'm going to go ahead and run
students uh I'm going to go ahead and
write students equals quote unquote
hermion quote unquote Harry and we'll
keep it even shorter this time quote
unquote Ron only those three students in
Gryffindor I'm going to now proactively
as we've done in the past give myself an
empty list so that I have something to
accumulate some answers to this problem
in and now I'm going to do something
like this for student in students so I
can iterate over each of them let's go
ahead and with the gryffindors list
append to it the name of the students so
quote unquote name and then student
which is indeed their name from that
list and now let's go ahead and just put
these students all in Gryffindor I know
these three students are in Gryffindor
so suppose that the problem at hand is
that I want to build up a list of
dictionaries that only contains the
Gryffindor students so it's sort of a
step back from the previous version
where I already had the names and the
houses for now just assume that the
problem is I have all of their names but
I don't yet have the student
dictionaries themselves so I'm
rebuilding that same structure that I
previously took for granted now let's go
ahead and just for the sake of
discussion just print out these
gryffindors so we can see what we've
built if I run python of gryffindors
dopy in my prompt I see a bit of a
cryptic syntax but again look for our
little hints I've got a square bracket
at the end and a square bracket at the
beginning and that indicates as always
this is a list I then have a whole bunch
of curly braces with a whole bunch of
quoted keys they happen to be single
quotes by convention when using print on
a dictionary but that's just a visual
indicator that that is my key and the
first value thereof is Hermione second
key is a house this value thereof is
Gryffindor then there's a comma which
separates one dict object from the next
and if we look past Harry and Gryffindor
there's a third a second comma which
separates Harry and Gryffindor from Ron
and Gryffindor as well so in short here
is some code whereby I fairly manually
built up with a for Loop and an
otherwise initially empty list the same
data structure as before minus Draco
just for Gryffindor students but here's
where again with dictionary
comprehensions or really list
comprehensions first can we do this a
little more succinctly Let Me Clear My
terminal window let's get rid of this
initially empty list and this for Loop
that appends appends appends to it and
let's just do this a gryffindors
variable will equal the following list
comprehension inside of that list I want
a dictionary structured with someone's
name and their name someone's house and
only for now Gryffindor and that's it
but I want one of these objects
here in these curly braces for each
student in students so here too inside
of my list comprehension with my square
brackets I want an object as indic I
want a dictionary as indicated by the
curly braces I want each of those
dictionaries to have two keys name and
house respectively the values thereof
are the student's name from earlier here
and Gryffindor only which students do I
want to create those objects from
well for student in students so again on
the left I have what I want in the final
list and on the right I have a loop and
this time no conditional I want all of
these students in Gryffindor as their
house now let's print this again uh
python of gryffindors dopy and hit enter
and now we have the exact same output so
instead of three lines it's just one
it's a little more uh cryptic to read at
first glance but once familiar with list
comprehensions and this sort of syntax
is just another way of solving that same
problem what if I want to change this
and simplify what if I don't want a list
of dictionaries which I now have again
per the square brackets I have a list of
three objects here what if I just
want one bigger dictionary inside of
which is a key like Hermione colon
Gryffindor Harry colen Gryffindor Ron
colen Gryffindor I don't need a list I
don't need separate objects per student
I just want instead one big dictionary
where the keys are the students names
and the values of their house and I'm
assuming for now no one's going to have
the same first name in this world well I
can do this let me get rid of this here
and not create a list comprehension but
again this thing known as a dictionary
comprehension and the visual indicator
or difference here is that instead of
being square brackets on the very
outside this time it's going to be curly
braces instead so inside of these curly
braces what do I want every key to be I
want every key to be the student's name
I want every value for now to be
Gryffindor and I want to do this for
each student in students and now things
are getting really interesting and this
is another manifestation of python in
some views being very readable from left
to right absolutely takes practice and
comfort but this is creating a variable
called Gryffindor which is going to be a
dictionary per these curly braces every
key is going to be the name of some
student every value is going to be
Gryffindor what names of what students
well this dictionary comprehension will
be be constructed from the list of
students one at a time so when I print
this now the syntax will look a little
different cuz it's not a list of
dictionary objects it's just one bigger
dictionary object itself but now
printing gryffindors gives me Hermione
col and Gryffindor Harry colen
Gryffindor and Ron colen Gryffindor as
well any questions now on what we've
called dictionary comprehensions as well
[Music]
any questions on
here no well let's introduce one other
function from Python's toolkit followed
by one final feature and flourish and
then you're off on your way well let's
go ahead and think back to this recall
some time ago that we had just a simple
list of students as we have here
Hermione Harry and Ron and for instance
way back when we wanted to print out for
instance their ranking from 1 to 2 to
three
unfortunately when you do something like
this for student in students you can
print out the student's name quite
easily of course if I do python of
gryffindors dopy I get Hermione Harry
Ron in that same order but I don't see
any numerical rank I see no number one
two or three so I could maybe do this
with maybe uh a different type of for
Loop instead of this why don't I try
this so maybe I could do for I in the
range of the length of the student list
and we've done something like this
before and then I could print out I and
I could print out the student's name by
indexing into that list at location I
well what does this look like if I run
python of gryffindors dopy it's close uh
but you know these aren't programmers
they don't necessarily think of
themselves as zero index termy probably
wants to be first not zero so how can we
fix this well just a little bit of
arithmetic I could print out i+ one of
course and then the student's name so if
I clear my terminal window and run
python of griffindor high once more now
we have this enumeration 1 two three of
each of these students but it turns out
that python actually has had all this
time another built-in function that you
might Now find useful that is namely
enumerate and enumerate allows you to
solve this kind of problem much more
simply by iterating over some sequence
but finding out not each value one at a
time but both the value one at a time
and the index thereof it gives you back
two answers at once so if I go back to
VSS code here now and take this approach
I don't need to do this this complicated
range and length and then I all over the
place I can more succinctly do this I
can say for I comma student in the
enumerate return value passing in
students so this gives me back an
enumeration if you will and now I can go
about printing I + one as before and I
can print out the student so I don't
need to index into the list with bracket
I notation I don't need to call range I
don't need to call length again
enumerate takes a sequence of values
like these students and it allows me to
get back the current index
012 and the current value Hermione Harry
Ron respectively so now just tighten
things up further and indeed that's been
our theme here can we solve the same
problems as we've been solving for weeks
but tighten things up using just more of
this tool
kit allow us to equip you with one final
tool for your toolkit namely this
ability to to generate values in Python
from functions this is not a problem
that we've necessarily encountered
before but it turns out if you're
writing a function that reads or
generates lots of data your function
your program your computer might very
well run out of memory and your program
might not be able to run any further but
it turns out there's a solution to this
problem that's something you might have
in your back pocket particularly if
after this course you start crunching
quite a few numbers and analyzing all
the more data in fact let's go back to
vs code here and let's go ahead and
create a program that's perhaps timely
at this time of day particularly
depending on your time zone you might be
feeling all the more sleepy but here in
the US it's quite common to be lulled to
sleep when you're struggling otherwise
by counting sheep in your head and
typically as depicted in cartoons you
might see in your mind's eye one sheep
jumping over a fence and then two and
then three sheep and then four and then
eventually you presumably get so bored
counting these sheep you actually do
fall asleep so in vs code here let's
create a program called sleep.i that
allows me to print out out some number
of sheep as though I'm counting them in
my mind's eye and Via this program let's
do this let's prompt the user for a
variable n setting it equal to the
integer conversion of the return value
of input asking the user what's n for
how many sheep do they want to try
counting and then let's do a familiar
for Loop here and we'll start counting
from zero as always so we'll first have
zero sheep then one sheep then two sheep
and so on for I in the range of that
value n Go ahead and print out and I'll
paste here an emoji representing a sheep
time I so the first iteration I'll see
Zero sheep the second iteration I'll see
one and then two and then however many
uh specified by n ultimately minus one
all right let's go down into my terminal
window here and run python of sleep. and
I should see indeed after typing in say
three for my value of n zero sheep then
one sheep then two sheep and so forth
and if I make my terminal window even
bigger here we can of course do many
more than this typing in for instance 10
and you'll see that we get more and more
sheep as time passes presumably becoming
all the more tedious to Envision in my
mind's eye so let's now go ahead and uh
practice what we've been preaching when
it comes to the design of this program
and see if and when we actually run into
a problem let me go ahead here now and
put all of this in a main function by
defining main up here as always let me
go ahead and indent all of this code
here and then let me just do this
conditionally as always if the name of
this file equals equals quote unquote
main let's go ahead and call Main let's
make sure I didn't break anything just
yet even though functionally this should
be nearly the same and if I type in
three I still have zero then one then
two sheep on the screen but we've been
in the habit of course of creating
helper functions for ourselves that is
factoring our code in a way that allows
us to abstract away certain
functionality like uh generating some
number of sheep into separate functions
so that one they're indeed abstracted
and we no longer have to think about how
they're implemented and we can even
reuse them in projects as in libraries
but we've also been in the habit too of
now testing those functions as with unit
tests so I probably shouldn't keep all
of my logic anyway in Main and let's
Factor some of this out wouldn't it be
nice if I could for instance just call a
sheep function uh as by uh taking this
line of code here and instead of just
printing it here let's print out the
return value of a new function called
Sheep that tells the function how many
sheep to print I in this case let's go
down as always and create another
function here called Sheep the Sheep
function now will take a parameter n
that's specifies how many sheep do you
want to return and so that we can test
this as with a unit test though we won't
do that here let me go ahead and not
print the number of sheep as via a side
effect but let me go ahead and return
one of those sheep times n so that the
user gets back a whole string of sheep
that's the appropriate number to print
so here too functionally I don't think
we've changed anything too fundamentally
python of sleep. typing three still
gives us zero then one and then two
sheep but now we at least have a
framework for focusing on the
implementation of this sheep function
but it's a little inelegant now that
it's still up to the main function to do
this iteration we've seen in the past
way back in week zero wouldn't it be
nice to define a function that actually
handles the process of returning the
entire string that we want rather than
just one row of sheep at a time well I
think we can do this why don't I go
ahead and change sheep as follows let me
go ahead here and uh first create a
flock of sheep that's initially empty
using an empty list then for I in uh the
range of n let's go ahead and append
that flock for instance one sheep times
I so that I keep adding to this list
zero sheep then one sheep then two sheep
then three and so forth and then
ultimately I'm going to return the whole
flock of sheep at once so this is going
to return the equivalent of all of those
strings of sheep so that eh Maine can
handle the print thereof so back up here
in Maine let's do this how about for
each sheep I'll call it s since sheep is
both singular and plural for s in sheep
of n which again returns to me a list of
all of the sheep the whole flock let's
just print out each sheep S one at a
time all right so so far so good here I
think let me go ahead and run python of
sleep. Pi and hit enter what's N3 and
that still seems to work just fine but
let me get a little uh creative here and
see not just three sheep on my screen
but maybe 10 rows of sheep and that too
seems to work fine let me get a little
more adventurous and type in maybe a 100
sheep and it's starting to look ugly to
be fair but they're all printing out
pretty fast let me go ahead and try
again with maybe 1,000 sheep on the
screen and they flew by pretty fast it's
still pretty messy but they're all there
we could count them all up how about not
just a th000 but 10,000 sheep well that
too seems okay it's it's taking like 10
times as long and that's why you see
this flickering on the screen all of the
sheep are still printing but but but
it's a lot of data being printed if I
hang in there a little
longer hopefully we'll see all 10,000
sheep coming to
pass this is here in the video where
will we will speed up
time all a real online oh my God this is
a lot of sheep there we go okay and now
all of my sheep have been printed so it
seems to be working just fine well let
me just be even more adventurous and
okay let me try my luck let me try like
uh how about 1 million sheep this time
and hit
enter
huh something's no longer
working while we wait for a spoiler here
does anyone have any intuition for why
my program suddenly stopped printing
sheep what is going going wrong in this
version wherein I'm generating this
really big flock of sheep we might have
run out of memory or computation power
yeah so maybe we're actually pushing the
limits of my Mac my PCS my cloud serers
memory or CPU the brains of the
computer's capabilities because it's
just trying to generate massive massive
massive lists of sheep 1 million of
those rows of sheep Each of which has a
huge number of sheep and it seems that
my computer here is honestly just really
struggling and this is really
unfortunate now because it would seem
that even though this program clearly
works pretty well for a th sheep 10,000
sheep once you cross some threshold it
just stops working alt together or it
just takes way too long for the program
to be useful anymore but this seems a
little silly right because theoretically
I should absolutely be able to print all
of these same sheep if I just printed
one right away then print two right away
then print three then four then five it
seems that the essence of this problem
if I go back to my code is that per my
best practices that I'm trying to
practice what I'm preaching it seems
that the fundamental problem is that
I've modularized my code by creating
this helper function called Sheep whose
purpose in life is to do all of the
generation of sheep and then return all
of them at
once wouldn't it be better and I can
actually hear my fan turning on now even
just trying to generate these sheep
wouldn't it be better then to just print
the Sheep one 2 3 four at a time well we
could do that but that's really a a step
backwards that rather contradicts all of
the Lessons Learned of the past few
weeks where generally not putting
everything in main is a good thing
generally having an additional function
that you can then test separately with
unit test is a good thing do we really
need to give up all of those best
practices just to print out some sheep
and and here fall asleep well it turns
out there's a solution to this problem
and namely in the form of these
generators in Python you can define a
function as a generator whereby it can
still generate a massive amount of data
for your users but you can have it
return just a little bit of that data at
a time and you yourself can implement
the code in almost the same way but you
don't have to worry about too much
getting returned all at once these two
like all features of python are
documented in the official documentation
therein but what you'll find ultimately
that it all boils down down to this
keyword here yield up until now when
we've been making functions we have been
defining functions that return values if
at all using the keyword return and
indeed if we go back to our code here
that's exactly what I've been waiting
for I've been waiting to return the
whole flock at once unfortunately if you
wait too long and here we have it my
program was quote unquote killed that is
to say my computer got so fed up with
how much memory and CPU it was trying to
use it just said nope you're not going
to run at all and that's unfortunate now
my program no longer works for large
numbers of sleeps sheeps which is not
good if I'm really having trouble
falling asleep some night so how can I
use yield to solve this problem instead
well let me do this instead of building
up this massive list of sheep in this
big list called flock let's just do this
instead let me go ahead and simplify
this whole function as follows where by
I iterate for I in the range of N and
then on each iteration in the past I
might have been inclined to use return
and return something like one sheep
times I but this won't work here right
because if you want a million sheep and
you start a for Loop saying for I in the
range of a million you're going to
return accidentally zero sheep right
away and then this function is
essentially useless you shouldn't return
a value in the middle of a loop like
this because you're not going to get to
any of these subsequent iterations of
the loop it's going to iterate once and
boom you return but thanks to this other
keyword in Python called yield you can
tell python to effectively return just
one value at a time from this Loop so if
I go back to this version of my code
here and I say not return but yield this
is like saying return one value at a
time return one value at a time return
one value at a time the four Loop will
keep working and I will keep counting
from zero to one to two all the way up
toward 1 million but each time the
function is just going to hand you back
a little piece of data it's going to
generate so to speak just a little bit
of that data not all of the data at once
and that's good because my computer has
a decent amount of ram certainly enough
to fit one row of sheep it just doesn't
have enough memory to fit apparently 1
million rows of so many sheep so now if
I go to my terminal window
and run python of sleep. Pi and hit
enter what's in three would still work
zero then one and then two let me go
ahead and increase the size of this here
and run python of sleep.i let's try 1
million as before and hit enter and now
I immediately see results I don't think
we'll wait for all of these sheep to be
printed because then we will literally
all be asleep but what you'll notice
happening now is the program is not
hanging so to speak it's not waiting and
waiting and thinking thinking and trying
to generate the entire flock at once
it's just generating one row of sheep at
a time and it's flickering on the screen
because there's so many of them and
that's all thanks to yield it's
generating a little bit of data at a
time not all at once any questions now
on this feature called
generators any questions at all to add
one more piece of terminology to the mix
just so you've heard it this same
feature of uh this same feature here is
returning what we'll technically Now
call an iterator yield is returning an
iterator that allows your own code your
own for Loop in Maine to iterate over
these generated values one at a time how
how does uh this yield uh actually works
under under the hood I I mean is it is
it using multi trading you can think of
the implementation as being asynchronous
in this sense whereby the function is uh
returning a value immediately and then
subsequently giving you back another one
as well underneath the hood what's
really happening is the generator is
just retaining state for you it does not
going to run the entire loop from top to
bottom and then return a value it's
going to do one iteration and yield a
result and the python for you is going
to suspend the function if you will but
remember on what iteration it was so the
next time you iterate over it as it's
going to happen again and again in this
for Loop in main you get back another
value again and again so yield returns
indeed this thing called an iterator and
that iterator can be stepped over as in
a loop one element at a time but the
language python handles all of that for
you so that you don't need to do all of
the underlying uh Plumbing yourself how
about time for one other question on
these generators and iterators as our
sheep continue to fly by so in every
iteration the program will return to the
memory to the system so the program will
not crash correct on each iteration it's
only returning the one string of sheep
that's appropriate for the current value
of I it is not trying to return all
million rows of the same and therefore
it uses really one millionth the amount
of memory although that's a bit of an
oversimplification all right as these
sheep continue to fly across the screen
let me now uh go ahead and interrupt
this as you might have had to in the
past with infinite Loop in your own code
even though this isn't infinite it's
just really long contrl c will interrupt
with your keyboard that program giving
me back control of my computer well here
we are at the end of cs50's introduction
to programming with python and if today
in particular of all days felt like a
real escalation real quickly realize
that these are really these are just
additional perhaps optional Tools in
your toolkit that you can add to all of
the past Lessons Learned so that as you
exit from this course and Tackle other
courses or projects of your own you have
all the more of a mental model and all
the more of a toolbox with which to
solve those same problems if we think
back now just a few weeks ago it was
probably in our focus on functions and
variables that you first started
struggling but now in retrospect if you
look back at those problems and those
same problem sets odds are those same
problems would come all too easily to
you now conditionals was the next step
in the class wherein we gave you the
ability to ask questions and get answers
and therefore do things conditionally in
your code we came full circle today and
you can can see that you can now use
those same kinds of conditionals now to
do fancier things with list
comprehensions and D dictionary
comprehensions and the like Loops of
course have been omnipresent now for
weeks including today as we built up
those same structures and of course
something can go wrong and exceptions
and exception handling was our mechanism
for not only catching errors in code but
also raising your own exception so that
if you're laying the foundation to write
code for other people as in the form of
libraries you can do that too libraries
of course are things you can not only
use but now write on your own be it a
small module or whole package of code
that you want to share with others
around the world and even better can you
write tests for your own code for your
libraries for others code as well so
that ultimately you can be all the more
confident that not only your code is
correct today but if you make a change
to your code tomorrow you haven't broken
anything at least according to your
tests if they continue to pass file IO
though meanwhile was a way of now
storing data not just in the computer's
memory like all of these sheep but
actually storing things persistently
longer term to dis being in a CSV or
something more like a binary file like
an image with regular Expressions you
then had the ability to express patterns
and actually validate data or extract
data from information all the more of a
useful technique nowadays when so much
of the world is trying to analyze and
process data at scale some of which
might uh in fact be uh quite messy uh
from the get-go and then of course most
recently object-oriented programming an
opportunity to solve the same kinds of
problems but with a slightly different
perspective a way to encapsulate and to
represent real world entities this time
in code and today of course Etc with so
many other tools that you can add that
didn't necessarily fall under any of
those earlier umbrellas but are useful
functions and data types and techniques
just to have again in your back pocket
as yet other mechanisms for solving
problems as well not just putting
everyone to sleep but I thought another
way to end might be a little more
vocally to try writing one final program
together this one using a Library we've
seen in the past as well as one other
I've taken the liberty of installing a
text to speech library on my computer
here and I'm going to go ahead perhaps
and open a new file here called uh uh
say dopy in vs code and I'm going to go
ahead here and first import our own
friend import cow and I'm going to
import this new library here import Pi
TT sx3 the python text to speech library
and now perit documentation which I read
in Advance I'm going to go ahead and
create a variable for myself here engine
equals pyttsx3 init to initialize that
library for text to speech I'm going to
then ask the user well what do I want to
hear spoken and I might do something
like this a variable called this equals
the return value of input what's this
shall be my simple question and I'm
going to keep it this time as a string
we've seen how to use C we can do c.ca
of this turns out this new library can
allow me to use its own to say this as
well but then ultimately I'm going to
have to run the engine. run and wait
just in case it's a long phrase or
sentence to be said but that's it in
just eight lines of code not only am I
apparently going to have a cow appear on
the screen to close us out now but also
some synthesized text ultimately then we
hope with this course that you not only
learned python that you've not only
learned programming but you've really
learned how to solve problems and
ultimately how to teach yourself new
languages a funny enough I myself only
learned python just a few years ago and
even though I certainly went through
some formal documentation and resources
online I mostly learned what I know now
and even what I had to learn again for
today by just asking lots of questions
be it of Google or friends who are more
versed in this language than I and so
having that instinct having that
vocabulary very which to ask questions
of others to search for answers to
questions you absolutely now have enough
of a foundation in Python and
programming to go off and stand on your
own so you can certainly and you're
welcome and encouraged to go on and take
other courses in Python and programming
specifically but better still as quickly
as you can is to find some project
that's personally of interest that uses
python or some other language because at
least from my own experience I tend to
learn best and I hope you might too by
actually applying these skills not to
problems in the classroom but really
truly to problems in the real world
allow me with all that said to look at
my full screen terminal window here run
python of s.p crossing my fingers one
final time in hopes that I've not made
any mistakes or bugs and here we go
python of sey prompting me what's this
how about we end on this note
here this was cs50
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.