All About Control

Jed Rembold

September 10, 2025

Announcements

  • Homework
    • Problem Set 2 posted!
      • You can already do the entirety of Problem 1
      • Problems 2 & 3 are approachable after today
    • I’ll be getting feedback to you on PS1 later in the week
  • Sections today and tomorrow. Make sure you are going, as you only get 3 unexcused absences before missing starts really hurting your grade
  • Polling: polling.jedrembold.prof

Review Question

Examining the code to the right, what is the returned value if I evaluate the expression func2(1,5)?

  1. \(1\)
  2. \(5\)
  3. \(32\)
  4. \(2.33\times10^{22}\)
def func1(x):
    for i in range(3):
        x *= 2
    return x + x

def func2(y, z):
    A = func1(y+1) % 8
    z, A = A + z, y
    return z ** A

Libraries

Visiting the library(ies)

  • A huge strength of Python is that it offers a very large number of code collections called libraries
    • Can save you the effort from writing that code yourself!
  • Requires you to import that library, which can take several different forms
    • Most common is to use import |||lib||| to grab everything in a library

      import math
      • You must then access any function in that library using its fully qualified name, which includes the library name (var = math.sqrt(4))
    • Can also use from |||lib||| import |||function/constant||| to grab specific functions from the library

      from math import sqrt
      • You do not need to use the library name then when you call it (var = sqrt(4))

Using Libraries

  • While using libraries is highly efficient, it does demand some different skills
  • How do you know what a library offers? Or how to use what it offers?
  • You read the documentation!
    • Describes what constants (if any) the library makes available
    • Describes all the functions the library offers
    • Describes what inputs and outputs those functions require
    • Often includes some examples
  • If you are unwilling to read documentation to learn a new library, then you will be forced to write everything from scratch on your own, and thus making anything interesting as a programmer will get unreasonably difficult

Useful math definitions

Full Documentation

Code Description
math.pi The mathematical constant \(\pi\)
math.e The mathematical constant \(e\)
math.sqrt(|||x|||) The square root of x
math.log(|||x|||) The natural logarithm of x
math.log10(|||x|||) The base 10 logarithm of x
Code Description
math.sin(|||x|||) The sine of x in radians
math.cos(|||x|||) The cosine of x in radians
math.asin(|||x|||) The arcsin of x
math.degrees(|||x|||) Converts radians to degrees
math.radians(|||x|||) Converts degrees to radians

Python’s Path

  • Wherever possible, Python runs code one line at a time, from top to bottom

  • It will not, however, enter indented blocks unless it has to

    • The code inside a function definition, for example, is only run when the function is called
    • Code inside an if statement is only run if the condition is met
  • A common paradigm then is to define functions first, and then include the code to run those functions beneath

    def func1(a):
        return a + 1
    
    def func2(b):
        return b // 2
    
    print(func1(2) + func2(2))

Collections of Constants and Functions

  • A library should generally just be a collection of defined functions and constants
    • You don’t want any code to actually run when you import the library, you just want to access the desired pieces
  • If you place everything inside a function definition though, nothing actually happens when you run the library code!
    • You just defined a bunch of functions, but never did anything with them
  • Commonly, we want the best of both worlds:
    • I can use a program easily as a library, if I want to import a defined function
    • I can run the program directly and have something actually happen

Running a Program

  • Karel programs always run the first defined function in the code when the program was run. General Python programs do not follow the same convention.

  • Python programs need to specify what part of the code is supposed to be executed when a program is run if everything is just function definitions. This commonly happens at the bottom of the program:

    if __name__ == '__main__':
        |||function_to_run()|||
    • |||function_to_run||| is the name of whatever function you want to execute when the program is run directly
  • Patterns of this sort are commonly called boilerplate

    • Less important to fully understand all the pieces of it now
    • Is important to understand what it is doing and how to implement it correctly

Sample Program

def print_odds(des_num):
    """
    Prints the first desired number of odd numbers 
    starting from 1.
    """
    value = 1
    for i in range(des_num):
        print(value)
        value += 2

if __name__ == '__main__':
    print_odds(100)

Bombastic Booleans

Booleans

  • In Karel we know certain functions would evaluate to yes/no or true/false
    • Python stores this sort of information in a data type called a boolean
  • A boolean data type can only have one of two possible values: true or false
  • Literal booleans are defined in Python using True or False
  • These can be assigned to variables, returned from functions, etc. just like numeric data types
    • Most importantly, they can be utilized with control statements!
    A = True
    if A:
      A = False
    print(A)

Extra iffy

  • Karel could only use if and else
  • Python also supports an elif statement
  • This lets you chain together multiple mutually exclusive condition checks
  • You can include as many elif chained statements as you want
  • Only a single elif block will ever be entered!
if |||condition 1|||:
    |||Run this code if condition 1 is true|||
elif |||condition 2|||:
    |||Run this code if condition 1 is false|||
    |||but condition 2 is true|||
elif |||condition 3|||:
    |||Run this code if both condition 1 and|||
    |||2 fail but condition 3 is true|||
else:
    |||This code runs if all above|||
    |||conditions fail|||

Boolean Expressions

  • Python defines two types of operators that work with Boolean data: relational operators and logical operators

  • Relational operators compare values of other types and produce a boolean True/False result:

    == Equals != Not equals
    < Less than <= Less than or equal too
    > Greater than >= Greater than or equal to
  • Be careful! == compares two values. A single = assigns a variable. The odds are high you’ll use one when you meant the other at least once this semester!

The Vulcan Way

  • Logical operators act on Boolean pairings

    Operator Description
    A and B True if both terms True, False otherwise
    A or B True if any term is True, False otherwise
    not A True if A False, False if A True (opposite)
  • Order of operations follows parentheses and then proceeds left to right
  • Careful that or is still True if both options are True
  • Similarly, careful with combining not with and and or
    • “Not A or B” in common English is not the same as not A or B

Understanding Check

What value is printed when the code to the right runs?

  1. True
  2. False
  3. 5
  4. This would give an error
A = 10
B = 4
C = 1
A *= B
if A > 40 and C != 10 % 4:
    print(B+C)
else:
    print(A < B or not (C == 10 // 4))

Shorting the Circuit

  • Python evaluates and and or operators using a strategy called short-circuit mode
  • Only evaluates the right operand if it actually needs to
    • Example: if n=0, then the x % n == 0 is never actually checked in the statement

      n != 0 and x % n == 0

      since n != 0 already is False and False and anything is always False

  • Can use short-circuit to prevent errors: the above x % n == 0 statement would have errored out if n=0

Sequences

For Loop Anatomy

  • We have already seen for loops in Karel, but let’s expand on their use:

  • The more general syntax of a for loop looks like:

    for |||variable name||| in |||sequence|||:
        |||code to loop over|||
    • |||variable name||| is a variable name that will be assigned every value in the sequence over the course of the loop
    • |||sequence||| is any expression that produces an object which supports iteration
      • We’ve already seen range() fill this role
      • Any sequence works though, and we’ll see examples of another type of sequence next week

The range() iterable

  • Need an easy way to produce or describe a range of numeric values
  • The built-in range() function handles this and produces the needed iterable object
  • Takes 1, 2, or 3 arguments:
    • Start (default 0): where to start the sequence at
    • Stop (mandatory): the sequence ends just below this value (does not include it!)
    • Step (default 1): what value the sequence counts by

Be careful, the range function will stop one step before the final stop value.

For ranging examples

  • Providing just a stop argument:

    for n in range(5):
        print(n)
  • Providing a start and stop:

    for n in range(1,11):
        print(n)
  • Providing a start, stop, and step:

    for n in range(10,0,-1):
        print(n)
// reveal.js plugins