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:
- Use variables to store data and reuse it as often as needed
- Use functions to store procedures and reuse them as often as needed
- Use built-in functions to solve problems
- Variables
- Statements and Expressions
- Functions
- Variable Scope
- Return Statements
- Print versus Return
- Function Composition
- Helper Functions
- Built-in Functions
- Module Functions
- Check 1.7
- 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
- A variable is a name that stores a piece of data inside of it.
- 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
- An expression is a data value or an operation that eventually evaluates to a value.
- 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
- A function is a procedure stored under a name that can be used as often as needed by calling the name.
- 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
- Variables exist in a specific scope based on when they are defined. This means they cannot be used at all places in code.
- 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
- Basic Example
- 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!
- Confusing print and return is a common early mistake.
- 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
- 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
- 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
- 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 importingprint(math.factorial(20)) # we did not first import the math module # Python output: # NameError: name 'math' is not defined
Call with importingimport math print(math.factorial(20)) # much better... # Note that the module name is included before the function name, separated by a . - Check 1.7
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))