= "Friday"
today print("Today is", today)
Today is Friday
Victor Omondi
April 30, 2021
This tutorial covers the following topics:
try
-except
blocksA function is a reusable set of instructions that takes one or more inputs, performs some operations, and often returns an output. Python contains many in-built functions like print
, len
, etc., and provides the ability to define new ones.
You can define a new function using the def
keyword.
Note the round brackets or parentheses ()
and colon :
after the function’s name. Both are essential parts of the syntax. The function’s body contains an indented block of statements. The statements inside a function’s body are not executed when the function is defined. To execute the statements, we need to call or invoke the function.
Functions can accept zero or more values as inputs (also knows as arguments or parameters). Arguments help us write flexible functions that can perform the same operations on different values. Further, functions can return a result that can be stored in a variable or used in other expressions.
Here’s a function that filters out the even numbers from a list and returns a new list using the return
keyword.
Can you understand what the function does by looking at the code? If not, try executing each line of the function’s body separately within a code cell with an actual list of numbers in place of number_list
.
As a programmer, you will spend most of your time writing and using functions. Python offers many features to make your functions powerful and flexible. Let’s explore some of these by solving a problem:
Radha is planning to buy a house that costs
$1,260,000
. She considering two options to finance her purchase:
- Option 1: Make an immediate down payment of
$300,000
, and take loan 8-year loan with an interest rate of 10% (compounded monthly) for the remaining amount.- Option 2: Take a 10-year loan with an interest rate of 8% (compounded monthly) for the entire amount.
Both these loans have to be paid back in equal monthly installments (EMIs). Which loan has a lower EMI among the two?
Since we need to compare the EMIs for two loan options, defining a function to calculate the EMI for a loan would be a great idea. The inputs to the function would be cost of the house, the down payment, duration of the loan, rate of interest etc. We’ll build this function step by step.
First, let’s write a simple function that calculates the EMI on the entire cost of the house, assuming that the loan must be paid back in one year, and there is no interest or down payment.
Let’s add a second argument to account for the duration of the loan in months.
Note that the variable emi
defined inside the function is not accessible outside. The same is true for the parameters amount
and duration
. These are all local variables that lie within the scope of the function.
Scope: Scope refers to the region within the code where a particular variable is visible. Every function (or class definition) defines a scope within Python. Variables defined in this scope are called local variables. Variables that are available everywhere are called global variables. Scope rules allow you to use the same variable names in different functions without sharing values from one to the other.
We can now compare a 6-year loan vs. a 10-year loan (assuming no down payment or interest).
As you might expect, the EMI for the 6-year loan is higher compared to the 10-year loan. Right now, we’re printing out the result. It would be better to return it and store the results in variables for easier comparison. We can do this using the return
statement
Next, let’s add another argument to account for the immediate down payment. We’ll make this an optional argument with a default value of 0.
Next, let’s add the interest calculation into the function. Here’s the formula used to calculate the EMI for a loan:
where:
P
is the loan amount (principal)n
is the no. of monthsr
is the rate of interest per monthThe derivation of this formula is beyond the scope of this tutorial. See this video for an explanation: https://youtu.be/Coxza9ugW4E .
Note that while defining the function, required arguments like cost
, duration
and rate
must appear before optional arguments like down_payment
.
Let’s calculate the EMI for Option 1
While calculating the EMI for Option 2, we need not include the down_payment
argument.
Invoking a function with many arguments can often get confusing and is prone to human errors. Python provides the option of invoking functions with named arguments for better clarity. You can also split function invocation into multiple lines.
We can already see that the EMI for Option 1 is lower than the EMI for Option 2. However, it would be nice to round up the amount to full dollars, rather than showing digits after the decimal. To achieve this, we might want to write a function that can take a number and round it up to the next integer (e.g., 1.2 is rounded up to 2). That would be a great exercise to try out!
However, since rounding numbers is a fairly common operation, Python provides a function for it (along with thousands of other functions) as part of the Python Standard Library. Functions are organized into modules that need to be imported to use the functions they contain.
Modules: Modules are files containing Python code (variables, functions, classes, etc.). They provide a way of organizing the code for large Python projects into files and folders. The key benefit of using modules is namespaces: you must import the module to use its functions within a Python script or notebook. Namespaces provide encapsulation and avoid naming conflicts between your code and a module or across modules.
We can use the ceil
function (short for ceiling) from the math
module to round up numbers. Let’s import the module and use it to round up the number 1.2
.
Help on built-in function ceil in module math:
ceil(x, /)
Return the ceiling of x as an Integral.
This is the smallest integer >= x.
Let’s now use the math.ceil
function within the home_loan_emi
function to round up the EMI amount.
Using functions to build other functions is a great way to reuse code and implement complex business logic while still keeping the code small, understandable, and manageable. Ideally, a function should do one thing and one thing only. If you find yourself writing a function that does too many things, consider splitting it into multiple smaller, independent functions. As a rule of thumb, try to limit your functions to 10 lines of code or less. Good programmers always write short, simple, and readable functions.
Let’s compare the EMIs and display a message for the option with the lower EMI.
Now we know for sure that “Option 1” has the lower EMI among the two options. But what’s even better is that we now have a handy function loan_emi
that we can use to solve many other similar problems with just a few lines of code. Let’s try it with a couple more questions.
Q: Shaun is currently paying back a home loan for a house he bought a few years ago. The cost of the house was
$800,000
. Shaun made a down payment of25%
of the price. He financed the remaining amount using a 6-year loan with an interest rate of7%
per annum (compounded monthly). Shaun is now buying a car worth$60,000
, which he is planning to finance using a 1-year loan with an interest rate of12%
per annum. Both loans are paid back in EMIs. What is the total monthly payment Shaun makes towards loan repayment?
This question is now straightforward to solve, using the loan_emi
function we’ve already defined.
cost_of_house = 800000
home_loan_duration = 6*12 # months
home_loan_rate = 0.07/12 # monthly
home_down_payment = .25 * 800000
emi_house = loan_emi(amount=cost_of_house,
duration=home_loan_duration,
rate=home_loan_rate,
down_payment=home_down_payment)
emi_house
10230
try
-except
Q: If you borrow
$100,000
using a 10-year loan with an interest rate of 9% per annum, what is the total amount you end up paying as interest?
One way to solve this problem is to compare the EMIs for two loans: one with the given rate of interest and another with a 0% rate of interest. The total interest paid is then simply the sum of monthly differences over the duration of the loan.
ZeroDivisionError: ignored
Something seems to have gone wrong! If you look at the error message above carefully, Python tells us precisely what is wrong. Python throws a ZeroDivisionError
with a message indicating that we’re trying to divide a number by zero. ZeroDivisonError
is an exception that stops further execution of the program.
Exception: Even if a statement or expression is syntactically correct, it may cause an error when the Python interpreter tries to execute it. Errors detected during execution are called exceptions. Exceptions typically stop further execution of the program unless handled within the program using
try
-except
statements.
Python provides many built-in exceptions thrown when built-in operators, functions, or methods are used incorrectly: https://docs.python.org/3/library/exceptions.html#built-in-exceptions. You can also define your custom exception by extending the Exception
class (more on that later).
You can use the try
and except
statements to handle an exception. Here’s an example:
try:
print("Now computing the result..")
result = 5 / 0
print("Computation was completed successfully")
except ZeroDivisionError:
print("Failed to compute result because you were trying to divide by zero")
result = None
print(result)
Now computing the result..
Failed to compute result because you were trying to divide by zero
None
When an exception occurs inside a try
block, the block’s remaining statements are skipped. The except
block is executed if the type of exception thrown matches that of the exception being handled. After executing the except
block, the program execution returns to the normal flow.
You can also handle more than one type of exception using multiple except
statements. Learn more about exceptions here: https://www.w3schools.com/python/python_try_except.asp .
Let’s enhance the loan_emi
function to use try
-except
to handle the scenario where the interest rate is 0%. It’s common practice to make changes/enhancements to functions over time as new scenarios and use cases come up. It makes functions more robust & versatile.
We can use the updated loan_emi
function to solve our problem.
Q: If you borrow
$100,000
using a 10-year loan with an interest rate of 9% per annum, what is the total amount you end up paying as interest?
We can add some documentation within our function using a docstring. A docstring is simply a string that appears as the first statement within the function body, and is used by the help
function. A good docstring describes what the function does, and provides some explanation about the arguments.
def loan_emi(amount, duration, rate, down_payment=0):
"""Calculates the equal montly installment (EMI) for a loan.
Arguments:
amount - Total amount to be spent (loan + down payment)
duration - Duration of the loan (in months)
rate - Rate of interest (monthly)
down_payment (optional) - Optional intial payment (deducted from amount)
"""
loan_amount = amount - down_payment
try:
emi = loan_amount * rate * ((1+rate)**duration) / (((1+rate)**duration)-1)
except ZeroDivisionError:
emi = loan_amount / duration
emi = math.ceil(emi)
return emi
In the docstring above, we’ve provided some additional information that the duration
and rate
are measured in months. You might even consider naming the arguments duration_months
and rate_monthly
, to avoid any confusion whatsoever. Can you think of some other ways to improve the function?
Help on function loan_emi in module __main__:
loan_emi(amount, duration, rate, down_payment=0)
Calculates the equal montly installment (EMI) for a loan.
Arguments:
amount - Total amount to be spent (loan + down payment)
duration - Duration of the loan (in months)
rate - Rate of interest (monthly)
down_payment (optional) - Optional intial payment (deducted from amount)
You’re planning a vacation, and you need to decide which city you want to visit. You have shortlisted four cities and identified the return flight cost, daily hotel cost, and weekly car rental cost. While renting a car, you need to pay for entire weeks, even if you return the car sooner.
City | Return Flight ($ ) |
Hotel per day ($ ) |
Weekly Car Rental ($ ) |
---|---|---|---|
Paris | 200 | 20 | 200 |
London | 250 | 30 | 120 |
Dubai | 370 | 15 | 80 |
Mumbai | 450 | 10 | 70 |
Answer the following questions using the data above:
$1000
, which city should you visit to maximize the duration of your trip? Which city should you visit if you want to minimize the duration?$600
, $2000
, or $1500
?Hint: To answer these questions, it will help to define a function cost_of_trip
with relevant inputs like flight cost, hotel rate, car rental rate, and duration of the trip. You may find the math.ceil
function useful for calculating the total cost of car rental.
With this, we complete our discussion of functions in Python. We’ve covered the following topics in this tutorial:
return
try
-except
This tutorial on functions in Python is by no means exhaustive. Here are a few more topics to learn about:
*args
and **kwargs
)Following are some resources to learn about more functions in Python:
Try answering the following questions to test your understanding of the topics covered in this notebook:
return
keyword in Python?return
statement be used inside an if
block or a for
loop?return
keyword be used outside a function?try
-except
statements in Python?try
-except
statements? Give an example.try
block?except
? Can you have multiple except
blocks under a single try
block?except
block to handle any type of exception?try
-except
inside a function with an example.