Lecture 1 - Basic Python Programming Part 1
Lecture 1 - Basic Python Programming Part 1
CIS-275
An Example Python Program
● To begin our review of Python, let’s write simple a program that thinks of a number
and asks the user to guess what it is.
○ First, the user will be asked for an upper and lower bound on the number the
computer should think of.
○ Then, a random number between those two bounds will be generated.
○ A while loop will continue until the user guesses the number correctly.
■ If they guess too high or low, we will inform them of this.
○ After they guess correctly, we will let them know how many guesses they took.
def main():
""" Asks the user for the bounds of the range of numbers and lets the user guess
the computer's number until the guess is correct """
lower = int(input("Enter the lower bound: "))
upper = int(input("Enter the upper bound: "))
main()
Chapter 1 Basic Python Programming 3
An Example Python Program
import random
● An import statement tells Python to include the code from another module in our
program.
○ A module is a file which may contain objects, functions, or classes.
● In this example, we import the random module, which includes functions for
generating pseudorandom numbers.
● When we use an import with this syntax, we type the module name, dot operator, and
function name to access a function from the module.
● For example, to call the randint function:
main()
● The input function pauses program execution and waits for the user to type a
response and then the ‘enter’ key.
● The characters the user typed are returned as a str object.
● In this example, we pass the returned string to the int function.
● This function converts its argument to an integer (if possible).
○ If not possible (for example the user enters “Hello”), an Error is raised.
● We often want to cast user input from a string to another data type if required by our
program.
● Finally, the value returned by int is assigned to smaller.
● The randint function from the random module returns an integer between its two
arguments (both values are inclusive)
● Note: If the first argument is larger than the second, an Error is thrown.
○ In a more robust program, we would ensure the user does not input such values.
● We can pass an f-string to the print function, just as we would a normal string literal:
● The value the variable holds will be appended to the string that prints.
● As the strings we print become more complicated and contain more variables, f-strings
will make the job much easier.
● Note: A placeholder must have the name of an existing variable, otherwise an error
will occur:
name = "Jonathan"
print(f'Hello {names}!') # ERROR!
num = 10
print(f'The value is {num * 2}')
{placeholder: format-specifier}
● If the format specifier we place after the colon is recognized by Python, the output will
be formatted in a special way. Otherwise, an error will occur.
total_cost = 5000
monthly_payment = total_cost / 12
print(f'Your monthly payment is {monthly_payment}')
Prints:
The population is 17,542,142
monthy_pay = 5000.0
annual_pay = monthy_pay * 12
print(f"Your annual pay is ${annual_pay:,.2f}")
● Note that we have to include the comma format specifier before the precision
designator. Otherwise, an error will occur.
print(f'{num1:.2f} {num2:.2f}')
print(f'{num3:.2f} {num4:.2f}')
127.90 3465.15
3.78 264.86
● Even though the value that prints requires 7 spaces, three extra spaces are added to its
left to bring the total to 10.
print(f'{num1:.2f} {num2:.2f}')
print(f'{num3:.2f} {num4:.2f}')
print(f'{num1:10.2f} {num2:10.2f}')
print(f'{num3:10.2f} {num4:10.2f}')
● By having each placeholder fill a minimum number of spaces, the columns will now
be uniform in size:
127.90 3465.15
3.78 264.86
● The minimum field width specifier must be placed before the precision specifier.
● This only works if the minimum width is larger than the largest number!
Chapter 1 Basic Python Programming 21
Reference Variables and Objects
● Everything in Python is an object which is stored in the computer’s memory.
● We use reference variables to refer (or point) to these objects.
● A Python reference variable can refer to any type of object during its lifetime.
● For example, in the following three statements, the reference variable my_var refers
to three different objects:
0x0065fd40 5
my_var 0x0065fd40
0x0488C04B 5
my_var 0x0065fd40
1 2 3
0x0488C04B
Chapter 1 Basic Python Programming 24
Reference Variables and Objects
my_var = 5 # my_var points to an int object
my_var = [1, 2, 3] # my_var now points to a list object
my_var = "Hello" # my_var now points to a string object
0x0488C04B 5
my_var 0x0065fd40
1 2 3
0x0488C04B
Chapter 1 Basic Python Programming 25
Garbage Collection
my_var = 5 # my_var points to an int object
my_var = [1, 2, 3] # my_var now points to a list object
my_var = "Hello" # my_var now points to a string object
0x0488C04B 5
my_var 0x0065fd40
1 2 3
0x0488C04B
Chapter 1 Basic Python Programming 26
Garbage Collection
my_var = 5 # my_var points to an int object
my_var = [1, 2, 3] # my_var now points to a list object
my_var = "Hello" # my_var now points to a string object
● In the third statement, a string object is created. Its memory address is assigned to
my_var.
● The List object at address 0x0488C04B is garbage collected.
my_var 0x0065fd4B
1 2 3
0x0488C04B
Chapter 1 Basic Python Programming 27
Garbage Collection
my_var = 5
my_var2 = my_var
my_var = 10
print(my_var2)
● In the first statement, my_var is assigned the memory address of an integer object.
my_var
● In the second statement, my_var2 is assigned the same memory address as my_var.
○ i.e. they both point to the same object.
my_var
my_var2
Chapter 1 Basic Python Programming 31
Immutability
my_var = 5
my_var2 = my_var
my_var = 10
print(my_var2)
● Integer objects are immutable: once an int object is created, it cannot be changed.
● Therefore, the third statement cannot change the object my_var points to.
○ Rather, Python creates a new object containing 10 and points my_var to it.
10 ● Because at least one variable still points to
5
the first integer object we created, it does
not get garbage collected.
my_var
my_var2
Chapter 1 Basic Python Programming 32
Immutability
● The following types of objects are immutable in Python:
○ int, float, decimal
○ bool
○ string
○ tuple, range
● The function body is made up of one or more statements that will execute each time
the function is called.
● Any code that is indented further than the function header is part of its body.
def cube(x):
print(x ** 3)
● In this code, when we call cube, we pass the integer literal 3 as an argument.
● When the function starts executing, the value 3 is assigned to the parameter x.
● Inside the function, we cube the value of x and pass the result to the print function.
● This code will print 27.
y = 3
increase(y)
print(y)
y = 3
increase(y)
print(y)
my_list = [ 1, 2, 3]
increase_all(my_list)
print(my_list)
my_list = [ 1, 2, 3]
increase_all(my_list)
print(my_list)
● Because arguments are passed by reference, a_list references the same object as
my_list when increase_all is executing.
● Because List objects are mutable, when we update a_list in increase_all, a new
List is not created.
○ Any change to a_list updates the object referenced by my_list.
Chapter 1 Basic Python Programming 43
Creating New Functions
● Consider this code. What will print?
def square(n):
"""Function Returns the square of n"""
result = n ** 2
x = square( 2)
print(x)
x = square( 2)
print(x)
x = square( 2) # Assigns 4 to x
print(x)
y = square( 5) # Assigns 25 to y
print(y)
● In this example, we explicitly tell Python to return the value of the result variable.
○ The values we’d expect are now assigned to x and y.
● Unlike other languages, a Python program will not crash if we try to assign the return
value of a function that doesn’t return a value to a variable.
● It is important to make sure we place a return statement in functions that require it.
def first():
print("Executing First")
def first():
print("Executing First")
first()
● To make the desired change, we need to create a new str object and assign it to the
my_string variable:
my_string = "Bill"
my_string = "Jill"
● Since strings are immutable, any operation performed on a string actually returns a
new string object.
○ Therefore, slicing does not change the original string.
● The result of slicing must always be assigned to a variable if we want to use it:
my_string = "Cypress College"
substring = my_string[ 2:5]
print(substring)
my_string = "Cypress"
my_string2 = " College"
my_string + my_string2
print(my_string)
my_string = "Cypress"
● When both operands of the + operator are strings, it
my_string2 = " College" performs concatenation on them.
my_string + my_string2
print(my_string) ○ However, the original string objects are not updated.
○ Rather, a third string object is created and returned
● In this example, the new object is not assigned to a variable and is garbage collected.
● When the call to print is executed, my_string still references a string object with
the value “Cypress”.
my_string + my_string2 =
Chapter 1 Basic Python Programming 56
Strings and Their Operations
● To keep a concatenated string in memory, it needs to be referenced by a variable.
my_string = "Cypress" ● In this example, the right side of the third statement
my_string2 = " College"
my_string = my_string + my_string2
creates and returns a string object containing “Cypress
print(my_string) College”
● It is is then assigned to my_string.
my_string2 my_string
Chapter 1 Basic Python Programming 57
Objects and Method Calls
● A method is similar to a function:
○ It may accept arguments.
○ It performs a task.
○ It returns a value.
● The main difference is that a method is always called on an object.
● We use the dot operator to specify which object to call a method on:
my_string = "Cypress"
my_string.isupper()
● This code calls the isupper method on the object referenced by my_string.
○ Note: A method can only be called on an object if that method is part of the class
definition of the object’s type.
my_list = []
● Although a list grows as items are added to it, we cannot use the subscript operator to
retrieve from or edit an index that doesn’t exist in the list.
● Because my_list currently has no indexes, we cannot assign to its first (0th) index
because it doesn’t have one.
my_string = "Python,is,cool"
tokens = my_string.split( ',')
print(tokens) # Prints: ['Python', 'is', 'cool']
second_string = "Test"
print(second_string.join(my_list)) # Each word separated by "Test": Prints "PythonTestisTestcool"
● In each iteration of the loop, score is assigned the next element in the list.
○ i.e. in the first iteration, it is assigned 67, 100 in the second iteration, and 22 in
the final iteration.
○ score is called the iteration variable. We can name an iteration variable with
any valid Python identifier.
def print_nums(n):
if n == 1:
# Base case, since 1 is the smallest positive integer
print(1)
else:
# Recursive case: Print n and call print_nums again with a value one lower
print(n, end=" ")
print_nums(n - 1)
● What could a recursive case look like for a function that calculates this?
● What is the base case?
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)
def main():
print(factorial( 7))
print(factorial( 3))
● In the top-level call to factorial, we are not at a base case, so we perform the
recursive case.
● We return the result of a multiplication expression.
○ The right operand of this expression is a function call, which must be evaluated
before we multiply it by n and return it.
Recursion 81
Recursive Functions that Return Data
● Let’s try n = 3
factorial(3) n=3
def factorial(n):
if n == 1: n = 2 3 by the value returned by factorial(2)
factorial(2) Multiply
return 1
else:
Multiply 2 by the value returned by factorial(1)
return n * factorial(n - 1)
print(factorial( 3))
● In the next recursive level, we will multiply 2 by the result of calling factorial(1)
Recursion 82
Recursive Functions that Return Data
● Let’s try n = 3
factorial(3) n=3
def factorial(n):
if n == 1: n = 2 3 by the value returned by factorial(2)
factorial(2) Multiply
return 1
else: factorial(1) n=1
Multiply 2 by the value returned by factorial(1)
return n * factorial(n - 1)
return 1
print(factorial( 3))
Recursion 83
Recursive Functions that Return Data
● Let’s try n = 3
factorial(3) n=3
def factorial(n):
if n == 1: n = 2 3 by the value returned by factorial(2)
factorial(2) Multiply
return 1
else:
Multiply 2 by 1 and return it
return n * factorial(n - 1)
print(factorial( 3))
Recursion 84
Recursive Functions that Return Data
● Let’s try n = 3
factorial(3) n=3
def factorial(n):
if n == 1: Multiply 3 by 2 and return it
return 1
else:
return n * factorial(n - 1)
print(factorial( 3))
Recursion 85
Catching Exceptions
name = input("Enter your name: ")
age = input("Enter your age: ")
print(f'Hello, {name}. You have been alive approximately {age * 365} days')
try:
<statements>
except:
<statements>
● When a try-except statement executes, the statements in the try clause are executed.
● If any of these statements raises an error, control immediately transfers to the except
clause.
● While this code now avoids a crash, is there any way to improve it?
● While this code now avoids a crash, is there any way to improve it?
● We can change it to continually ask the user for input until they enter a number.
○ In fact, let’s write a helper function that retrieves an integer from the user.
● This recursive function returns the user’s input if it is a properly formatted integer.
● Otherwise, it returns the result of calling get_integer recursively.
○ This gives the user another chance to enter a correct value.