- Variables
- A variable is a named value that references or stores a piece of data.
# 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,
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 with 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
- Statements and Expressions
- An expression is a data value or an operation that 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.
Unlike expressions, statements cannot be used in operations.
# Examples of statements.
print(4)
x = True
- Functions
- A function is a procedure (a sequence of statements) stored under a name that can be used repeatedly 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
- 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 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 .
- Variable Scope
- Variables exist in a specific scope based on when they are defined. This means they are not visible and cannot be used outside that scope,
in other parts of the 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 have no relation to 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
- 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
- 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!
- 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
- 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 confusing 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 almostEqual 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!
# Python includes a builtin function math.isclose(), but that function
# has some confusing behavior when comparing values close to 0.
# 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))
- Test Functions
- A broken test function
def onesDigit(n):
return n%10
def testOnesDigit():
print("Testing onesDigit()...", end="")
assert(onesDigit(5) == 5)
assert(onesDigit(123) == 3)
assert(onesDigit(100) == 0)
assert(onesDigit(999) == 9)
print("Passed!")
testOnesDigit() # Passed! Why is this bad?
- A better version
def onesDigit(n):
return n%10
def testOnesDigit():
print("Testing onesDigit()...", end="")
assert(onesDigit(5) == 5)
assert(onesDigit(123) == 3)
assert(onesDigit(100) == 0)
assert(onesDigit(999) == 9)
assert(onesDigit(-123) == 3) # Added this test
print("Passed!")
testOnesDigit() # Crashed! So the test function worked!