7. Functions#

7.1. Defining a function#

A function is a block of code (related statements) that perform a specific task. This block of code only runs when you call the function. Therefore, functions are useful when you want to run part of your code repeatedly or when you want to put a complex part of your code into a separate sub-program to increase the readibility of your code.

Below is a simple example of a function called rectangle in Python that computes the area and perimeter of a rectangle given its length l and its width w.

def rectangle(l,w):
  area=l*w
  perimeter=2*(l+w)
  return area, perimeter

As you can see, the function is defined using def keyword. The function name comes next; here it is called rectangle. The function takes the two input parameters l and w which should come after the function name inside parenthesis () followed by :. Note that the body of this function is defined by indentation. This function returns two outputs using the return statement.

Note that a function can have none or multiple input and output arguments.

def add_numbers(num1, num2, num3):
  sum = num1 + num2 + num3
  print("sum: ", sum)

7.2. Calling a function#

To call a function you can use the function name followed by parenthesis to pass along the arguments.

The figure below shows how functions work. When you call a function (1), the program jumps to the code inside that function and executes it (2). After the function completes its execution, it returns a result/output. The program then resumes running from where it left off after the function call (3).

working-of-function-python.webp

There are multiple ways you can call a function based on your preferance or application. Below are some examples.

# First define the function
def rectangle(l,w):
  area=l*w
  perimeter=2*(l+w)
  return area, perimeter
# Call the function
# syntax 1
area1, per1= rectangle(4,2)
print("rectangle 1: area =",area1 ,", perimeter=",per1)

# syntax 2
area2, per2= rectangle(w=2,l=4)
print("rectangle 2: area =",area2 ,", perimeter=",per2)

# syntax 3
l3=40; w3=20
rec3= rectangle(l3,w3)
print("rectangle 3: area =",rec3[0] ,", perimeter=",rec3[1])
rectangle 1: area = 8 , perimeter= 12
rectangle 2: area = 8 , perimeter= 12
rectangle 3: area = 800 , perimeter= 120

❗Note the different possible syntaxes for input and output arguments above. Also note that in the second syntax, known as “keyword arguments”, the order of the inputs is not important and you can switch. Here is another example:

# define a function
def divide(a,b):
  return a/b
# Now call the function

# syntax 1: call function and print resut
print("syntax 1:", divide(8,2))

# syntax 2: call function and print result
print("syntax 2:", divide(b=2, a=8))
syntax 1: 4.0
syntax 2: 4.0

7.3. Extra: return to the BMI calculator!#

Do you remember the program you wrote to calculate BMI using if and else-statements in Python Notebook? Now we are going to reuse it by calling it multiple times without ending up unnecessarily long code.

Our original code is below:

# Original code

# Get input for age and weight
weight = #Enter your weight in kilograms (float)
height = #Enter your height in meters (float)


# Calculate BMI
bmi = weight / (height ** 2)

# Determine BMI range
if bmi < 18.5:
    category = "underweight"
elif 18.5 <= bmi < 24.9:
    category = "healthy weight"
elif 25 <= bmi < 29.9:
    category = "overweight"
else:
    category = "obese"

# Print results
print(f"Your BMI is {bmi:.2f}, which falls in the '{category}' range.")

Now let’s define the main code as a function, with a few adjustments:

  • The inputs are already defined in the brackets as parameters, so there is no need to ask the user for input.

  • You can return the parameters bmi and category, but using a print function to display them would also work and be more convenient in this case.

#Define the function

def bmi_calculator(weight, height):

  # Calculate BMI
  bmi = weight / (height ** 2)

  # Determine BMI range
  if bmi < 18.5:
      category = "underweight"
  elif 18.5 <= bmi < 24.9:
      category = "healthy weight"
  elif 25 <= bmi < 29.9:
      category = "overweight"
  else:
      category = "obese"

  #return the parameters
  print(f"Your BMI is {bmi:.2f}, which falls in the '{category}' range.")
# Now let's call the function

#syntax 1
bmi_calculator(70, 1.77)
#syntax 2
bmi_calculator(110, 1.65)
#syntax 3
bmi_calculator(weight=35, height=1.55)
#syntax 4
bmi_calculator(height= 1.90, weight= 95)
Your BMI is 22.34, which falls in the 'healthy weight' range.
Your BMI is 40.40, which falls in the 'obese' range.
Your BMI is 14.57, which falls in the 'underweight' range.
Your BMI is 26.32, which falls in the 'overweight' range.

✅ By defining the function bmi_calculator, you can apply the code multiple times without having to rewrite it, making your work easier and faster. Functions help in organizing the code better and make it more readable and maintainable.

7.4. Parameter or argument?#

Note that these two terms may get confusing sometimes. In Python functions:

  • A parameter is the variable used in the function definition.

  • An argument is the value that is passed to the function when it is called.

7.5. Required and default arguments#

A function should be given the correct number of arguments when it is called or it will give an error. For example, the rectangle function defined above requires exactly two arguments. However, you can set a default value for an input parameter when defining the function. In this case, if you call the function without the argument, it uses the default value to compute the results. Here is an example.

# define a function
def subtract(a,b=0):
  return a-b

# call function and print resut
print(subtract(8))     # a=8, b=0 (default)
print(subtract(8,5))   # a=8, b=5 (input)
8
3

7.6. Variable number of arguments#

You can have variable number of parameters in Python, but you have to indicate that in the function definition. That can be done by adding an asterisk * before the parameter name. Here is an example:

def multiplication(*numbers):
  result=1
  for num in numbers:
    result *= num
  return result

print(multiplication(1,2,3,4,5,6))
720

7.7. Lambda functions (anonymous functions)#

Another way to quickly define a function in Python that has only one expression is using the lambda keyword instead of def. The correct syntax is: lambda arguments : expression. Here is an example which performs the same task as the divide and substract functions you saw earlier.

divide2 = lambda x,y: x/y

print (divide2(8,2))
4.0
substract2 = lambda a,b: a-b

print(substract2(8,5))

# with default value
substract2 = lambda a,b=0: a-b

print(substract2(8))
3
8

Lambda functions are mostly used when you require a nameless function for a short period of time, but a detailed explanation is outside the scope of this basic introduction.


7.8. Exercises: Functions#

When working with different cells (defining functions in one cell and calling them in another cell), ensure that you first run the cell where the functions are defined.


7.8.1. Exercise: Temperature conversion#

Write a Python program that defines a function temperature_converter() to convert temperatures between Celsius and Fahrenheit. This function does not take any parameters, instead; it prompts the user to make a choice for the conversion direction and then to input the temperature. The function will then print the converted temperature.

Conversion options:

  1. Celsius to Fahrenheit: °F = (°C * 9/5) + 32

  2. Fahrenheit to Celsius: °C = (°F - 32) * 5/9

💡 Hint 1: Use the if-elif-else construction for the conversion logic and include the print statements within these cases.

💡 Hint 2: First, write the main code and test if it works properly. Once it works correctly, define this main code as a function.

# Main code
# Print the options
print("Temperature Converter")
print("1. Celsius to Fahrenheit")
print("2. Fahrenheit to Celsius")

# Prompt the user to make a choice between 1 and 2
choice = #Enter your choice (1 or 2) 
# If option 1
if choice == 1:
        # Prompt the user to enter temperature in Celsius
        # your code here
        # Celsius -> Fahrenheit
        fahrenheit = # your code here
        # Print the converted temperature
        print(f"{celsius}°C is equal to {fahrenheit:.2f}°F")

# If option 2
elif choice == 2:
        # Prompt the user to enter temperature in Fahrenheit
        fahrenheit = # your code here
        # Fahrenheit -> Celsius
        celsius = # your code here
        # Print the converted temperature
        print(f"{fahrenheit}°F is equal to {celsius:.2f}°C")

else:
        # your code here

✅ If your code works properly, now define it as a function with a few adjustments. You don’t need to use return since you can print the output directly within the function.

def temperature_converter():

  # your code here

✅ Once you define the function, you can call and use it without needing a long piece of code each time. This makes your code more efficient, easier to read, and more convenient to maintain and reuse.

# Call and test the function
temperature_converter()

7.8.2. Exercise: Battery life of a chip#

Suppose that we have a chip, and we want to calculate how long it will take before its battery is fully exhausted. By calculating its dynamic and static power, we can easily obtain the time as: battery time = battery capacity /\(( P_{dynamic} + P_{static}) \)

But there are some parameters that we have to take into account to do that.

  • \(V_{DD}\) : Supply voltage

  • \(f\) : Clock frequency

  • \(C\) : Capacitance

  • \(α\) : Activity factor

  • \(I\) : Leakage current

The formulas needed to calculate the dynamic and static power are below:

\(P_{dynamic}\) = \( \alpha C V_{DD}^2 f\)

\(P_{static} = I V_{DD}\)

💡 Dynamic power: This is the power consumed by the chip during its active operation, such as processing tasks and running programs.

💡 Static power: This is the power consumed by the chip when it is idle or in standby mode, due to leakage currents and other static effects. It will always draw power no matter what you do.

Write Python code to calculate the time it takes for the battery to become fully exhausted. First, define functions for dynamic and static power consumption separately. Then, define a function for the chip’s battery life.

# Define the dynamic power
def dynamic_power(alpha, capacitance, supply_voltage, frequency):
    dynamic_power_value = # your code here
    return dynamic_power_value

# call and test the function with a simple example
print(dynamic_power(1, 2, 3, 4))
# Define the static power
def static_power(leakage_current, supply_voltage):
    static_power_value = # your code here
    return static_power_value

# call and test the function with a simple example
print(static_power(2, 3))
# Define the chip battery
def chip_battery(dynamic_power_value, static_power_value, battery_capacity):
    battery_time = # your code here
    return battery_time

# call and test the function with a simple example
print(chip_battery(10,2, 3))

After that, use the provided values for two different scenarios for the parameters and call the functions accordingly.

Scenario 1

  • battery_capacity = 30 (Ah)

  • alpha = 0.1

  • capacitance = 10e-9 (F)

  • supply_voltage = 2.0 (V)

  • frequency = 100e6 (Hz)

  • leakage_current = 100e-3 (A)

Scenario 2

  • battery_capacity = 52 (Ah)

  • alpha = 0.1

  • capacitance = 20e-9 (F)

  • supply_voltage = 4.0 (V)

  • frequency = 10e6 (Hz)

  • leakage_current = 50e-3 (A)

print("Scenario 1:")

# Assign values
alpha = 0.1
capacitance = 10e-9       # F
supply_voltage = 2.0      # V
frequency = 100e6         # Hz
leakage_current = 100e-3  # A
battery_capacity = 30     # Ah

# Call the functions
dynamic_power_value = # your code here
static_power_value = # your code here
battery_time = # your code here

# Print the results
print(f"Dynamic Power: {dynamic_power_value:.2f} W")
print(f"Static Power: {static_power_value:.2f} W")
print(f"Battery Time: {battery_time:.2f} hours")
print("Scenario 2:")

# Assign values
alpha = 0.1
capacitance = 20e-9       # F
supply_voltage = 4.0      # V
frequency = 10e6         # Hz
leakage_current = 50e-3  # A
battery_capacity = 52     # Ah

# Call the functions
# your code here

# Print the results
# your code here

7.8.3. Exercise: Palindrome checker#

Create a program that defines a function to check if a given string is a palindrome (reads the same forwards and backwards). Define a string variable and display whether it’s a palindrome or not. Test your code with some examples and make sure it’s not case sensitive.

First, remember how to make a word lowercase and how to reverse it. Once you have that in mind, you can start writing the program to solve the problem. You can use the example in the cell below.

# define a variable with a word stored in it
word = "Hello"

# Convert the word to lowercase
lower = # your code here
print(lower)

# Reverse the word using slicing
reverse = # your code here
print(reverse)
def palindrom_checker(word):

  word = # your code here
  revers_word=# your code here

  # your code here:


palindrom_checker ("Hello")
palindrom_checker ("Bob")