Week 4: indefinite loops, functions, string formatting
Announcements
-
due to the fire drill, Quiz 1 now scheduled for Wednesday
Monday
string formatting
motivation
Adding strings together and converting from ints or floats to strings
gets tiresome for anything but simple strings. We could use the comma to
print multiple items (e.g., print(x,y,z)
) but that automatically adds
a space, and doesn’t allow for precision. String formatting allows more
control over the result, by specifying both width and precision.
Assume you have three variables:
num = 6 factor = 7 answer = num*factor
Using string concatenation, the print
statement looks like this:
print(str(num) + " x " + str(factor) + " = " + str(answer))
Using string formatting, we avoid all of the str()
calls:
print("%d x %d = %d" % (num,factor,answer))
And if the width of the integers changes (double or triple-digits), we can use the width specification to make everything line up! Without specifying the width, our times table looks like this:
6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36 6 x 7 = 42 6 x 8 = 48 6 x 9 = 54 6 x 10 = 60 6 x 11 = 66 6 x 12 = 72
Notice the 54
and the 60
don’t line up, because the 9
and the 10
have
a different number of digits.
Using a width of two:
print("%2d x %2d = %2d" % (num,factor,answer))
makes the numbers in the table line up (all single-digit numbers are padded with one space):
6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36 6 x 7 = 42 6 x 8 = 48 6 x 9 = 54 6 x 10 = 60 6 x 11 = 66 6 x 12 = 72
syntax
There are three format-specifiers we normally use:
%f for floats %s for strings %d for (decimal) integers (I think %i also works for ints)
In the print statement, the format-specifiers get replaced by data, which is given at the end, like this:
print("%d x %d = %d" % (num,factor,answer))
In the above example, the first %d
is replaced by the data stored in
the variable num
, the second is replaced by factor
, and the third by
answer
.
Each format-specifier has an optional width, so, for example, you could
print out 8-character usernames with %8s
, padding the usernames that
have less than 8 characters (like jknerr1) with spaces.
Floats have an additional precision specifier, so %7.2f
means a width
of 7 (including the decimal point), with 2 digits of precision (after the decimal).
examples
Making usernames line up:
>>> unames = ["ewu1","jtaylor5","dpike1","craty1","wchou1"] >>> for name in unames: ... print("%8s" % (name)) ... ewu1 jtaylor5 dpike1 craty1 wchou1
Making numbers line up, with 2 digits of precision:
>>> nums = [3.14159, 145.7, 2, 2000, 2.1234567] >>> for num in nums: ... print("Cost of item: $%7.2f" % (num)) ... Cost of item: $ 3.14 Cost of item: $ 145.70 Cost of item: $ 2.00 Cost of item: $2000.00 Cost of item: $ 2.12
your turn!
Suppose you have parallel lists, meaning the first item in the first list corresponds to the first item in the second list, and so on. Here are parallel lists for elements and their atomic masses:
def main():
elements = ["H","He","Li","Be","B","C"]
amass = [1.0079,4.0026,6.941,9.0122,10.811,12.0107]
for i in range(len(elements)):
print(elements[i],amass[i])
main()
Currently they print out OK, but things don’t quite line up:
$ python3 periodictable.py H 1.0079 He 4.0026 Li 6.941 Be 9.0122 B 10.811 C 12.0107
If you run update21
you should get the above periodictable.py
file
in your w04-whileloops
directory. Add string formatting to the
print()
statement to make everything line up like this:
$ python3 periodictable.py H 1.0079 He 4.0026 Li 6.9410 Be 9.0122 B 10.8110 C 12.0107
Wednesday
Finally took Quiz 1! We also took our first look at functions!!
motivation
As our programs get larger and more complex, using functions becomes a neccessity. Designing and writing your programs using functions makes them easier to write, read, test, and debug.
function syntax
Just like we’ve been doing all along with main()
, a function is just
an indented block of code with a name. Here’s a simple function:
def happybirthday(name): """display happy birthday song for name"""
print("Happy Birthday to you.") print("Happy Birthday to you.") print("Happy Birthday, dear %s." % (name)) print("Happy Birthday to you!")
return
Some things to note about the above function:
-
it has one parameter, the
name
variable -
it has four
print
statements -
the
return
at the end signals the end of the function, but is not always necessary
Here’s an example of how the above function might be called from
main()
:
def main(): name = input("Who's birthday is it? ") happybirthday(name)
Whatever the user types in, it is stored in the variable name
.
That data is then sent to the function, for use in the print
statements. In main()
, the variable name
is used as an argument
in the call to the happybirthday()
function. When writing and calling
functions, the number of arguments must match the number of
parameters.
I also don’t have to use a variable as an argument. I could just use a string argument, like this:
happybirthday("Ravi")
which would print:
Happy Birthday to you. Happy Birthday to you. Happy Birthday, dear Ravi. Happy Birthday to you!
another example
Next we wrote the allCaps()
function, which returns a boolean value:
def main():
result = allCaps("HELLO")
print(result)
result = allCaps("hello")
print(result)
def allCaps(string):
"""return True if string is all CAPs, False otherwise"""
caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for ch in string:
if ch not in caps:
return False
# if we get here, past the for loop
return True
main()
Again, the parameter string
is assigned to whatever the argument
is in the call to allCaps()
in main()
. In the first call, string
will
be "HELLO"
, and the function should return the value True
.
In the allCaps()
function, note how we can return as soon as any letter
in the string is not in caps
. We don’t need to check any further if we find
a letter that is not in caps
. If we make it past the for
loop,
then we know the string must be all capital letters, so we can then
return a True
value.
Friday
We reviewed the q1.py
file you got when running update21
.
Also note the use of functions in that file!
Also take a look at this example of another function, with labels for the argument, parameter, and return value:
![args and params image](img/argsparams.png)
Here’s an example of the running program, where the user enters "hello, 123":
$ python3 isdigit.py Please enter a string: hello, 123 h is a digit? False e is a digit? False l is a digit? False l is a digit? False o is a digit? False , is a digit? False is a digit? False 1 is a digit? True 2 is a digit? True 3 is a digit? True
valid user input
Starting with the rock papaer scissors code I gave you in the w04
directory (rps.py
), let’s add some code to get the input from the
user and make sure it’s valid input.
Here’s what we currently have:
user = input("rock, paper, or scissors? ")
That works, unless the user makes a typo or types in something crazy
(like "zebra"). We could add more code to main()
, but a better
approach is to write a new function, and have that function take care
of making sure the user enters a valid choice.
Here’s the start of the function:
def getInput():
"""get user input, make sure it is valid"""
answer = input("rock, paper, or scissors? ")
options = ["rock", "paper", "scissors"]
Now that I have the user’s answer, I want to make sure it is
one of the valid options in my list. If it is, I return
the answer,
but if it isn’t, I want to print a message and ask again. This
sounds like an if
statement, but you don’t know if they will need
more than one try, so we’ll use a while
loop.
Here’s one way to write the function:
def getInput():
"""get user input, make sure it is valid"""
answer = input("rock, paper, or scissors? ")
options = ["rock", "paper", "scissors"]
while answer not in options:
print("That's not a valid option!!")
answer = input("rock, paper, or scissors? ")
return answer
Which says, as long as they give invalid input, keep printing the error message and asking again.
Here’s what the output looks like:
rock, paper, or scissors? yes That's not a valid option!! rock, paper, or scissors? zebra That's not a valid option!! rock, paper, or scissors? ROCK That's not a valid option!! rock, paper, or scissors? rock I chose scissors
your turn!
See if you can write the countletter(letter,phrase)
function
shown in the file countletter.py
:
$ cat countletter.py """ practice with functions...write the countletter(letter,phrase) function """ def main(): phrase = input("enter a phrase: ") letter = input("enter a letter: ") result = countletter(letter,phrase) print("Number of %s's: %d" % (letter, result)) # add your countletter() function here!! main()