4 Functions

A function is a sequence of instructions that has been given a name.
Functions allow us to avoid repetition, organize code, and make programs easier to understand, test, and maintain.

In Python, we use the keyword def to define a function.

Defining a Function

The syntax for defining a simple function is:

def function_name():
    # Code to be executed by the function

Example 1: A simple greeting function

def greeting():
    print("Hello, world!")

Example 2: Function with a parameter

def square(n):
    print(n**2)

Here, n is called a parameter. When we call the function, we provide an argument to replace the parameter.

Return Values

So far, our functions have printed a result directly. But often, we want the function to produce a value that can be used later in calculations.

  • A function that sends back a value is said to return a value.
  • Most Python functions return values instead of printing them.

For example, the built-in sum() function takes a list and returns the sum of its elements.

Syntax of a function with return:

def half(x):
    return x / 2

Example:

y = half(36)
print(y)
18.0

Here, the value 18.0 is returned by the function and stored in the variable y.

Default Parameter Values

Sometimes, it is useful to give a default value to a parameter. This means that if the caller does not provide a value, Python will automatically use the default.

Example:

def sum_first(arg_list, n=5):
    total = 0
    for i in range(n):
        total += arg_list[i]
    return total
  • If n is not specified, the function sums the first 5 elements.
  • If n is provided, it overrides the default.
print(sum_first([1, 2, 3, 4, 5, 6, 7]))    # default n=5 → 15
print(sum_first([1, 2, 3, 4, 5, 6, 7], 3)) # n=3 → 6
15
6

Returning Multiple Values

A Python function can return more than one value. This is usually done by returning a tuple (or list).

Example:

def power(a, b):
    return (a**b, b**a)

a_to_b, b_to_a = power(2, 5)
print(a_to_b)
print(b_to_a)
32
25
  • The function returns two values: 2^5 and 5^2.
  • These are stored in two separate variables.

Anonymous (Lambda) Functions

  • Python has support for so-called anonymous or lambda functions, which are a way of writing functions consisting of a single statement, the result of which is the return value.

  • They are defined with the lambda keyword:

def short_function(x):
    return x * 2
## Equivalent Anonymous Function
equiv_anon = lambda x: x * 2
equiv_anon(10)
20
  • They are especially convenient in data analysis because, as we’ll see, there are many cases where data transformation functions will take functions as arguments.

  • For example, suppose we wanted to sort a collection of strings by the number of distinct letters in each string:

strings = ["foo", "card", "bar", "aaaa", "abab"]
  • Here, we could pass a lambda function to the list’s sort method:
strings.sort(key=lambda x: len(set(x)))
strings
['aaaa', 'foo', 'abab', 'bar', 'card']

Generator Functions

Sometimes we want a function to produce a sequence of values one at a time instead of returning everything at once. This is where generator functions come in.

  • Defined like normal functions but use the keyword yield instead of return.
  • Each time the function yields a value, its state is saved so it can resume where it left off.

Example:

def count_up_to(n):
    i = 1
    while i <= n:
        yield i   # pause and return value
        i += 1

gen = count_up_to(5)
print(next(gen))  # 1
print(next(gen))  # 2
1
2
  • The function doesn’t finish after the first yield.
  • Instead, it pauses and continues from where it left off when next() is called again.

Why Generators?

  • Memory-efficient: They don’t store all values at once.
  • Lazy evaluation: Values are produced only when needed.
  • Useful for large datasets or infinite sequences.

Example: Infinite Even Numbers

def infinite_even_numbers():
    n = 0
    while True:
        yield n
        n += 2

gen = infinite_even_numbers()
print(next(gen))  # 0
print(next(gen))  # 2
print(next(gen))  # 4
0
2
4

Exercises

  1. Division with Remainder Write a function div_w_remainder(num, div) that returns both the quotient and the remainder. The remainder should be coerced into an integer.

  2. Locating Elements in a List Write a function locate(x, item) that takes a list x and searches for the element item. The function should return the index if found, or -1 if not found.

  3. Area of a Circle Write a function that takes the radius as input and returns the area of the circle. (Hint: Use π ≈ 3.1416)

  4. Maximum of Three Numbers Write a function max_of_three(a, b, c) that returns the largest of the three numbers.

  5. Generator Exercise Write a generator function squares(n) that yields the squares of numbers from 1 up to n. Test it using next() and a for loop.