CMU 15-112: Fundamentals of Programming and Computer Science
Class Notes: Variables and Functions


 Learning Goal: use variables and functions when writing code. In particular:
  1. Variables
  2. Statements and Expressions
  3. Functions
  4. Variable Scope
  5. Return Statements
  6. Print versus Return
  7. Function Composition
  8. Helper Functions
  9. Built-in Functions
  10. Module Functions
  11. Check 1.7

  1. Variables
    • A variable is a name that stores a piece of data inside of it.
      # we put a value in a variable using an = sign x = 5 print(x) # x evaluates to 5 print(x*2) # evaluates to 10

    • Unlike in math, variables can have new values assigned to them whenever needed, even values of different types.
      y = 10 print(y - 2) y = True print(y)

    • Variables can be given any name, as long as it starts with a letter and contains no special characters.
      numberOfRabbits = 40 courseIs15112 = True 99problems = 0 # will crash because it starts with a number

    • Variables can be updated using a set of assignment operations.
      x = 5 x += 2 # same as x = x + 2 print(x) # should be 7 # This can be done with any of the arithmetic operations. y = 350 y //= 10 print(y) # should be 35

  2. Statements and Expressions
    • An expression is a data value or an operation that eventually evaluates to a value.
      # Examples of expressions. # Note that when this is run in the editor, none of these values are displayed. 4 "Hello World" 7 + 2 True or False (2 < 3) and (9 > 0)

    • A statement is a line of code that performs an action. Statements cannot be used in operations.
      # Examples of statements. print(4) x = True

  3. Functions
    • A function is a procedure stored under a name that can be used as often as needed by calling the name.
      # A function is composed of two parts: the header and the body. # The header defines the name and parameters. # A function header is written as follows: def functionName(parameters): # The parameters are variables that will be provided when the function is called. # The header ends with a colon to indicate that a body will follow. # The body contains the actions (statements) that the function performs. # The body is written under the function with an indent. # When the lines are no longer indented, the function body ends. # Functions usually contain a return statement. This will provide the result when the function is called. # Example: def double(x): print("I'm in the double function!") return 2 * x # To call the function, we use the function's name, # followed by parentheses which contain the data values we want to use, called function arguments. # This function call will evaluate to an expression. print(double(2)) # will print 4 print(double(5)) # will print 10 print(double(1) + 3) # will print 5

    • Functions can have as many parameters as they need, or none at all.
      def f(x, y, z): return x + y + z print(f(1, 3, 2)) # returns 6 def g(): return 42 print(g()) # returns 42 # Note - the number of arguments provided must match the number of parameters! print(g(2)) # will crash print(f(1, 2)) # would also crash if it ran

  4. Variable Scope
    • Variables exist in a specific scope based on when they are defined. This means they cannot be used at all places in code.
      def f(x): print("x:", x) y = 5 print("y:", y) return x + y print(f(4)) print(x) # will crash! print(y) # would also crash if we reached it!

    • Variables in functions have a local scope. They exist only inside the immediate function, and do not share data with other variables of the same name in different functions.
      def f(x): print("In f, x =", x) x += 5 return x def g(x): y = f(x*2) print("In g, x =", x) z = f(x*3) print("In g, x =", x) return y + z print(g(2)) # Another example def f(x): print("In f, x =", x) x += 7 return round(x / 3) def g(x): x *= 10 return 2 * f(x) def h(x): x += 3 return f(x+4) + g(x) print(h(f(1)))

    • When defined outside of functions, variables have a global scope and can be used anywhere.
      # In general, you should avoid using global variables. # You will even lose style points if you use them! # Still, you need to understand how they work, since others # will use them, and there may also be some very few occasions # where you should use them, too! g = 100 def f(x): return x + g print(f(5)) # 105 print(f(6)) # 106 print(g) # 100 # Another example def f(x): # If we modify a global variable, we must declare it as global. # Otherwise, Python will assume it is a local variable. global g g += 1 return x + g print(f(5)) # 106 print(f(6)) # 108 print(g) # 102

  5. Return Statements
    • Basic Example
      def isPositive(x): return (x > 0) print(isPositive(5)) # True print(isPositive(-5)) # False print(isPositive(0)) # False

    • Return ends the function immediately:
      def isPositive(x): print("Hello!") # runs return (x > 0) print("Goodbye!") # does not run ("dead code") print(isPositive(5)) # prints Hello, then True

    • No return statement --> return None:
      def f(x): x + 42 print(f(5)) # None

    • Another example:
      def f(x): result = x + 42 print(f(5)) # None

  6. Print versus Return
    • Confusing print and return is a common early mistake.
      def cubed(x): print(x**3) # Here is the error! cubed(2) # seems to work! print(cubed(3)) # sort of works (but prints None, which is weird) print(2*cubed(4)) # Error!

    • Once again (correctly):
      def cubed(x): return (x**3) # That's better! cubed(2) # seems to be ignored (why?) print(cubed(3)) # works! print(2*cubed(4)) # works!

  7. Function Composition
    def f(w): return 10*w def g(x, y): return f(3*x) + y def h(z): return f(g(z, f(z+1))) print(h(1)) # hint: try the "visualize" feature

  8. Helper Functions
    # We commonly write functions to solve problems. # We can also write functions to store an action that is used multiple times! # These are called helper functions. def onesDigit(n): return n%10 def largerOnesDigit(x, y): return max(onesDigit(x), onesDigit(y)) print(largerOnesDigit(134, 672)) # 4 print(largerOnesDigit(132, 674)) # Still 4

  9. Builtin Functions
    # Some functions are already provided by Python print("Type conversion functions:") print(bool(0)) # convert to boolean (True or False) print(float(42)) # convert to a floating point number print(int(2.8)) # convert to an integer (int) print("And some basic math functions:") print(abs(-5)) # absolute value print(max(2,3)) # return the max value print(min(2,3)) # return the min value print(pow(2,3)) # raise to the given power (pow(x,y) == x**y) print(round(2.354, 1)) # round with the given number of digits

  10. Module Functions
    Python has many different functions already implemented, but not available immediately. To use these functions, you must import a module. You can find these modules by reading the Python documentation online.

    Call without importing
    print(math.factorial(20)) # we did not first import the math module # Python output: # NameError: name 'math' is not defined

    Call with importing
    import math print(math.factorial(20)) # much better... # Note that the module name is included before the function name, separated by a .

  11. Recommended functions
    # There are a few functions from modules you'll definitely want to use in the assignments # First: the built-in round function has inconsistent behavior when rounding 0.5. # Use our function roundHalfUp to fix this. def roundHalfUp(d): # Round to nearest with ties going away from zero. # You do not need to understand how this function works. import decimal rounding = decimal.ROUND_HALF_UP return int(decimal.Decimal(d).to_integral_value(rounding=rounding)) print(round(0.5)) # This evaluates to 0 - what! print(round(1.5)) # And this will be 2 - so confusing! print(roundHalfUp(0.5)) # Now this will always round 0.5 up (to 1) print(roundHalfUp(1.5)) # This still rounds up too! # Second: when comparing floats, == doesn't work quite right. # Use math.isclose to compare floats instead print(0.1 + 0.1 == 0.2) # True, but... d1 = 0.1 + 0.1 + 0.1 d2 = 0.3 print(d1 == d2) # False! print(d1) # prints 0.30000000000000004 (uh oh) print(d1 - d2) # prints 5.55111512313e-17 (tiny, but non-zero!) # Moral: never use == with floats! import math print(math.isclose(d1, d2)) # True! # math.isclose checks if the two numbers are ALMOST equal, within a small error # S19 UPDATE: unfortunately, it appears that math.isclose does not work properly # when comparing a number to 0. print(math.isclose(0, 0.0000000000001)) # A terrible betrayal of math! # Instead, let's just make our own version of isclose. def almostEqual(x, y): return abs(x - y) < 10**-9 # This will now work properly! print(almostEqual(0, 0.0000000000001)) print(almostEqual(d1, d2))

  12. Check 1.7