Python Reference
This python reference is hopefully posted here: https://jeffknerr.github.io/pythonreference
See the pythonreference repo for the actual asciidoc files.
Introduction
These pages are meant as a quick reference for the python programming language. All code here assumes you are using python version 3. Use the Table of Contents on the left to select your topic of interest.
The python shell or interpreter is very useful for testing or trying simple python statements. Any examples below that have a triple-greater-than prompt (>>>) are showing output using the python shell, like this:
>>> print("hello!") hello!
You can start the python shell by typing the python3
command in a terminal
window (the dollar sign ($) is the terminal prompt, which you don’t type):
$ python3 Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>>
You can exit the python shell with Cntl-d (hold down the Control key, then hit the 'd' key).
Variables
example
>>> x = 3.14159 >>> name = "Harry" >>> m = 2 >>> cities = ["Philadelphia", "Denver", "Paris"] >>> print(x) 3.14159 >>> print(x*m) 6.28318 >>> print(cities*m) ['Philadelphia', 'Denver', 'Paris', 'Philadelphia', 'Denver', 'Paris']
explanation/notes
We are declaring variables using the assignment operator (=).
Declaring m = 2
means: create a variable called m that refers to the
integer value 2
stored in memory. We can then use the variable m
throughout the rest of our program.
Variable names are case sensitive.
>>> bird = "Eagle" >>> print(bird) Eagle >>> print(Bird) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'Bird' is not defined
No spaces allowed in variable names.
>>> my name = "Jeff" File "<stdin>", line 1 my name = "Jeff" ^ SyntaxError: invalid syntax
Also can’t start with a number.
>>> 5star = "Hilton" File "<stdin>", line 1 5star = "Hilton" ^ SyntaxError: invalid syntax
The variable declaration syntax is always <variable> = <value>
or
<variable> = <expression>
.
>>> pi = 3.1415928 >>> radius = 2 >>> area = pi*(radius)**2 >>> print(area) 12.5663712
Switching the order (value = variable) doesn’t work!
>>> 2 = m File "<stdin>", line 1 SyntaxError: can't assign to literal
another example
You can use variables on either side of the assignment operator. Just remember that the right side (the value or expression) is always evaluated first, then assigned to the variable on the left side. That allows something like this (increment a variable) to work:
>>> counter = 0 >>> counter = counter + 1 >>> print(counter) 1 >>> counter = counter + 1 >>> print(counter) 2
The second line above says: get the value referred to by counter
, add 1 to it
to make a new value, then store that new value in memory in the location that the
counter variable refers to. So we pull out what is stored there, make a new value,
then store the new value back in the same spot.
Data Types
example
>>> age = 54 >>> height = 5.75 >>> name = "Jeff" >>> happy = True >>> dogs = ["Max", "Sam", "Lily"] >>> print(happy) True >>> type(happy) <type 'bool'> >>> type(height) <type 'float'>
explanation/notes
The main data types in python are: integer (int), string (str), float, list, and boolean (bool). There are others (e.g., tuples and dictionaries), but these are the main basic types.
A data type is defined by it’s possible values and the operations that
can be performed on those values. For integers, the possible values are
all integers (0, 1, 2, …, and the negative integers -1, -2, …), and
the operations are addition, subtraction, multiplication, and so on.
The boolean data type has just two values: True
and False
(must be
uppercase).
The data type really matters for some things!
>>> 5/2 2.5 >>> 5//2 2
The first line above uses floating-point math, and probably does what you were expecting. The second line does integer division (i.e., ignores any remainder).
For the string data type, multiplication by integers is allowed/supported, but multiplication by floats is not.
>>> "hello"*3 'hellohellohello' >>> "hello"*3.5 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't multiply sequence by non-int of type 'float'
The same is true for lists:
>>> dogs*2 ['Max', 'Sam', 'Lily', 'Max', 'Sam', 'Lily'] >>> dogs*2.5 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't multiply sequence by non-int of type 'float'
In python you do not need to declare what type to store in a variable, so you can freely reassign different types to the same variable (not recommended!).
>>> x = 5 >>> print(x) 5 >>> x = "hello" >>> print(x) hello >>> type(x) <class 'str'>
This is a tradeoff! Python code is usually shorter and cleaner than other languages, because we don’t have to write out what type everything is (variables and functions). However, this can often lead to other problems (e.g., if you expect x to be a float, but it’s a string) or slower code (sometimes the computer can optimize your code for you, if it knows the type of every variable and function).
another example
Sometimes it is useful to check if something is an instance of a certain data type:
>>> isinstance(5,int) True >>> isinstance(5,float) False >>> isinstance(5,str) False >>> isinstance("5",str) True
See also:
Functions: builtin
example
>>> S = "Swarthmore" >>> print(S) Swarthmore >>> print(len(S)) 10 >>> L = list(S) >>> print(L) ['S', 'w', 'a', 'r', 't', 'h', 'm', 'o', 'r', 'e'] >>> x = int(5.371) >>> print(x) 5 >>> type(x) <class 'int'>
explanation/notes
A function is just a block of code with a given name. You use the name
followed by parentheses to call the function: print("hello")
. Calling
the function executes the code block. After the function executes, the program
that called the function continues running.
Using functions, either built-in or creating your own, is the primary way to manage code complexity. As you start to write larger programs, you will break large tasks into smaller, manageable functions.
In all of the function calls above, an argument is provided inside the parentheses.
In print("hello")
, the print()
function is called with the string argument "hello"
.
The arguments are just data sent to the function. Functions can have zero or more
arguments. Here’s a call to print()
with 3 arguments:
>>> name = "Jeff" >>> print("Hello, ", name, "!") Hello, Jeff !
Sometimes, but not always, a function returns something to the program that
called the function. In x = int(5.371)
the float 5.371 is sent to the int()
function, which converts (truncates) it into an integer (5), and returns the result
(the 5). This result is then immediately assigned to the variable x
.
Here are some useful built-in python functions:
function | description | example | returns |
---|---|---|---|
|
prints arguments to terminal |
|
nothing |
|
converts arg to integer |
|
integer |
|
converts arg to float |
|
float |
|
converts arg to string |
|
string |
|
displays data type of arg |
|
type object |
|
returns length or sequence |
|
integer |
|
gets input from the user |
|
string |
another example
The input()
function is used to get input from the user.
It will pause the program, waiting for the user to type something
and hit Enter. The argument provided becomes the prompt to the
user.
>>> age = input("How old are you? ") How old are you? 53 <-- user types 53 here and hits Enter key >>> print(age) 53 >>> type(age) <class 'str'>
Note the input()
function always returns a string, no matter what
the user enters (characters, digits, etc).
If you know the user is going to enter a valid integer, you can use
the int()
function to convert the input string to an integer:
>>> age = int(input("How old are you? ")) How old are you? 53 >>> print(age) 53 >>> type(age) <class 'int'>
But this won’t work if the user enters something that can’t be converted to an integer:
>>> age = int(input("How old are you? ")) How old are you? pony Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: invalid literal for int() with base 10: 'pony'
See later sections
(while
(indefinite) loops, try/except)
for ways to handle invalid input.
Input
This could mean input from the user, or from a file, or some other source, like pulling data from a web site.
example
>>> number = input("Pick a number from 1-10: ") Pick a number from 1-10: 4 >>> print(number) 4
explanation/notes
The built-in input()
function allows the program to prompt the user for
input, then wait for a response.
The argument (a string: "Pick a number…") is displayed to the
user. When the user types in a response (the 4) and hits the "Enter" key, the input data
is returned to the program. In the above example, the "4" is returned and
immediately assigned to the variable number
.
The input()
function always returns a string, no matter what the
user types (letters, digits, punctuation, etc). If you are expecting the
user to enters integers or floats, and your program needs integers or
floats to work, you will need to convert the user input to the correct data type:
>>> print(type(number)) <class 'str'> >>> number = int(number) >>> print(type(number)) <class 'int'> >>> print(number) 4
See the try/except section for better ways to check for and convert valid user input.
another example
name = input("Name: ")
prompt = "Hi, %s! Year you were born? " % (name)
year = int(input(prompt))
This code asks for the user’s name, then uses it in the next prompt
that asks for when the user was born. The second input is automatically
converted to an int and assigned to the year
variable. Here’s a
sample run of the above code, where the user enters "George" and "1732":
Name: George Hi, George! Year you were born? 1732
See also:
Output
Typically by output we mean either output to the terminal/screen,
or output to a file. The print()
function is used for output to
the terminal (see examples below). For files, the write()
method
is used — see Files for examples of writing to a file.
example
>>> name = "Julie Ertz" >>> number = 8 >>> position = "midfielder" >>> gpg = 0.23 >>> print(name) Julie Ertz >>> print(number) 8 >>> print(name, number, position, gpg) Julie Ertz 8 midfielder 0.23 >>> print("%s (%d) is a %s averaging %.2f goals/game." % (name,number,position,gpg)) Julie Ertz (8) is a midfielder averaging 0.23 goals/game.
explanation/notes
The print()
function can print strings, ints, floats, and other data types.
When printing multiple types together, separating them by
commas is easiest (useful for debugging!), but doesn’t allow formatting.
Using String Formatting is best for complex formatted output.
another example
When printing a large block of text, it is often easier to use a triple-quoted string, which you can format exactly as you want it to display over multiple lines:
rules = """
##############################
Scattegories v0.1
-----------------
Pick a letter and a category list.
You then have 30 seconds to write down an entry for each
category that starts with that letter. Good luck!
##############################
"""
print(rules)
See also:
String Formatting
This is a nice way to handle output strings that include variables. By nice I mean it avoids printing variables separated by commas, or concatenated together with the plus (+) operator.
example
>>> name = "Ryan Howard" >>> homeruns = 58 >>> average = 0.313 >>> year = 2016 >>> print("In %d, %s hit %.3f with %d home runs!" % (year, name, average, homeruns)) In 2016, Ryan Howard hit 0.313 with 58 home runs!
explanation/notes
You can even create strings with this and use them as needed:
>>> output = "In %d, %s hit %.3f with %d home runs!" % (year, name, average, homeruns) >>> type(output) <class 'str'> >>> print(output) In 2016, Ryan Howard hit 0.313 with 58 home runs!
In both of these examples, a sting is created by substituting the
variables at the end in for the format specifiers (the %s
, %d
, and
the %f
). The variables must be in the correct order, so the first
variable (year
) is substituted for the first format specified (%d
).
And here’s what the format specifiers mean:
format specifier | description | example |
---|---|---|
|
for decimal integers |
|
|
for floats |
|
|
for strings |
|
You can also include width and precision information in the
format specifier. For example, the %.3f
in the above examples
means we want only 3 digits after the decimal in the float.
If I were printing out numbers that I want to all line up (maybe dollar amounts), I could specify the width of each output string. For example:
>>> nums = [21.5, 100, 3.45, 367.39] >>> for num in nums: ... print("$%7.2f" % num) ... $ 21.50 $ 100.00 $ 3.45 $ 367.39
The %7.2f
means I want all floats printed with a width of 7
and with 2 digits after the decimal. Notice that after the
dollar sign, all floats have a width of 7 characters (the decimal is one of
the 7 characters). If the float doesn’t already have a width of 7,
it is padded with spaces on the left side as needed.
another example
There’s also a newer .format
way to handle string formatting.
Here’s an example of the above using the newer syntax:
>>> output = "In {:d}, {:s} hit {:.3f} with {:d} home runs!".format(year, name, average, homeruns) >>> print(output) In 2016, Ryan Howard hit 0.313 with 58 home runs!
See also:
for
loops
example
>>> names = ["Andy", "Kevin", "Lauri", "Jeff"] >>> for name in names: ... print("Hello, ", name, "!") ... Hello, Andy ! Hello, Kevin ! Hello, Lauri ! Hello, Jeff !
Note: I don’t type the dot dot dots (…). That’s just the python
shell telling me it expects something more — the indented code block
of the for
loop. On the last line, before the "Hello…" output, I
just hit the Enter key (no indentation).
>>> limit = 10 >>> for i in range(limit): ... output = 2*i ... print(i,":",output) ... 0 : 0 1 : 2 2 : 4 3 : 6 4 : 8 5 : 10 6 : 12 7 : 14 8 : 16 9 : 18
explanation/notes
for
loops are great when we want to repeat something, and we know how many
times we want to repeat. In the first example above, we want to print a greeting
for however many names are in our list of names. In the second example, we want
to create and print something limit times.
The for
loop syntax is:
for <variable> in <sequence>: indented code indented code indented code
The variable is any name you want (but choose good variable names, unlike this next example!):
>>> for n in names: ... print("Hello, ", n, "!") ... Hello, Andy ! Hello, Kevin ! Hello, Lauri ! Hello, Jeff !
And the variable takes on all values in the sequence, one at a time. Each time the variable gets a new value from the sequence, the indented code lines (i.e., the code block) are executed.
There must be one (or more) indented code lines in the for
loop.
The next unindented line ends the code block! So if I had this:
limit = 10
for i in range(limit):
output = 2*i
print(i,":",output)
print("-"*20)
It would print this (see how the dashed line is after or outside the for
loop!):
0 : 0 1 : 2 2 : 4 3 : 6 4 : 8 5 : 10 6 : 12 7 : 14 8 : 16 9 : 18 --------------------
The sequence in a for loop can be many things: a list, a string, or even a file. If the sequence is:
-
a list, the variable becomes each item in the list
-
a string, the variable becomes each character in the string
-
a file, the variable becomes each line in the file
Here’s a string sequence example:
>>> for ch in "ABCDEFG": ... print(ch*3) ... AAA BBB CCC DDD EEE FFF GGG
These examples may all seem trivial or a little silly, but for
loops are very important!
As we learn more python, we’ll see some more useful examples.
the range()
function
The range()
function is a built-in python function that is super-useful
for creating sequences used in for
loops. Technically (in python 3) it
is it’s own type, but you can see what it’s doing if you call the list()
function on it:
>>> x = range(10) >>> type(x) <class 'range'> >>> list(x) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Given a single integer (say, n
) it creates a range of integers from 0 to n-1
.
The full syntax is range(start, stop, step)
, but you can leave out the start
(defaults to 0) and/or the step (defaults to 1). Here’s an example using all of them:
>>> list(range(1,11,2)) [1, 3, 5, 7, 9] >>> list(range(10,-1,-1)) [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
another example
>>> n = 7 >>> for i in range(1,11): ... answer = i*n ... print(n,"x",i,"=",answer) ... 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70
See also:
Accumulator
Suppose you have a list of data values, and you need to know how many of those data values are less than zero.
example
data = [37.5, -0.01, 99.34, 14.7, ...]
counter = 0
for item in data:
if item < 0:
counter = counter + 1
print("Number a values < 0: ", counter)
explanation/notes
The counter
variable is an example of an accumulator.
It starts at zero, and we check each data value in the list. Each time
we find one that meets a certain condition (here, less than zero), we
increment the counter variable. At the end of the for
loop we have
built-up/accumulated the answer (how many values are less than zero).
This accumulator pattern (initialize to zero, build up solution one item at a time) arises in different situations, and can be reused to solve problems in these different areas.
Here are some examples:
-
keep track of consecutive correct answers, print a message if user gets 5-in-a-row correct ("Good work!")
-
get data from file, keep a count of how many invalid data items read in
-
get numbers from user, keep a running sum of the input numbers
another example
Here’s the "keep a running sum" example mentioned above. In this example we are getting numbers from the user, then calculating and displaying the average of those numbers.
ngrades = int(input("Number of grades: "))
total = 0
for n in range(ngrades):
grade = float(input("grade: "))
total = total + grade
avegr = total/ngrades
print("Average grade: ", avegr)
string accumulator
You can also build-up/accumulate strings, starting with an empty string.
What do you think this for
loop will print to the screen?
output = ""
for i in range(10):
output += "*"
print(output)
Note: the +=
operator is shorthand for assignment addition.
So the output += "*"
line above is equivalent to this:
output = output + "*"
if
/else
(branching)
The if/elif/else
statement is used for branching:
when your code needs to decide between one or more actions.
example
if height > 48:
print("Good to go!")
elif height >= 42:
print("You need an adult with you to ride this rollercoaster!")
else:
print("Sorry, you are not tall enough for this rollercoaster!")
explanation/notes
The above code prints a different message, depending on the value
stored in the height
variable. There are three branches in this
if
statement:
-
people over 48 (inches) can ride on their own
-
people in the 42-48 inch range can ride with an adult
-
people less than 42 inches (i.e., everyone else) cannot ride this rollercoaster
Each branch is a code block. Just like the for
loop, the code
block is indented, and can be one or more lines long.
The syntax of the if/elif/else
statement is:
if <boolean expression>: do this line and any others in this block elif <boolean expression>: do this other code block else: do this indented line and this one, too
The boolean expression can be anything that evaluates to either True
or False
.
If one of the boolean expressions is True
, that code block is executed
and no further branches are tried (i.e., the program jumps down to
the code that comes after the if/elif/else
statement and carries on
from there).
You can have a single if
statement all by itself:
if grade > 90:
print("Good work!")
You can also have just two branches (no elif
):
if grade > 70:
print("You passed!")
else:
print("Uh oh...")
You can have three branches as shown above, or as many branches as you need:
if grade >= 90:
print("A")
elif grade >= 80:
print("B")
elif grade >= 70:
print("C")
elif grade >= 60:
print("D")
else:
print("F")
In the last example, if grade
has the value 85, the first boolean
expression (grade >= 90
) is False
, so the computer goes on to
test the next expression (grade >= 80
). Since this one is True
,
it prints the B and then skips all further tests and would carry
on with any code located below/after the if/elif/else
statement.
boolean expressions
Here are the boolean comparison operators:
-
equals:
==
-
not equals:
!=
-
greater than:
>
-
less than:
<
-
greater than or equal to:
>=
-
less than or equal to:
<=
Python allows string comparisons (see ord
and chr
for how):
>>> "apple" < "banana" True >>> "Zebra" > "Tiger" True >>> "Jeff" == "jeff" False >>> "Apple" < "apple" True
There is also a membership operator (in
) that is really useful:
>>> S = "Swarthmore" >>> L = ["dog", "cat", "zebra"] >>> "a" in S True >>> "z" in S False >>> "dog" in L True >>> "camel" in L False >>> "more" in S True >>> "a" in L False
another example
You can also combine boolean expressions with and
, or
, and not
:
if (flavor == "chocolate") and (num_scoops > 0):
print("Yum!!")
For and
: both conditions must be True
to execute the code block.
For or
: the code block will be executed if either or both are True
:
if (flavor == "chocolate") or (flavor == "mint chip"):
print("I'm OK with that. Thanks!")
Functions: simple
Functions are just blocks of code with a name, which we can call using the name and parentheses:
example
>>> def celsius(tempF): ... tempC = (tempF - 32) * (5/9) ... return tempC ... >>> print(celsius(72)) 22.22222222222222 >>> print(celsius(32)) 0.0 >>> print(celsius(-40)) -40.0
explanation/notes
In the above example we define the function called celsius
.
It has one parameter: a varible named tempF
, which presumably
holds the temperature in degrees Fahrenheit that we want to convert
to degrees Celsius. Given tempF
, we calculate the temperature in
degrees Celsius and store it in a variable called tempC
. Finally,
the function returns the data stored in tempC
back to whoever
called this function.
The next three lines above just show three examples of calling the function.
In the first example (celsius(72)
) the argument in the function call is
the integer 72. This means, in the function, tempF
is assigned the value of 72.
In the second call, the argument is 32, and the function calculates and returns
32F converted to Celsius.
As you can see, functions are extremely useful if we ever have to perform repeated calculations. They can also make our programs more readable, if we choose good function names. And they greatly reduce complexity for larger programs, making them both easier to read and to design/write.
The syntax of defining a function is:
def <function>(<params>): <body of function>
The name of the function can be almost anything (no spaces, can’t start with a number, similar to variable names). A function can have zero or more parameters. The body of the function can be one or more lines (every indented line is part of the function). A function may or may not return anything to the calling program.
Here’s an example of a function that just prints stuff and doesn’t return anything back to the program that called the function:
def poem(color1, color2):
"""print a silly poem"""
print("Roses are %s," % color1)
print("Violets are %s," % color2)
print("Sugar is sweet.")
print("And we love CompSci!!")
Calling the above function as poem("red", "blue")
produces this:
Roses are red, Violets are blue, Sugar is sweet. And we love CompSci!!
And calling the function as poem("black", "pink")
produces this:
Roses are black, Violets are pink, Sugar is sweet. And we love CompSci!!
another example
def average(mylist):
"""calculate and return average of numbers in a list"""
total = 0.0
for num in mylist:
total = total + num
ave = total/len(mylist)
return ave
This function calculates the average of all numbers in the given list,
as it says in the triple-quoted comment (the first line under the
def
statement). All functions should have a comment under the def
statement, as it helps the reader to understand what the function
does, and is also part of the built-in python help documentation.
See also:
def main()
example
def main():
name = input("What is your name? ")
print("Hello, %s!" % (name))
main()
explanation/notes
Above we define a short function called main, and then
call the function on the very last line. Remember, for functions,
anything indented is part of the function, so the first unindented
line (in this case, the call to main()
) marks the end of the function
definition above.
Most programs have a main function that drives the whole program.
Reading through main()
should give the reader a good overview of what
the whole program does (like an outline). And just like other functions,
if main()
is more than one screen, it’s probably too long (and should
be broken up into more functions).
A common practice is to put def main()
as the first function defined
in the file, with others below. This makes it easy to see/find when you
open the program for editing.
another example
def main():
printRules()
score = 0
GAMEOVER = False
while not GAMEOVER:
displayBoard(score)
score = Turn(score)
if score < 0:
GAMEOVER = True
print("Thanks for playing!!")
As you can probably guess, the above is a main()
function from a simple
game. Another function (printRules()
) is called to display the rules of
the game, then the board is displayed and the user takes
a turn. This repeats (display, turn, display, turn, …) until the game is over.
See also:
Strings
A string is a sequence of characters between single or double quotes. The characters can be letters, digits, punctuation, spaces, etc.
example
>>> S = "hello" >>> len(S) 5 >>> print(S[0]) h >>> print(S[4]) o
explanation/notes
Each character in a string has a position, also called an index. In python, positions start at 0, so the "h" in the above string is at position 0, and the "o" is at position 4 (note: one less than the length of the string).
You can access individual characters in a string using square-bracket indexing:
>>> print(S[2]) l >>> print(S[3]) l >>> print(S[4]) o
Any sequence in python can be used in a for
loop. For strings, we can
either loop over characters in the string or indices (0 to len(S)-1
).
Here are a few examples:
>>> S = "hello" >>> for ch in S: ... print(ch) ... h e l l o >>> for i in range(len(S)): ... print(i,S[i]) ... 0 h 1 e 2 l 3 l 4 o
Strings are immutable, which means you cannot change individual characters in a string. For example, this doesn’t work:
>>> name = "jeff" >>> name[0] = "J" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment
However, you can create new strings from parts of existing
strings. Slicing (using [:]
to pick out part of the original string) and
concatenation (using the +
operator) are useful for doing this:
>>> name = "jeff" >>> name = "J" + name[1:] >>> print(name) Jeff
Here are some more slicing examples:
>>> S = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" >>> first10 = S[:10] >>> print(first10) ABCDEFGHIJ >>> last10 = S[len(S)-10:] >>> print(last10) QRSTUVWXYZ >>> middle = S[10:20] >>> print(middle) KLMNOPQRST
string concatenation
We can use the accumulator pattern to grow or accumulate a string:
>>> S = "" >>> for i in range(5): ... S = S + str(i) ... print(S) ... 0 01 012 0123 01234
In the above code, str(i)
converts the current value of i
to a string.
This is then added to the current value of S
, and assigned back to the
variable S
.
comparing strings
Strings are encoded using the
ASCII
encoding scheme. This just means a numeric value is assigned to each
possible character (+,-./0123….ABCD…XYZ…abcd…xyz…
).
When you compare strings, they are compared
by these numeric values. It is not important to know the ASCII values, but
you should remember that the ASCII values for 'a' to 'z',
'A' to 'Z' and '0' to '9' are contiguous. This means comparing two
lowercase strings works as you would expect:
>>> "apple" < "banana" True >>> "zebra" > "pony" True
and comparing two uppercase strings also works:
>>> "Rich" > "Jeff" True >>> "Jeff" > "Sara" False
You can also test if a substring is present in another string using the in
(membership) operator:
>>> "a" in "computer science" False >>> "the" in "well hello there" True >>> "LL" in "hello" False
ord()
and chr()
If you are curious, you can convert single characters to their ASCII values
using the ord()
function (and convert back using chr()
).
The ASCII values alone are not that useful, but comparing them and doing
math with them can often be useful.
>>> ch = "C" >>> ord(ch) 67 >>> difference = ord(ch) - ord("A") >>> print(difference) 2 >>> ord(ch) + difference 69 >>> chr(ord(ch) + difference) 'E'
common string methods
Strings are objects in Python, and thus have methods that
we can invoke on them.
There are a lot of methods in the str
library for creating new
string objects from existing string objects and for testing properties
of strings. Keep in mind that strings are immutable!
Here are a few str
methods that may be particularly useful (run help(str)
in the python interpreter to see the full set):
str method | result |
---|---|
upper() |
return copy of str converted to uppercase |
lower() |
return copy of str converted to lowercase |
isalpha() |
return True if string is all alphabetic characters |
isdigit() |
return True if string is all digits |
count(sub) |
return number of occurrences of sub |
index(sub) |
return index of first occurrence of sub |
strip() |
strip off leading and trailing whitespace |
split() |
split into list of "words" (see below) |
>>> S = "we LOVE cs" >>> S.upper() 'WE LOVE CS' >>> S.lower() 'we love cs' >>> S.isalpha() False >>> S.isdigit() False >>> S.count(" ") 2 >>> S.index("L") 3 >>> S.split() ['we', 'LOVE', 'cs'] >>> S = " we love cs " >>> len(S) 17 >>> S = S.strip() >>> len(S) 10 >>> print(S) we love cs
converting between strings and lists
Often, in programs that manipulate strings, you want to convert from a string to a list or from a list to a string (due to lists being mutable and strings being immutable).
To convert any string to a list of individual characters,
use the list()
function:
>>> S = "ABCDEFG" >>> L = list(S) >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G']
Use the split()
string method to split a string into substrings. The substrings
are returned as a list. If no argument is given, it will split on whitespace.
Using an argument, we can split on any substring:
>>> S = "we love cs" # split on spaces >>> L = S.split() >>> print(L) ['we', 'love', 'cs']
>>> S = "jeff:rich:sara:david" # split on colons >>> L = S.split(":") >>> print(L) ['jeff', 'rich', 'sara', 'david']
Use the join()
string method to convert a list back to a string.
Here’s a quick example:
>>> print(L) ['jeff', 'rich', 'sara', 'david'] >>> S = "".join(L) >>> print(S) jeffrichsaradavid >>> S = "XXXX".join(L) >>> print(S) jeffXXXXrichXXXXsaraXXXXdavid
Whatever string is used as the object ("" or "XXXX"), it is inserted between each item in the list when making the new string.
See also:
Lists
example
>>> names = ["Kevin", "Andy", "Lauri", "Jeff"] >>> for name in names: ... print("Hello, %s!" % (name)) ... Hello, Kevin! Hello, Andy! Hello, Lauri! Hello, Jeff!
explanation/notes
A list is a sequence of items, where each item could be anything (an integer, a float, a string, etc), even another list!
Like strings, lists have a length: the number of items in the list.
>>> L = ["pony","donkey","zebra"] >>> print(len(L)) 3
Each item in a list has a position, also called an index. In python, positions start at 0, so the string "pony" in the above list is at position 0, and "zebra" is at position 2.
You can access individual items in a list using square-bracket indexing:
>>> print(L[2]) zebra >>> print(L[1]) donkey
Any sequence in python can be used in a for
loop.
For lists, we can either loop over items in the list (see names
list
above) or indices. Here is an example using range()
to loop over indicies:
>>> L = ["pony","donkey","zebra"] >>> for i in range(len(L)): ... print(i,L[i]) ... 0 pony 1 donkey 2 zebra
Unlike strings, lists are mutable . This means their contents can be modified, without having to create a new list.
>>> L = ["pony","donkey","zebra"] >>> L[2] = "horse" # assign to position 2 in the list >>> print(L) ["pony","donkey","horse"]
The in
(membership) operator also works for lists:
>>> positives = ["y","Y","yes","Yes","YES"] >>> "no" in positives False >>> "yes" in positives True
common list methods
Lists are objects in Python, and thus have methods that
we can invoke on them. Here are a few that may be particularly useful
(run help(list)
in the python interpreter to see the full set):
list method | result |
---|---|
append(item) |
add item to end of list |
insert(index,item) |
insert item at index |
extend(L1) |
add list L1 to original list |
sort() |
sort the list |
reverse() |
reverse the list |
count(item) |
return number of occurrences of item in list |
index(item) |
return index of first occurrence of item |
pop(index) |
remove and return item at index |
>>> L = list("ABCDEFG") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> L.append("X") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X'] >>> L.extend(["Y","Z"]) >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X', 'Y', 'Z'] >>> L.reverse() >>> print(L) ['Z', 'Y', 'X', 'G', 'F', 'E', 'D', 'C', 'B', 'A'] >>> L.sort() >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'X', 'Y', 'Z'] >>> L.count("E") 1 >>> L.index("E") 4 >>> L.pop(4) 'E' >>> print(L) ['A', 'B', 'C', 'D', 'F', 'G', 'X', 'Y', 'Z'] >>> L.insert(1,"hello") >>> print(L) ['A', 'hello', 'B', 'C', 'D', 'F', 'G', 'X', 'Y', 'Z']
converting between strings and lists
Often, in programs that manipulate strings, you want to convert from a string to a list or from a list to a string (due to lists being mutable and strings being immutable).
To convert any string to a list of individual characters,
use the list()
function:
>>> S = "ABCDEFG" >>> L = list(S) >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G']
Use the split()
string method to split a string into substrings. The substrings
are returned as a list. If no argument is given, it will split on whitespace.
Using an argument, we can split on any substring:
>>> S = "we love cs" # split on spaces >>> L = S.split() >>> print(L) ['we', 'love', 'cs']
>>> S = "jeff:rich:sara:david" # split on colons >>> L = S.split(":") >>> print(L) ['jeff', 'rich', 'sara', 'david']
Use the join()
string method to convert a list back to a string.
Here’s a quick example:
>>> print(L) ['jeff', 'rich', 'sara', 'david'] >>> S = "".join(L) >>> print(S) jeffrichsaradavid >>> S = "XXXX".join(L) >>> print(S) jeffXXXXrichXXXXsaraXXXXdavid
Whatever string is used as the object ("" or "XXXX"), it is inserted between each item in the list when making the new string.
another example
Here’s a list-of-lists example:
>>> LOL = [["jeff", 77], ["lila", 99.0], ["joshua", 87.3]] >>> for item in LOL: ... print("%s's final grade is %.1f" % (item[0], item[1])) ... jeff's final grade is 77.0 lila's final grade is 99.0 joshua's final grade is 87.3
See also:
Slicing
Slicing is useful for pulling out parts of strings or lists. For example, if you just want the first 6 characters of a string, or the last two items in a list.
example
>>> first = "luke" >>> last = "skywalker" >>> first[0] + last[0:6] + "1" 'lskywal1' >>> >>> L = list("ABCDEFG") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> print(L[2:5]) ['C', 'D', 'E'] >>> print(L[5:]) ['F', 'G'] >>> print(L[:2]) ['A', 'B']
explanation/notes
Using square-bracket indexing and the slicing operator (":"),
the last[0:6]
statement grabs just the first six characters
(0 through 5) from the last
string.
The slicing syntax is [start:stop]
, meaning grab all items or
characters from index start
up to but not including index stop
.
In the list example, L[2:5]
grabs items from the list from positions
2 through 4 (does not include item at position 5).
Leaving off the start (e.g., L[:2]
) defaults to the beginning of
the sequence. Leaving off the stop (L[5:]
)
defaults to the end of the sequence.
It’s also OK if the stop is past the end of the sequence:
>>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> L[5:20] ['F', 'G'] >>> >>> S = "hello" >>> S[3:20] 'lo'
Objects and Methods
This section is just the basics of objects and methods: what they are, and how we use them. See Classes if you are looking for help on creating your own objects.
example
>>> course = "Introduction to Computer Science" >>> course.count("o") 4 >>> course.count("z") 0 >>> course.isalpha() False >>> course.upper() 'INTRODUCTION TO COMPUTER SCIENCE'
>>> grades = [88,90,78,99,93] >>> grades.sort() >>> print(grades) [78, 88, 90, 93, 99] >>> grades.append(75) >>> print(grades) [78, 88, 90, 93, 99, 75]
explanation/notes
Both python strings and python lists are examples of objects. An object is just some data plus some methods (similar to functions) wrapped up together into one thing.
The string methods used above are:
-
count()
— returns the number of occurrences of the given substring -
isalpha()
— returns True if all characters in the string are letters -
upper()
— returns an uppercase version of the string
There are many other str methods. In string objects, the data are the characters in the string.
The list methods used above are:
-
sort()
— sorts the list in place -
append()
— adds the given argument to the end of the list
In list objects, the data are the items in the list.
object.method()
syntax
Methods are always called with the dot syntax: object.method()
Again, methods are similar to functions, except they are tied to the type of object, and are called with this special syntax.
another example
>>> from graphics import * >>> gw = GraphWin() >>> p = Point(10,20) >>> c = Circle(p, 50) >>> c.draw(gw) >>> c.move(150,0)
This example uses the Zelle Graphics Library.
Three objects are created: a graphics window, a point, and a circle. The circle
is centered at the point’s location (x=10, y=20), and has a radius of 50.
The next line calls the Circle’s draw()
method to draw the circle in the
graphics window. The last line moves the drawn circle 150 pixels in the x direction.
See also:
import
statements
Python libraries contain commonly-used functions. In order to use the functions, we need to first import the correct library.
example
Here’s an example of importing the python math
library, to gain
access to the sqrt()
function:
from math import *
for i in range(1,6):
result = sqrt(i)
print("Sqrt(%d) = %.2f" % (i, result))
Running the above code would produce this output:
Sqrt(1) = 1.00 Sqrt(2) = 1.41 Sqrt(3) = 1.73 Sqrt(4) = 2.00 Sqrt(5) = 2.24
explanation/notes
In python there are two common ways to import libraries:
from math import * import math result = sqrt(5) result = math.sqrt(5)
The example on the left is typically used in our intro courses, as it requires less typing and makes short codes easier to read.
For larger, more complex codes, the example on the right is preferred.
Calling the function as math.sqrt()
avoids any possibility of two
functions from different libraries having the same name (i.e., if they
did have the same name, calling them as library.function()
would
allow us to know which library each was from).
Some useful python libraries include:
library | description | functions |
---|---|---|
|
basic mathematical functions |
|
|
random number functions |
|
|
manipulate time values |
|
To see documentation on any library, simply import the library and
then call the help()
function:
>>> import math >>> help(math)
Use 'q' to quit the help documentation.
Usually all import statements are at the top of the file, before any code or function definitions:
"""
Comments...
"""
from math import *
from random import *
def main():
main code here...
main code here...
main code here...
main()
another example
>>> from random import * >>> L = list("ABCDEFG") >>> choice(L) 'E' >>> choice(L) 'A' >>> choice(L) 'F'
You can also just import one function if you know that’s all you need:
>>> from math import sqrt >>> result = sqrt(5)
See also:
random
library
The python random
library provides pseudo-random numbers
for your programs (useful for games, etc). There are also
functions to choose a random item from a list or sequence.
example
>>> from random import * >>> randrange(1,101) 60 >>> randrange(1,101) 24 >>> randrange(1,101) 35 >>> randrange(1,101) 91 >>> L = list("ABCDEFG") >>> choice(L) 'C' >>> choice(L) 'D' >>> choice(L) 'F' >>> choice(L) 'B'
explanation/notes
To use the random
library, we first need to
import
it.
The randrange(start,stop)
function picks a random number
from start
to stop - 1
, so the above example is choosing a
random number from 1-100.
The choice(sequence)
function picks a random item from a sequence
(here a python list).
function | description | example |
---|---|---|
|
pick random integer from range |
|
|
pick random item from sequence |
|
|
pick random number from [0-1) |
|
|
shuffle list in place |
|
another example:
>>> from random import * >>> if random() >= 0.5: ... print("Heads") ... else: ... print("Tails") ... Tails
See also:
while
(indefinite) loops
example
Sometimes you want to repeat a code block, but you don’t know exactly how many times to repeat. For example, in a game like tic-tac-toe, you might want to get the player’s move, then update board, then get the next player’s move, and so on, until the game is over. The "get move, update board" code might be executed 5 or more times. This is called an indefinite loop.
Here’s an example using random numbers, so we don’t know how many times the code block will run, and each time we run this code the output will be different (because the random numbers chosen will be different):
from random import *
value = 0
limit = 10
while value < limit:
print("value: %2d -- limit = %2d" % (value, limit))
print("picking random number from 1-10...")
randnumber = randrange(1,11)
print(">>>>> picked %d" % randnumber)
if randnumber > 6:
value = value + 2
print("-"*30)
print("Done!")
Here’s one example of running the above code:
value: 0 -- limit = 10 picking random number from 1-10... >>>>> picked 7 value: 3 -- limit = 10 picking random number from 1-10... >>>>> picked 8 value: 6 -- limit = 10 picking random number from 1-10... >>>>> picked 4 value: 6 -- limit = 10 picking random number from 1-10... >>>>> picked 10 value: 9 -- limit = 10 picking random number from 1-10... >>>>> picked 8 ------------------------------ Done!
explanation/notes
The above while
loop keeps picking random numbers as long as (while)
value
is less than limit
. Note that in the code block (the indented
code below the while value < limit
line), it is possible that
value
will be changed (increased by 2), if the random number chosen
is greater than 6.
The while
loop syntax is:
while <boolean expression>: do this line and this indented line and this indented line
This looks just like the if
statement, and it is, except that after the code block is
run, we go back to the top and re-check the boolean expression. If the boolean expression
is still True
, we run the code block again. As long as (while) the boolean expression
evaluates to True
, we’ll keep running the code block. After each run of the code block,
we re-check the boolean expression to see if it is True
or False
. Once it’s False
, we
skip the code block and continue on with the rest of the program.
Don’t confuse the if
statement with the while
loop!
if x < 20: while x < 20: do this line do this line
Both of those will execute the "do this line" if x
is less than 20.
The while
loop will then go back and re-check if x
is still less than
20, where the if
code will continue on with the rest of the program.
What do you think this code will do?
x = 0
while x < 100:
print(x)
print("--------------------")
This is an infinite loop, that will just print 0 and a dashed line over and
over and over. You can use Ctrl-c
to kill a program stuck in an infinite loop.
another example
Have you ever used Duolingo, where the owl cheers you on, and notices when you give the correct answer three times in a row?
from random import *
factor = 9
inarow = 0
while inarow < 3:
otherfactor = randrange(2,13) # pick number 2-12
answer = factor * otherfactor # calculate the right answer
question = "What is %d*%d? " % (factor,otherfactor)
useranswer = int(input(question)) # get user's answer
if useranswer == answer:
inarow = inarow + 1
else:
print("Nope...answer = %d" % answer)
inarow = 0
print("Three in a row...good work!")
And here’s one possible run of the above code:
What is 9*7? 63 What is 9*10? 90 What is 9*2? 19 Nope...answer = 18 What is 9*12? 108 What is 9*5? 45 What is 9*8? 72 Three in a row...good work!
See also:
Functions: advanced
Functions make your programs easier to read, write, design, debug, and test. Once you understand how functions work, they will make your programming life much much easier!
This section describes some important details about functions in python:
-
scope/variables
-
stack diagrams
-
mutable objects in functions
scope and variables
A variable’s scope refers to where a variable is valid.
For example, in this program with two functions, main()
and
times2()
, the variable factor
is in scope (i.e., valid)
only in times2()
:
def main():
x = 5
result = times2(x)
print("result: ", result)
print(" x: ", x)
def times2(factor):
factor = factor*2
return factor
main()
If we added a print(factor)
statement in main()
, the program
would crash, since factor
is not defined or valid in main()
:
print(factor) NameError: name 'factor' is not defined
Similarly, the variable x
is only valid (in scope) in main()
.
Trying to use x
in times2()
would also cause a runtime error.
Furthermore, it does not matter what the factor
variable in times2()
is called! We could name it x
, but that would be a different x
than the one defined in main()
.
Here’s the code again, this time with the variable in times2()
defined as x
:
def main():
x = 5
result = times2(x)
print("result: ", result)
print(" x: ", x)
def times2(x):
x = x*2
return x
main()
And here’s the output from running that code:
result: 10 x: 5
Notice that the x
printed in main()
, after the times2()
function
was called, still has the value 5 (even though the x
in times2()
was
set to 10).
stack diagrams
You can easily see a variable’s scope if you view the program’s stack
diagram using the python tutor. Here’s an image
of the above code (with x
in each function) running in the
python tutor:
On the right of that image are three stack frames: Global (which we
are ignoring), main, and times2. We have used the python tutor "Forward>"
button to step through the program, one statement at a time. First
main()
was called, then main()
called times2()
on line 3, and we
are currently stopped at the end of times2()
(line 9), about to
return x
.
For the stack, each time a function is called, a new stack frame is
created and placed "on top" of the stack. All of that function’s variables
are defined in that stack frame and have local scope. As you can see, there
is an x
in main()
with value 5, and there is an x
in times2()
with value 10. Even though we used the same name, there are two
different x
variables. Each variable is local in scope to that
function.
The stack is useful for seeing what variables are in scope, but also for
keeping track of where we are in the execution of the program. If
main()
calls functionA()
and functionA()
calls functionB()
,
the stack would look like this:
In the python tutor the stack is always drawn increasing toward the bottom of the window, but it is more useful to think of the stack as a stack of trays or dishes: the one on top is the current tray/dish (the one you would grab). The function on "top" of the stack is the one currently running. When that function finishes and returns, control drops back to the function one "below" on the stack.
This is how the "Back" button on your browser works, or the "Undo" option in an editor works. All visited web pages (or editor changes) are kept in a stack. The item on "top" of the stack is the current item. For the browser, if you hit the "Back" button, the page on top of the stack is removed and the browser goes back to the previous page (the next page down in the stack).
mutable objects
In python, mutable objects are not copied to local variables in
functions. Instead, they are passed to functions by reference.
This means, for example, if you send a python list to a function, and
in that function you change an item in the list, that change will be
visible back in main()
:
def main():
L = list("ABCD")
print(L)
change2(L)
print(L)
def change2(mylist):
mylist[2] = "pony"
# note...no return statement needed
main()
Here’s the result of running that program:
$ python3 function-list.py ['A', 'B', 'C', 'D'] ['A', 'B', 'pony', 'D']
You can again easily see this in the python tutor:
See how both L
in main()
and mylist
in change2()
both point to the same list data! Both variables refer
back to the same list stored in the memory of the computer.
Assigning mylist[2]
in change2()
to some other value ("pony")
has the side-effect of also changing L
in main()
, since they both
refer back to the same list.
This feature is useful, but often confusing to first-time programmers.
It is useful, say, if you pass a 1-million-element list to a function. If python made a copy of that list, it would take time and be inefficient.
It is confusing because the function can change items in a list (or any items in a mutable python object), and those changes are seen outside of the function, and the function doesn’t have to return anything. This is exactly the opposite of what we talked about above, with variables in functions and local scope.
Here’s a simple example of using a function that modifies a list without returning anything from the function:
>>> from random import shuffle >>> L = list("ABCDEFG") >>> print(L) ['A', 'B', 'C', 'D', 'E', 'F', 'G'] >>> shuffle(L) >>> print(L) ['E', 'B', 'F', 'C', 'A', 'G', 'D'] >>> shuffle(L) >>> print(L) ['C', 'D', 'A', 'F', 'G', 'B', 'E']
See also:
Files
example
$ cat poem.txt Roses are red. Violets are blue. Sugar is sweet. And so are you! $ python3 >>> infile = open("poem.txt", "r") >>> lines = infile.readlines() >>> print(lines) ['Roses are red.\n', 'Violets are blue.\n', 'Sugar is sweet.\n', 'And so are you!\n']
explanation/notes
The variable infile
stores the file object returned by
the open()
function. We have opened the file named "poem.txt"
for reading (using the "r" argument). The readlines()
method
reads in all lines from the file and returns them as a list
of strings. We assign this list of strings to the lines
variable.
Note how each line from the file ends with a newline character
(the '\n').
For file objects, here are the frequently-used methods:
method | description | example | returns |
---|---|---|---|
|
reads all lines from file |
|
list of strings |
|
reads one line from file |
|
string |
|
closes the file |
|
nothing |
|
writes one line to file |
|
number of chars written |
another example
Files are another example of a sequence in python (like strings and
lists). We can use sequences in for
loops, so we could also read in
all lines from a file like this:
inf = open("poem.txt", "r")
lines = []
for line in inf:
lines.append(line)
inf.close()
This does exactly the same thing as the previous example. It’s just
shown here as an example of iterating over each line in the file.
Sometimes you want to process the data line-by-line, as you read each
line in (instead of reading them all in at once with readlines()
).
writing to files
Similar to reading, but the file is opened with the "w" flag:
>>> outfile = open("newfile", "w") >>> outfile.write("We love CompSci!!\n") >>> outfile.write("Here's another line...\n") >>> outfile.close() >>> $ cat newfile We love CompSci!! Here's another line... $
Note how we have to include the newline character ('\n') at the end of each string we write. Otherwise the file would contain just one long line. Also, if the file already exists, and we open it for writing, any data already in the file is wiped out and replaced by whatever we write.
See also:
Classes
Classes allow us to design and create our own objects! Object-oriented programming (OOP) is crucial for large programs, often written by multiple people. It greatly simplifies writing, testing, and debugging if the objects/classes can be written and tested on their own, then used in larger programs. OOP also promotes code reuse if the objects can be used in other programs.
example
Imagine you are a teacher, and you want to keep track of your students and their grades for the semester! :)
Here is a Student
object (in a file called student.py
), where all
students have a name, class year, username, quiz grades, and lab grades:
class Student(object):
"""student objects"""
def __init__(self, name, year, username):
"""constructor, given student name, year, username"""
self.name = name
self.year = year
self.username = username
self.quizzes = [] # initially, no quiz
self.labs = [] # or lab grades
def __str__(self):
"""this one *must* return a string"""
s = "%s (%s) -- %d" % (self.name, self.username, self.year)
s += "\n%s\n%s" % (self.quizzes, self.labs)
return s
def addQuizGrade(self, qgrade):
"""add a given grade to the quizzes list"""
self.quizzes.append(qgrade)
def addLabGrade(self, lgrade):
"""add a given grade to the labs list"""
self.labs.append(lgrade)
def currentGrade(self):
"""
calculate and return current grade.
quizzes are 60%, labs 40% of total grade
"""
quizavg = 0.0
if len(self.quizzes) > 0:
quizavg = sum(self.quizzes)/len(self.quizzes)
labavg = 0.0
if len(self.labs) > 0:
labavg = sum(self.labs)/len(self.labs)
grade = quizavg*.60 + labavg*.40
return grade
#####################################################
def main():
s1 = Student("Lee Majors", 2020, "lmajors1")
print(s1)
s2 = Student("Lindsay Wagner", 2022, "lwagner2")
print(s2)
s1.addQuizGrade(78)
s1.addQuizGrade(75)
s1.addQuizGrade(83)
s1.addLabGrade(91)
s1.addLabGrade(90)
print(s1)
print(s1.currentGrade())
print(s2.currentGrade())
if __name__ == "__main__":
main()
explanation/notes
The code in the def main()
part at the bottom is solely for testing purposes
(for the person writing the class), and it is not part of the class definition.
It is run only if the file is run: python3 student.py
,
and not if the file is imported (from student import *
). This test code is
very simple, and just tests some of the methods. It also shows how to use the class.
the __init__
method
In the test code you can see two different student objects (s1
and s2
)
are created by calling the name of the class: Student(…)
. Calling the
name of the class invokes the constructor method: __init__(…)
. This creates
the object with the given data (name, year, username). In this particular case,
it also creates the empty lists that will hold the student’s quiz and lab grades.
what is self
???
All of the self.xxxxx
variables in the constructor are data stored in each
object. The self
part refers back to which object (e.g., s1
or s2
). So the
class year 2020 is stored in the first object’s self.year
variable, and the
username "lwagner2" is stored in the second object’s self.username
variable.
If you want data stored in an object, create a self.xxxxx
variable in
the class constructor (the __init__()
function). These self.xxxxx
variables
are sometimes called instance variables, because they exist for every instance
of the class (i.e., all Student
objects).
Note how the self.xxxxx
variables are used in the other methods (like currentGrade()
),
and they don’t have to be passed around as arguments and parameters. Any self.xxxxx
variable
defined in the constructor (__init__()
) can be used in any other method in the
given class.
methods
After the objects are created, we can modify or access the data stored in the objects using the other methods in the class. For example, the teacher might want to add grades to each student object:
s1.addQuizGrade(83) s1.addLabGrade(91)
These two methods add data to the self.quizzes
and self.labs
variables.
Methods are just like functions, but they belong to a specific class, and are
called using the object.method()
syntax.
the __str__
method
The str method is automatically invoked anytime an object is printed
(e.g., print(s1)
). You can control how you want your object’s data to appear
by changing the string that __str__
returns. This method is often very helpful
when debugging a class, as you can print your objects and see what data they contain.
class Writer vs class User
In OOP, it is often useful to keep in mind these two roles: the person writing the class, and the person using the class. Sometimes you’re doing both, but other times you may just be using a class someone else wrote.
The methods in the class definition provide the class user with ways to interact with the object and it’s data. If you are writing a class, you need to think about how people will use the class, and provide methods for all that they might want to do. If you are using a class, you’ll need to study the methods for how best to use the objects, and what operations are possible.
another example
Suppose I want to write a stats program to keep track of data on all NBA players. I could make a python list for each player, where in the list I store the player’s name, team, total points scored, etc. But then my whole program would involve lists and indexing, and be much harder to read (e.g., player[0] would be the player’s name, player[1] would be the player’s team, etc).
Instead, let’s make an NBAPlayer object and store all data for a player in the object:
class NBAPlayer(object):
"""class for single NBA player object"""
def __init__(self, name, number, team):
"""constructor for player object, given name, etc"""
# any self.whatever variable is DATA for this object,
# and can be used in any methods in this class
self.name = name
self.number = int(number) # jersey number
self.team = team
self.gp = 0 # games played
self.pts = 0 # total points scored
def __str__(self):
"""pretty-format info about this object, return a string"""
s = "%s #%d -- Team: %s" % (self.name, self.number, self.team)
s += "\nGP: %d, PTS: %d" % (self.gp, self.pts)
return s
def playGame(self, points):
"""example of adding data to player object"""
self.gp += 1 # one game played
self.pts += points # add to total points scored
def ppg(self):
"""calculate average points per game"""
if self.gp == 0:
return 0
else:
ave = self.pts/float(self.gp)
return ave
def trade(self,newteam):
"""change team to newteam"""
self.team = newteam
def getName(self):
"""getter for player's name"""
return self.name
def getTeam(self):
"""getter for player's team"""
return self.team
Now the user of this class could write code like this to keep data on a particular player:
from nbaplayer import *
p1 = NBAPlayer("Jeff Knerr", 11, "Philadelphia 76ers")
print(p1)
p1.playGame(20) # a good game!
p1.playGame(10) # so-so...
print(p1)
print("%s is averaging %5.1f points/game" % (p1.getName(), p1.ppg()))
p1.playGame(3) # Jeff not playing well....let's trade him
p1.trade("New York Knicks")
print(p1)
Running the above code produces the following output:
Jeff Knerr #11 -- Team: Philadelphia 76ers GP: 0, PTS: 0 Jeff Knerr #11 -- Team: Philadelphia 76ers GP: 2, PTS: 30 Jeff Knerr is averaging 15.0 points/game Jeff Knerr #11 -- Team: New York Knicks GP: 3, PTS: 33
See also:
Dictionaries
Dictionaries are great for storing key-value mappings or pairs.
example
Suppose you wanted to convert letters into their equivalent Morse Code dots and dashes:
>>> d = {} >>> d['a'] = ".-" >>> d['b'] = "-..." >>> d['c'] = "-.-." >>> print(d) {'a': '.-', 'b': '-...', 'c': '-.-.'} >>> print(d['a']) .-
Here the letters ('a','b', and 'c') are the keys, and the dot/dash strings are the values. The first line creates an empty dictionary (using curly-braces). The next three lines add key-value pairs into the dictionary.
If we had the full Morse Code dictionary defined:
morse = {'a': '.-', 'b': '-...', 'c': '-.-.', 'd': '-..', 'e': '.',
'f': '..-.', 'g': '--.', 'h': '....', 'i': '..', 'j': '.---',
'k': '-.-', 'l': '.-..', 'm': '--', 'n': '-.', 'o': '---',
'p': '.--.', 'q': '--.-', 'r': '.-.', 's': '...', 't': '-',
'u': '..-', 'v': '...-', 'w': '.--', 'x': '-..-', 'y': '-.--',
'z': '--..'}
then we could use it to lookup values, given letters. Here’s a quick example:
for ch in "sos":
print(morse[ch])
This would print three dots for the 's', then three dashes for the 'o', and then another three dots for the last 's'.
explanation/notes
Dictionaries are useful for any kind of key-value lookup system. For example, usernames and passwords:
passwords = {'terry':'lovesYogurt', 'jake':'DieHard5',
'amy':'MoreBinders', 'holt':'Cheddar!!'}
Given a username (e.g., 'jake'), we can lookup the password in the dictionary (passwords['jake']).
another example
There are a variety of useful methods for dictionary objects:
>>> passwords.keys() dict_keys(['terry', 'jake', 'amy', 'holt']) >>> passwords.values() dict_values(['lovesYogurt', 'DieHard5', 'MoreBinders', 'Cheddar!!']) >>> passwords.items() dict_items([('terry', 'lovesYogurt'), ('jake', 'DieHard5'), ('amy', 'MoreBinders'), ('holt', 'Cheddar!!')]) >>> for k in passwords: ... print(k, passwords[k]) ... terry lovesYogurt jake DieHard5 amy MoreBinders holt Cheddar!!
The last example shows dictionaries can be used in a for
loop,
with the loop variable becoming each key in the dictionary.
See also:
Tuples
Tuples are just like python lists, except they use parentheses, and are immutable.
example
>>> T = (1,2,3,4) >>> print(T) (1, 2, 3, 4) >>> print(type(T)) <class 'tuple'> >>> x = T[0] + T[2] >>> print(x) 4 >>> T[0] = 42 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>>
explanation/notes
Tuples are useful if you want a list-like data structure, but you want to make sure it can’t be changed later in the program. They can also be used as keys in Dictionaries.
We don’t use tuples much in CS21, but they are included here so you know what they are. Sometimes they are mentioned in error messages. Here’s the most-common error involving tuples in CS21 (forgot to use 'Point' when defining a graphics point object):
>>> from graphics import * >>> p = (100,200) # <-- should have been Point(100,200) >>> c = Circle(p, 25) Traceback (most recent call last): File "<stdin>", line 1, in <module> graphics.TypeError: When calling Circle constructor, argument should have type Point but instead has type tuple.
another example
This is also not used much, and somewhat discouraged in CS21, but returning multiple items from a function will automatically put them in a tuple:
def minmax(L):
"""given a list, find and return min and max of list"""
min = L[0]
max = L[0]
for item in L:
if item < min:
min = item
if item > max:
max = item
return min,max
Here’s the output from running the above function:
>>> result = minmax([30,45,-4,200,5,6,37,99]) >>> print(result) (-4, 200) >>> print(type(result)) <class 'tuple'>
See also:
ord
and chr
example
>>> ord('a') 97 >>> ord('b') 98 >>> ord('c') 99 >>> chr(97) 'a' >>> chr(98) 'b' >>> chr(65) 'A'
explanation/notes
Sometimes it is useful to compare letters and strings, or to do "math" on letters (e.g., if I have a letter, give me the 5th letter after the one I have).
The computer is able to compare letters and strings because, underneath, the computer just sees letters as numbers. This is called an encoding, and one of the most-famous encodings is the ASCII encoding:
000 nul |
001 soh |
002 stx |
003 etx |
004 eot |
005 enq |
006 ack |
007 bel |
008 bs |
009 tab |
010 nl |
011 vt |
012 np |
013 cr |
014 so |
015 si |
016 dle |
017 dc1 |
018 dc2 |
019 dc3 |
020 dc4 |
021 nak |
022 syn |
023 etb |
024 can |
025 em |
026 sub |
027 esc |
028 fs |
029 gs |
030 rs |
031 us |
032 sp |
033 ! |
034 " |
035 # |
036 $ |
037 % |
038 & |
039 ' |
040 ( |
041 ) |
042 * |
043 |
044 , |
045 - |
046 . |
047 / |
048 0 |
049 1 |
050 2 |
051 3 |
052 4 |
053 5 |
054 6 |
055 7 |
056 8 |
057 9 |
058 : |
059 ; |
060 < |
061 = |
062 > |
063 ? |
064 @ |
065 A |
066 B |
067 C |
068 D |
069 E |
070 F |
071 G |
072 H |
073 I |
074 J |
075 K |
076 L |
077 M |
078 N |
079 O |
080 P |
081 Q |
082 R |
083 S |
084 T |
085 U |
086 V |
087 W |
088 X |
089 Y |
090 Z |
091 [ |
092 \ |
093 ] |
094 ^ |
095 _ |
096 ` |
097 a |
098 b |
099 c |
100 d |
101 e |
102 f |
103 g |
104 h |
105 i |
106 j |
107 k |
108 l |
109 m |
110 n |
111 o |
112 p |
113 q |
114 r |
115 s |
116 t |
117 u |
118 v |
119 w |
120 x |
121 y |
122 z |
123 { |
124 | |
125 } |
126 ~ |
127 del |
So the computer sees the letter 'a' as 97, 'b' as 98, and 'c' as 99. That’s why these work:
>>> 'a' < 'b' True >>> 'b' < 'c' True >>> 'apple' < 'banana' True >>> 'apple' < 'azure' True
ord()
and chr()
allow you to convert back and forth between letters
(or punctuation and other characters) and their ASCII encoding numbers.
another example
word = "dog"
newword = ""
for letter in word:
newnumber = ord(letter) + 3
newletter = chr(newnumber)
newword = newword + newletter
print(word, newword)
In the above example we use ord(letter)
to turn the letter into a number,
add 3 to it, then use chr(newnumber)
to get the letter for that new number.
If the letter were an 'a', the newletter would be a 'd'. This is often used
in simple cipher programs to shift letters in a string by
some amount. The above example would print "dog grj".
Note: if the word was "xyz", what would the new "word" be? To be a "rotation cipher" the above code would have to test if the new number was past the end of the alphabetic characters ('z' or 122), and if so, subtract 26 from the new number.
Also, note that all of the capital letters ('A' - 'Z') are before the lowercase letters, so when comparing strings, make sure the case is the same!
>>> "APPLE" < "apple" True >>> "banana" < "APPLE" False >>> "BANANA" < "apple" True
See also:
try/except
In previous examples, when getting a number from the user, we just blindly converted it from a string to an int or a float:
age = float(input("How old are you? "))
This will of course crash the program if the user enters something that can’t be converted to a float:
How old are you? pony Traceback (most recent call last): File "tryexcept.py", line 3, in <module> age = float(input("How old are you? ")) ValueError: could not convert string to float: 'pony'
The try/except
statement gives us a way to catch the exception
(the ValueError
above) and do something about it (like give the
user another try, and not just crash the program).
example
age = input("How old are you? ")
try:
age = float(age)
except ValueError:
print("Please enter a number...")
And here’s what happens when we run that:
How old are you? zebra Please enter a number...
explanation/notes
In the above example we try to convert the input stored in age
to a float. If that succeeds, great, and the program continues with
any code below the try/except
block. If that fails with the
ValueError
exception, the except block is executed (the print
statement).
If we combine the above with a while
loop, our input statment
now repeats until we get valid input:
VALIDINPUT = False
while not VALIDINPUT:
age = input("How old are you? ")
try:
age = float(age)
VALIDINPUT = True
except ValueError:
print("Please enter a number...")
print("Thanks!")
Here we are using a boolean flag variable (VALIDINPUT
) to control
the while
loop. The loop continues as long as VALIDINPUT
is False
.
The only way VALIDINPUT
changes to True
is if the age=float(age)
statement succeeds. Here’s how it looks to the user:
How old are you? pony Please enter a number... How old are you? zebra Please enter a number... How old are you? 98-5.2 Please enter a number... How old are you? 54.2 Thanks!
another example
There are many different
exceptions in python.
You can use any of them in a try/except
statement. Here’s another
example, trying to open a file, using the FileNotFoundError
exception:
VALIDFILE = False
while not VALIDFILE:
filename = input("File to open: ")
try:
infile = open(filename, "r")
VALIDFILE = True
except FileNotFoundError:
print("I couldn't find that file...")
print("Got it!")
See also:
assert()
The assert()
function is a simple way to add semi-automatic testing to your
programs and libraries. An assert()
statement gives no output if the test
succeeds, but gives an AssertionError
if the test fails.
example
>>> assert(1==1) >>> assert(1+1==2) >>> assert(1+1!=3) >>> assert(1+1==3) Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError >>> assert("hello".upper()=="HELLO") >>> from math import sqrt >>> assert(sqrt(4)==2)
explanation/notes
In the above examples, only the fourth test fails (1+1==3
)
and crashes with an AssertionError
. If tests that pass produce
no output, you can add these statements to a test function in your code
and periodically run the test function to make sure everything is
still working (no news is good news).
another example
Suppose I wrote a binarySearch(x,L)
function that looks for x
in the
list L
, using a binary search. Here’s an example of a function I
might add, to test all possible cases I can think of:
def testcode():
"""test the binarySearch function"""
x = 5
L = [1,2,3,4,5,6,7,8,9,10]
letters = list("BCDEFGHIKLMNPQRSTWXY")
assert(binarySearch(x,L)==True)
assert(binarySearch(-20,L)==False)
assert(binarySearch("F",letters)==True)
assert(binarySearch("Z",letters)==False)
assert(binarySearch("A",letters)==False)
assert(binarySearch("A",["A"])==True)
assert(binarySearch("A",[])==False)
for item in L:
assert(binarySearch(item,L)==True)
for item in L:
assert(binarySearch(item,letters)==False)
print("All tests passed!")
If I run the testcode()
function and see the "All tests passed!"
message at the bottom, I feel confident that my search function is
working. And if I ever make changes to my search function, I can just
run the test code again to make sure I didn’t break anything.