Python For Beginners

Introduction to Functions

Functions allow you to encapsulate a task; they take input, process that input, and then produce and return output.
Enroll

Introduction to Functions

Theory

Functions are fundamental building blocks in Python and many other programming languages. They allow you to encapsulate a task; they take input, process that input, and then produce and return output. Think of functions as mini-programs within your larger program that are responsible for performing specific tasks.

The use of functions offers several benefits:

  • Code Reusability: Once you've defined a function, you can use it multiple times throughout your program. This means you can write the code once and use it in many different situations, rather than rewriting the same code over and over again.
  • Organization: Functions help you to organize your code better. By segmenting your code into functions, you make it more readable and manageable. Each function has a specific job, which helps in understanding the overall program flow.
  • Readability: Functions can make a program more readable by giving blocks of code a name. This makes the program easier to understand, not just for you, but for anyone else who might read your code in the future.

Syntax

The basic syntax of a function in Python is as follows:

def function_name(parameters):
    """Docstring explaining the function."""
    # function body
    return result
  • def: This keyword is used to declare or define a function.
  • function_name: This is the name of the function. It should be descriptive and follow the naming conventions of Python (lowercase with words separated by underscores).
  • parameters: These are the variables that you pass into the function. A function can have any number of parameters, including none at all.
  • Docstring: This is an optional string that explains what the function does. Although optional, it's good practice to include a docstring for most functions, especially complex ones.
  • Function body: This is where you write the code that the function will execute. It can include one or more lines of code.
  • return: This keyword is used to exit a function and pass back a value to the caller. A function doesn't always have to return something; if no return statement is used, the function will return None by default.

Here's a simple example of a function in Python:

def say_hello(name):
    """Greet the person by name."""
    greeting = f"Hello, {name}!"
    return greeting

In this example, say_hello is a function that takes one parameter, name, and returns a greeting string. The function demonstrates the basic structure and components of a function in Python.

Parameters and Arguments

Theory

In the context of functions, the terms "parameters" and "arguments" are often used interchangeably, but there is a subtle difference between them that is important to understand.

  • Parameters refer to the variables that are listed in the function's definition. Parameters act as placeholders for the values that a function expects to receive when it is called. You can think of parameters as the "input slots" that a function has for receiving data.
  • Arguments, on the other hand, are the actual values that are passed to the function when it is called. Arguments are the data you provide to fill in the "input slots" defined by the parameters. When a function is executed, the arguments are the values that are used within the function.

This distinction is crucial for understanding how to pass data to functions and how that data is handled inside the function.

Example 2: Function with Parameters and Passing Arguments

Let's define a simple function that uses parameters and then demonstrate how to pass arguments to it.

Function Definition:

def calculate_difference(x, y):
    """Calculate and return the difference between two numbers."""
    difference = x - y
    return difference

In this function, calculate_difference, x and y are parameters. These parameters are placeholders for the numbers that will be subtracted when the function is called.

Passing Arguments to the Function:

Now, let's call this function and pass arguments to it.

result = calculate_difference(10, 5)
print("The difference is:", result)


In this call, 10 and 5 are the arguments. Here, 10 is passed as the argument for the parameter x, and 5 is passed as the argument for the parameter y. When the function runs, it calculates the difference (10 - 5) and returns 5. The returned value is then printed, showing "The difference is: 5".

This example demonstrates how parameters and arguments work together to allow functions to perform operations on dynamic data. The parameters (x and y) define what kind of data the function should expect, and the arguments (10 and 5) provide the actual data to work with.

Default Parameter Values

Theory

In Python, you can assign default values to the parameters of a function. This feature allows those parameters to be optional when the function is called. If the caller provides a value for the parameter, that value is used in the function. If the caller does not provide a value, the default value is used instead.

Default parameter values make functions more flexible and easier to use. They can significantly reduce the need for function overloads and help manage situations where default behavior is desired most of the time.

To assign a default value to a parameter, you use the assignment operator (=) in the function's definition. This default value must be a constant or a value that is determined at the time the function is defined; it cannot be something that is determined at runtime (with some exceptions for mutable types, but that's an advanced topic).

Example 4: Function with Default Parameters

Let's create a function that greets a user. The function will have a parameter for the user's name, but we'll provide a default value in case the name is not provided.

Function Definition with Default Parameter:

def greet(name="Guest"):
    """Return a greeting string for the provided name, or 'Guest' if no name is provided."""
    return f"Hello, {name}!"

In this example, name="Guest" sets the default value of the name parameter to "Guest". This means that if the greet function is called without an argument, "Guest" will be used as the value for name.

Calling the Function with and without an Argument:

  • With an argument:

personal_greeting = greet("Alice")
print(personal_greeting)  # Output: Hello, Alice!

  • Without an argument (using the default value):

default_greeting = greet()
print(default_greeting)  # Output: Hello, Guest!

These examples demonstrate how default parameter values work in Python. By specifying a default value for the name parameter, the greet function can be called with or without providing a name. This flexibility allows for more versatile function designs and simplifies cases where a common default behavior is sufficient.

Variable Scope

Theory

In Python, the scope of a variable refers to the part of the program where that variable is accessible. Variable scope is determined by where the variable is defined. The two main types of scope in Python are:

  • Local Scope: Variables created inside a function belong to the local scope of that function, and can only be used inside that function.
  • Global Scope: Variables created in the main body of the Python code are global variables and are accessible throughout the code, including inside functions.

Understanding the distinction between local and global scopes is crucial for managing variable values and avoiding naming conflicts or unexpected behavior in your code.

Local vs. Global Scope

  • Local Variables: Cannot be accessed or modified outside the function in which they are declared. They are created at the function's start and destroyed when the function ends.
  • Global Variables: Can be accessed throughout the code, from any location. However, to modify a global variable inside a function, you must use the global keyword to declare that the variable is global.

Example 5: Demonstrating Variable Scope

Local Variable Example:

def my_function():
    local_variable = 5
    print(local_variable)  # This will print 5

my_function()
# Trying to print local_variable outside the function will raise an error:
# print(local_variable)  # NameError: name 'local_variable' is not defined

In this example, local_variable is defined inside my_function and is only accessible within this function. Attempting to access it outside will result in a NameError.

Global Variable Example:

global_variable = 10

def access_global_variable():
    # Accessing a global variable inside a function
    print(global_variable)  # This will print 10

access_global_variable()
print(global_variable)  # This will also print 10

Here, global_variable is defined outside any function, making it a global variable accessible anywhere in the code.

Modifying a Global Variable Inside a Function:

counter = 0  # A global variable

def increment_counter():
    global counter  # Declare counter as global to modify it
    counter += 1

increment_counter()
print(counter)  # This will print 1

Exercise 5: Fixing Scope-Related Errors

Below is a function that attempts to modify and print a variable from outside its scope. Your task is to fix the code so that it correctly increments and prints the global variable number each time the function is called.

number = 0

def increment_number():
    # This function should increment and print the global variable 'number'
    # Add your code here

increment_number()  # Should print 1
increment_number()  # Should print 2

Task: Modify the increment_number function so it correctly uses the global variable number. Ensure it increments this variable and prints the new value each time the function is called.

Docstrings

Theory

Docstrings, short for documentation strings, play a crucial role in documenting Python code, especially functions. They are enclosed in triple quotes ("""Docstring""") and are placed immediately after the function header. Docstrings serve several important purposes:

  • Documentation: They provide a convenient way of associating documentation directly with Python functions, classes, and modules. This documentation can be accessed through the help() function in Python, making it easily retrievable for developers.
  • Readability: Docstrings improve the readability of the code by providing a high-level overview of what the function does, its parameters, what it returns, and any other pertinent information. This helps developers understand the purpose and workings of a function without needing to read its code.
  • Standardization: The Python community encourages the use of docstrings, providing a standardized way of documenting code. Various tools can automatically generate documentation from docstrings, making it easier to maintain up-to-date documentation.
  • Best Practices: Writing docstrings is considered a best practice in Python programming. It's encouraged to write docstrings for public functions, classes, and modules at the very least, though documenting more extensively is usually better.

Example 6: Writing a Docstring

Let's take a look at how to write a docstring for a simple function. We'll document a function named add, which adds two numbers together and returns the result.

def add(a, b):
    """Add two numbers and return the result.

    Parameters:
    a (int): The first number to add.
    b (int): The second number to add.

    Returns:
    int: The sum of `a` and `b`.
    """
    return a + b

In this example, the docstring for the add function provides a concise description of what the function does ("Add two numbers and return the result"). It also documents the parameters a and b, including their expected data types (both int) and a brief description of each. Finally, it describes the return value of the function, indicating that it returns an integer which is the sum of a and b.

This docstring format is clear and informative, making it easy for someone else (or yourself in the future) to understand the purpose and usage of the add function without needing to delve into its implementation.

Advanced: Variable Number of Arguments

Theory

In Python, functions can be designed to accept a variable number of arguments, allowing for more flexible interactions. This is achieved through the use of *args and **kwargs in the function's definition.

  • *args: Allows a function to accept an arbitrary number of positional arguments. These arguments are accessed within the function as a tuple. The asterisk (*) before the parameter name args is what enables this functionality.
  • **kwargs: Enables a function to accept an arbitrary number of keyword arguments. These are accessed within the function as a dictionary. The double asterisk (**) before the parameter name kwargs signifies this capability.

These features are particularly useful when you're not sure how many arguments might be passed to your function, or if you want to design functions that can accept any number of inputs.

Example 7: Function Using *args and **kwargs

Here's an example function that demonstrates the use of both *args and **kwargs to handle a variable number of both positional and keyword arguments.

def record_information(*args, **kwargs):
    """Print out all positional and keyword arguments provided to the function.

    Parameters:
    *args: A variable number of positional arguments.
    **kwargs: A variable number of keyword arguments.
    """
    print("Positional arguments (args):")
    for arg in args:
        print("-", arg)
    
    print("\nKeyword arguments (kwargs):")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# Example usage
record_information("John Doe", 30, "New York", email="johndoe@example.com", occupation="Developer")

In this record_information function:

  • *args captures the positional arguments ("John Doe", 30, "New York") in a tuple.
  • **kwargs captures the keyword arguments (email="johndoe@example.com", occupation="Developer") in a dictionary.

This function then iterates over these collections to print out the arguments. The flexibility of *args and **kwargs allows this function to accept any number of positional and keyword arguments without needing to specify them upfront in the function's definition. This makes record_information extremely versatile for logging, data processing, or handling user input in a variety of formats.

Function excercises:

Here are 10 exercises covering different aspects of functions in Python, as described above. Each exercise is designed to reinforce a specific concept, ranging from basic function definitions to the use of *args and **kwargs. Solutions are provided for each exercise.

Exercise 1: Simple Function Definition

Task: Define a function named square that takes a single argument and returns its square.

def square(x):
    return x ** 2

# Solution usage
print(square(4))  # Output: 16

Exercise 2: Function with Multiple Parameters

Task: Write a function named multiply that takes two arguments and returns their product.

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

# Solution usage
print(multiply(3, 4))  # Output: 12

Exercise 3: Function with Default Parameters

Task: Create a function greet that takes a name and a greeting with default value "Hello" and returns a greeting message.

def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

# Solution usage
print(greet("Alice"))  # Output: Hello, Alice!
print(greet("Bob", "Hi"))  # Output: Hi, Bob!

Exercise 4: Using Docstrings

Task: Write a function subtract with a docstring that subtracts the second parameter from the first.

def subtract(a, b):
    """Return the result of a minus b."""
    return a - b

# Solution usage
help(subtract)  # Displays the docstring

Exercise 5: Fixing Scope-Related Errors

Task: Given the global variable counter, write a function increment that correctly increments counter.

counter = 0

def increment():
    global counter
    counter += 1

# Solution usage
increment()
print(counter)  # Output: 1
increment()
print(counter)  # Output: 2

Exercise 6: Variable Length Arguments (*args)

Task: Write a function calculate_sum that takes any number of arguments and returns their sum.

def calculate_sum(*args):
    return sum(args)

# Solution usage
print(calculate_sum(1, 2, 3, 4))  # Output: 10

Exercise 7: Keyword Arguments (**kwargs)

Task: Create a function build_profile that accepts a first name and last name, and any number of keyword arguments, and returns a dictionary representing a user profile.

def build_profile(first, last, **kwargs):
    kwargs['first_name'] = first
    kwargs['last_name'] = last
    return kwargs

# Solution usage
profile = build_profile('John', 'Doe', location='New York', field='Software')
print(profile)

Exercise 8: Combining *args and **kwargs

Task: Write a function create_record that takes any number of positional arguments (*args) and keyword arguments (**kwargs) and prints them out as a formatted string.

def create_record(*args, **kwargs):
    print("Positional:", args)
    print("Keyword:", kwargs)

# Solution usage
create_record('John', 30, city='New York', email='john@example.com')

Exercise 9: Function Returning Multiple Values

Task: Define a function min_max that takes a list of numbers and returns both the minimum and maximum numbers.

def min_max(numbers):
    return min(numbers), max(numbers)

# Solution usage
print(min_max([1, 2, 3, 4, 5]))  # Output: (1, 5)

Exercise 10: Using Functions as Arguments

Task: Write a function apply_operation that takes a function and a list of numbers. It should apply the given function to all numbers in the list and return the result as a new list.

def apply_operation(func, numbers):
    return [func(number) for number in numbers]

# Solution usage
print(apply_operation(square, [1, 2, 3]))  # Output: [1, 4, 9]

These exercises cover a wide range of function use cases in Python, from simple definitions to more complex scenarios involving variable number of arguments and scope management. They are designed to provide hands-on practice with key concepts and encourage experimentation and further exploration.

Functions: map, reduce, filter, and lambda Expressions

In Python, higher-order functions like map, reduce, and filter are used to apply functions to sequences and collections of data. Alongside these functions, lambda expressions allow for defining small, anonymous function objects. Let's explore these concepts.

lambda Expressions

A lambda function is a small anonymous function that can take any number of arguments, but can only have one expression. It is often used in situations requiring a simple function for a short period.

  • Syntax:lambda arguments: expression

map Function

The map function applies a given function to each item of an iterable (list, tuple, etc.) and returns an iterator that yields the results.

  • Syntax:map(function, iterable, ...)

filter Function

The filter function constructs an iterator from elements of an iterable for which a function returns true.

  • Syntax:filter(function, iterable)

reduce Function

The reduce function applies a function of two arguments cumulatively to the items of an iterable, from left to right, so as to reduce the iterable to a single value. This function is part of the functools module.

  • Syntax:from functools import reduce
    reduce(function, iterable[, initializer])

Examples

Using lambda

# A lambda function that adds 10 to the input argument
add_ten = lambda x: x + 10
print(add_ten(5))  # Output: 15

Using map

# Use map to square all numbers in a list
numbers = [1, 2, 3, 4]
squared = map(lambda x: x**2, numbers)
print(list(squared))  # Output: [1, 4, 9, 16]

Using filter

# Use filter to get only even numbers from a list
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  # Output: [2, 4, 6]

Using reduce

# Use reduce to compute the product of numbers in a list
from functools import reduce
numbers = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, numbers)
print(product)  # Output: 24

Exercises on map reduce filter lambda

  1. Square Numbers: Use map to square each number in a list.
  2. Filter Names: Use filter to get names that start with the letter 'A' from a list.
  3. Sum of Numbers: Use reduce to calculate the sum of numbers in a list.
  4. Lengths of Words: Use map and a lambda function to calculate the lengths of each word in a sentence.
  5. Find Maximum: Implement a function using reduce to find the maximum number in a list.

These exercises encourage the practical application of map, reduce, filter, and lambda expressions, enhancing the understanding of functional programming paradigms in Python.

Solutions

Square Numbers

Use map to square each number in a given list.

numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda x: x**2, numbers))
print(squared_numbers)  # Output: [1, 4, 9, 16, 25]

Filter Names

Use filter to extract names that start with the letter 'A' from a list.

names = ["Alice", "Bob", "Alex", "Charlie", "Annie"]
names_with_a = list(filter(lambda name: name.startswith('A'), names))
print(names_with_a)  # Output: ['Alice', 'Alex', 'Annie']

Sum of Numbers

Use reduce to calculate the sum of numbers in a list.

from functools import reduce

numbers = [1, 2, 3, 4, 5]
total_sum = reduce(lambda x, y: x + y, numbers)
print(total_sum)  # Output: 15

Lengths of Words

Use map and a lambda function to calculate the lengths of each word in a sentence.

sentence = "Hello world from Python"
words = sentence.split()  # Splits the sentence into words
word_lengths = list(map(lambda word: len(word), words))
print(word_lengths)  # Output: [5, 5, 4, 6]

Find Maximum

Implement a function using reduce to find the maximum number in a list.

from functools import reduce

numbers = [5, 8, 2, 1, 9, 3, 4, 7]
maximum_number = reduce(lambda x, y: x if x > y else y, numbers)
print(maximum_number)  # Output: 9

These examples showcase how to effectively use map, filter, and reduce functions along with lambda expressions for various common tasks in Python. They provide a concise way to perform operations on collections of data, adhering to the principles of functional programming.

Lesson Assignment
Challenge yourself with our lab assignment and put your skills to test.
# Python Program to find the area of triangle

a = 5
b = 6
c = 7

# Uncomment below to take inputs from the user
# a = float(input('Enter first side: '))
# b = float(input('Enter second side: '))
# c = float(input('Enter third side: '))

# calculate the semi-perimeter
s = (a + b + c) / 2

# calculate the area
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('The area of the triangle is %0.2f' %area)
Sign up to get access to our code lab and run this code.
Sign up

Create Your Account Now!

Join our platform today and unlock access to expert- led courses, hands- on exercises, and a supportive learning community.
Sign Up