---
description: >-
  In this section, we will cover the basics of Python functions.  Knowing how to
  use functions is essential for writing efficient and reusable code...
---

# Functions

A function is a block of code that performs a specific task. It is like a subprogram that can be called from the main program. Functions take input arguments, perform operations, and return output values. Python provides several built-in functions, and we can also define our own functions to perform custom operations.

### Benefits of Using Functions

There are several benefits of using functions in programming, including:

1. Code Reusability: Functions allow us to reuse code by defining a block of code that can be called multiple times from different parts of the program.
2. Modularity: Functions break down complex tasks into smaller, more manageable units, making the code more organized and easier to maintain.
3. Abstraction: Functions provide an abstraction layer that hides the complexity of the code and makes it easier to use.
4. Debugging: Functions make it easier to isolate and fix errors in code, making debugging a more straightforward process.

### Types of function <a href="#types" id="types"></a>

There are two types of function in Python programming:

* **Standard library functions** - These are built-in functions in Python that are available to use.
* **User-defined functions** - We can create our own functions based on our requirements.\


## Defining and Calling Functions

Defining and calling functions is a fundamental concept in Python programming. Functions enable us to organize code into reusable blocks, which makes our programs easier to read, debug, and maintain. In this section, we will explore the process of defining and calling functions in Python.

### Defining Functions

Defining a function in Python means creating a function object that maps the function name to the function.&#x20;

#### a. Syntax&#x20;

#### The syntax for defining a function in Python is:

```python
def function_name(parameters):
    """docstring"""
    statement(s)
```

Where:

* `def` keyword is used to define a function.
* `function_name` is the name of the function. It should follow the same naming rules as for the identifiers.
* `parameters` are the input arguments to the function. They are optional.
* `docstring` is an optional documentation string that describes what the function does. It is enclosed within triple quotes.
* `statement(s)` are the statements that are executed when the function is called. They should be indented with four spaces.

For example:

```python
def greet(name):
    """This function greets the person passed in as parameter"""
    print("Hello, " + name + ". How are you doing?")

```

Here, `greet` is the name of the function, `name` is the input parameter, and the `print()` statement is executed when the function is called.

#### &#x20;b. Parameters&#x20;

Function parameters are the inputs that a function can accept. Parameters allow us to pass values or data to a function, which the function can then use to perform certain operations. In Python, function parameters are defined within the parentheses following the function name. There are two types of parameters:

1. Positional parameters: These are mandatory parameters that are passed to a function in a specific order. The number of positional parameters should match the number of arguments passed to the function.
2. Keyword parameters: These are optional parameters that can be passed to a function with a specific keyword. They have default values assigned to them, which are used when no value is passed for them during function call.

For example:

```python
def greet(name, message="Hello"):
    print(message + ", " + name)
```

In this example, `name` is a positional parameter and `message` is a keyword parameter with a default value of "Hello". We can call this function using either positional or keyword arguments:

```arduino
greet("John")   # prints "Hello, John"
greet("Jane", "Hi")   # prints "Hi, Jane"
greet(message="Hi", name="Alice")   # prints "Hi, Alice"
```

{% hint style="info" %}
Note that when using keyword parameters, the order in which they are passed does not matter, as long as their keywords match the parameter names in the function definition.\

{% endhint %}

#### c. Return Values&#x20;

In Python, functions can return values using the `return` statement. The `return` statement can be followed by a value or an expression that is evaluated to return the value. The general syntax for returning values from a function is as follows:

```python
def function_name(parameters):
    # function body
    return value
```

Here, the `return` statement is used to return the value to the calling function. The value can be of any data type, such as an integer, float, string, or even a list, dictionary, or tuple.

When a function returns a value, it can be assigned to a variable, used in an expression, or printed to the console using the `print()` function.

For example, the following function calculates the sum of two numbers and returns the result:

```arduino
def sum_numbers(a, b):
    result = a + b
    return result
```

The function can be called and the returned value can be printed to the console using the following code:

```scss
result = sum_numbers(10, 20)
print(result)
```

This will output `30` to the console, which is the result of adding `10` and `20`.&#x20;

#### Examples&#x20;

Here's an example of a function that takes two parameters and returns their sum:

```python
def add_numbers(a, b):
    sum = a + b
    return sum
```

In this example, we define a function called `add_numbers` that takes two parameters `a` and `b`. The function then calculates their sum and returns the result using the `return` keyword. Once the function is defined, we can call it and pass in arguments to the parameters:

```scss
result = add_numbers(5, 7)
print(result) # Output: 12
```

In this example, we call the `add_numbers` function and pass in the values `5` and `7` as arguments to its parameters `a` and `b`. The function then calculates the sum of these two values and returns `12`. Finally, we assign the return value of the function to a variable called `result` and print it to the console.&#x20;

### Calling Functions&#x20;

After defining a function, you can call it to perform a specific task or operation. When a function is called, the code inside the function's block gets executed, and the function may return a value if specified.

#### &#x20;a. Syntax &#x20;

The syntax for calling a function is:

```scss
function_name(argument1, argument2, ...)
```

Here, `function_name` is the name of the function that you want to call and `argument1`, `argument2`, and so on, are the arguments that you want to pass to the function. If the function doesn't take any arguments, you can simply call it using the following syntax:

```scss
function_name()
```

This will call the function with no arguments.&#x20;

#### b. Positional Arguments&#x20;

Positional arguments are the most common type of arguments passed to a function in Python. In this type of argument passing, the arguments are matched based on their position in the function call. The first argument in the function call is matched with the first parameter in the function definition, the second argument with the second parameter, and so on.

For example, let's say we have a function called `add_numbers` that takes two arguments, `num1` and `num2`, and returns their sum:

```python
def add_numbers(num1, num2):
    return num1 + num2
```

To call this function, we can pass two values as positional arguments:

```scss
result = add_numbers(5, 10)
print(result)   # Output: 15
```

In this example, the first argument `5` is matched with the first parameter `num1`, and the second argument `10` is matched with the second parameter `num2`. The function returns their sum `15`, which is then printed to the console.&#x20;

#### c. Keyword Arguments&#x20;

Keyword arguments are arguments passed to a function that are preceded by the name of the parameter to which they correspond. In this case, the order in which the arguments are passed doesn't matter, as long as each argument is assigned to the correct parameter.

Here is an example of a function call with keyword arguments:

```python
def greet(name, message):
    print(f"{message}, {name}!")

greet(message="Hello", name="Rocky")
```

Output:

```
Hello, Rocky!
```

In the example above, we pass the arguments `message` and `name` to the function `greet` using the syntax `parameter_name=value`. This allows us to pass arguments out of order without any confusion, and makes our code more readable.&#x20;

#### d. Default Values&#x20;

When defining a function, you can specify default values for some or all of the parameters. These default values will be used when the function is called without passing any values for those parameters.

Here's an example:

```scss
def greet(name, greeting='Hello'):
    print(greeting + ', ' + name)

greet('Alice')          # prints "Hello, Alice"
greet('Bob', 'Hi')      # prints "Hi, Bob"
```

In the example above, `greeting` is an optional parameter with a default value of `'Hello'`. When we call `greet('Alice')`, the function uses the default value for `greeting` and prints "Hello, Alice". When we call `greet('Bob', 'Hi')`, the function uses the value `'Hi'` for `greeting` and prints "Hi, Bob".

#### Examples&#x20;

```python
# Defining a function to calculate the sum of two numbers
def add_numbers(num1, num2):
    sum = num1 + num2
    return sum

# Calling the function with positional arguments
result1 = add_numbers(5, 10)
print("Result 1:", result1)

# Calling the function with keyword arguments
result2 = add_numbers(num1=7, num2=3)
print("Result 2:", result2)

# Calling the function with one argument and using the default value for the other
result3 = add_numbers(num1=2)
print("Result 3:", result3)
```

Output:

```rust
Result 1: 15
Result 2: 10
Result 3: TypeError: add_numbers() missing 1 required positional argument: 'num2'
```

In this example, we defined a function `add_numbers()` that takes two parameters and returns their sum. We then called the function three times with different combinations of arguments:

* The first call uses positional arguments to pass `5` and `10` as the values for `num1` and `num2`, respectively.
* The second call uses keyword arguments to pass `7` and `3` to `num1` and `num2`, respectively.
* The third call only passes a value for `num1`, which uses the default value of `0` for `num2`. However, this call results in a `TypeError` because the function requires two arguments and we only provided one.&#x20;

## Function Arguments

Functions are an essential aspect of Python programming. They allow us to create blocks of code that can be reused throughout our code, which makes our code more efficient, modular, and easier to maintain. In Python, we can define functions that accept arguments to take input values and use them to perform some tasks.

There are several types of function arguments in Python, and we will explore them in detail. We will learn how to define functions with arguments and how to call them with different types of arguments, including positional arguments, keyword arguments, and default arguments.&#x20;

### Positional Arguments&#x20;

When it comes to passing arguments to a function, positional arguments are one of the most commonly used methods in Python. As the name suggests, these arguments are passed based on their position or order, from left to right, in the function call.

In other words, the first argument passed in the function call corresponds to the first parameter defined in the function definition, the second argument corresponds to the second parameter, and so on. Positional arguments are useful when you want to pass a fixed number of arguments to a function, and the order in which they are passed is important.

Let's take an example of a function that calculates the area of a rectangle using its length and breadth as arguments. The length and breadth will be our positional arguments, and their order will be important.

```python
def calculate_area(length, breadth):
    area = length * breadth
    return area

# Calling the function with positional arguments
result = calculate_area(5, 6)
print("The area of the rectangle is:", result)
```

In this example, we define a function called `calculate_area` that takes two positional arguments: `length` and `breadth`. We then call the function and pass the values `5` and `6` as arguments, respectively. These values are assigned to `length` and `breadth` in the function definition, and the area of the rectangle is calculated using the formula `area = length * breadth`. Finally, the calculated area is returned and printed to the console.&#x20;

### Keyword Arguments&#x20;

When calling a function, the values for the parameters can be passed by specifying the parameter names, rather than relying on their positions. These are called keyword arguments. Using keyword arguments can make the function call more readable and easier to understand, especially when dealing with functions that have many parameters.

Keyword arguments are particularly useful when the function has default parameter values. By using keyword arguments, you can selectively override the default values for only the parameters that need to be changed.

For example, let's consider a function that calculates the volume of a rectangular prism, which has three parameters: length, width, and height. We can use keyword arguments to specify the values for these parameters, like this:

```python
def calculate_volume(length, width, height):
    return length * width * height

# calling the function with keyword arguments
volume = calculate_volume(length=3, width=4, height=5)
```

Here, we've specified the values for the length, width, and height parameters using keyword arguments. This makes the function call more readable, and we can easily see what values we're passing in.

Using keyword arguments can also make the function call more robust to changes in the function signature. If we add or remove a parameter from the function, the function call will still work as long as the parameter names remain the same. This is in contrast to positional arguments, where adding or removing a parameter can break the function call if the argument positions are not adjusted accordingly.&#x20;

### Default Arguments&#x20;

Have you ever found yourself repeatedly passing the same argument to a function while calling it? In Python, you can avoid that repetition by setting default values for function arguments. In this way, if an argument is not specified while calling the function, it takes the default value that was defined in the function definition. This feature is known as default arguments. Default arguments are used to provide a default value to a function parameter in case a value is not provided when the function is called. This makes it easier to write functions that can handle different input values without requiring the user to provide a value for every parameter.

#### &#x20;**Syntax**

To specify a default value for a parameter, you simply include an equal sign and the default value after the parameter name in the function definition. For example:

```python
def greet(name, message="Hello"):
    print(message, name)
```

In this example, the `message` parameter has a default value of `"Hello"`. If the user does not provide a value for `message` when they call the `greet` function, it will default to `"Hello"`. If the user does provide a value for `message`, that value will be used instead.

#### Example

```scss
def greet(name, message="Hello"):
    print(message, name)

greet("John") # prints "Hello John"
greet("Jane", "Hi there") # prints "Hi there Jane"
```

In this example, we define a function `greet` that takes two parameters: `name` and `message`. If the user does not provide a value for `message`, it defaults to `"Hello"`. We then call the `greet` function twice, once with only a value for `name`, and once with values for both `name` and `message`. The function uses the default value of `"Hello"` for `message` in the first call, and the user-provided value of `"Hi there"` in the second call.&#x20;

### Variable-Length Arguments (Arbitrary Arguments)&#x20;

Variable-length arguments, also known as arbitrary arguments, allow a function to accept any number of arguments. In Python, there are two types of variable-length arguments: \*args and \*\*kwargs.

_args is used to pass a variable number of non-keyword arguments to a function. It is represented by an asterisk (_) before the parameter name in the function definition. The function treats the arguments as a tuple.

**kwargs is used to pass a variable number of keyword arguments to a function. It is represented by two asterisks (**) before the parameter name in the function definition. The function treats the arguments as a dictionary.

Using variable-length arguments makes the function more flexible, as it allows the user to pass any number of arguments without having to change the function definition.

Here is an example of a function that accepts variable-length arguments:

```python
def print_args(*args, **kwargs):
    print("Positional arguments:", args)
    print("Keyword arguments:", kwargs)
    
print_args(1, 2, 3, a=4, b=5)
```

Output:

```css
Positional arguments: (1, 2, 3)
Keyword arguments: {'a': 4, 'b': 5}
```

In this example, the print\_args() function accepts both positional arguments (1, 2, 3) and keyword arguments (a=4, b=5). The function then prints the positional arguments as a tuple and the keyword arguments as a dictionary.

Note that the order of the parameter names does not matter, but \*args must come before \*\*kwargs in the function definition.&#x20;

### Keyword Variable-Length Arguments.

Keyword variable-length arguments, also known as kwargs, allow you to pass a variable number of keyword arguments to a function. This means you can pass any number of arguments to a function, as long as they are all named.

The syntax for defining kwargs uses two asterisks (\*\*) before the parameter name. Within the function, kwargs are treated as dictionaries, with the keyword argument names as keys and their corresponding values as values.

Kwargs are especially useful when you want to create a function with a lot of optional arguments, as it allows you to pass them in a flexible manner without having to define all possible argument combinations in the function definition.

Here's an example of using kwargs in a function definition:

```python
def print_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")
```

In this example, the `print_kwargs` function takes any number of keyword arguments and prints them out in the format `key: value`.

Here's how you can call the `print_kwargs` function with kwargs:

```python
print_kwargs(name="Rocky", age=30, location="New York")
```

This will output:

```vbnet
name: Rocky
age: 30
location: New York
```

As you can see, the kwargs are passed as keyword arguments, with the argument name followed by the value. The function then prints out each key-value pair in the kwargs dictionary.

## Anonymous Functions (Lambda Functions)&#x20;

Lambda functions, also known as anonymous functions, are functions without a name. These functions are small and typically used when you need to pass a function as an argument to another function. Lambda functions are defined using the keyword "lambda" and can take any number of arguments, but can only have one expression.

Lambda functions are often used with built-in functions such as filter(), map(), and reduce(). They are also commonly used in functional programming paradigms.

The syntax of a lambda function is:

```python
lambda arguments: expression
```

Here, "arguments" are the parameters that the lambda function will accept and "expression" is the operation that the function will perform.

Let's take an example to understand it better:

```makefile
# Define a lambda function to add two numbers
add_numbers = lambda x, y: x + y

# Call the lambda function
result = add_numbers(10, 20)

# Print the result
print(result)
```

In the example above, we defined a lambda function that takes two arguments and adds them together. We then called the lambda function with arguments 10 and 20 and stored the result in the variable "result". Finally, we printed the result, which is 30.

Lambda functions are a powerful tool in Python programming, but it's important to use them wisely and only when necessary.\


## Return Statement

The return statement is a fundamental concept in Python functions. It is used to return a value or an expression from a function to the calling program. When a return statement is encountered in a function, it immediately terminates the execution of the function and returns the specified value to the calling program.

The return statement in Python can be used with or without a value. If you don't specify a value after the return keyword, it returns None by default.

In Python, a function can return multiple values separated by commas. When multiple values are returned, they are packed into a tuple.

Example:

```python
def sum_and_difference(a, b):
    sum = a + b
    difference = a - b
    return sum, difference

result = sum_and_difference(10, 5)
print(result)  # Output: (15, 5)
```

In the example above, the `sum_and_difference` function returns two values: the sum and the difference of the two input arguments. The function is called with the arguments `10` and `5`, and the returned values are assigned to the variable `result`. The print statement outputs the tuple containing the two returned values.

It's important to note that the return statement can only be used within a function. If you try to use it outside of a function, you will get a syntax error.&#x20;

## Global and Local Variables

Global and local variables are an essential aspect of programming in any language, and Python is no exception. In Python, a variable's scope determines where the variable can be accessed within the code. There are two types of variables in Python - global variables and local variables.

Global variables are the variables that are declared outside a function or a block of code, and they can be accessed from anywhere within the code. Local variables, on the other hand, are declared inside a function or a block of code and can only be accessed within that block.

When a variable is declared inside a function, it is by default considered to be a local variable. If we want to use the same variable name globally, we can use the 'global' keyword to indicate that the variable is a global variable.&#x20;

### a. Global variable&#x20;

In Python, a variable defined outside a function is a global variable. Global variables are accessible from any part of the code, including inside functions. However, if a function tries to modify a global variable, it must first declare the variable as global using the `global` keyword. Otherwise, the function will create a new local variable with the same name as the global variable, which will have no effect on the original global variable.

Here's an example:

<pre class="language-python"><code class="lang-python"><strong>x = 10 # global variable
</strong>
def my_func():
    global x
    x += 5 # modifies the global variable
    print(x) # prints 15

my_func()
print(x) # prints 15
</code></pre>

In this example, we have a global variable `x` with a value of 10. The function `my_func()` modifies the value of `x` by adding 5 to it and then prints the new value. When we call the function, it prints 15. After the function call, we print the value of `x` again, which is still 15 because we modified the global variable inside the function.

Without the `global` keyword, the function would create a new local variable `x` that has no relation to the global variable `x`:

```python
x = 10 # global variable

def my_func():
    x = 5 # creates a new local variable x
    print(x) # prints 5

my_func()
print(x) # prints 10
```

In this example, the function `my_func()` creates a new local variable `x` with a value of 5. When we call the function, it prints the local variable, which is 5. After the function call, we print the value of the global variable `x`, which is still 10 and was not affected by the function call.&#x20;

### b. Local variables&#x20;

In Python, a variable defined inside a function has local scope, which means it can only be accessed inside that function. Local variables can be defined with the same name as a global variable, but they are entirely different variables.

Here's an example:

```python
x = 5  # global variable

def my_function():
    x = 3  # local variable with the same name as global variable
    print("Local variable x:", x)

my_function()
print("Global variable x:", x)
```

Output:

```sql
Local variable x: 3
Global variable x: 5
```

In the example above, `x` is a global variable with a value of 5. Inside the `my_function` function, a local variable named `x` is defined with a value of 3. When the function is called, the local variable `x` is printed, which outputs `3`. After the function call, the global variable `x` is printed, which outputs `5`.

It's important to note that a local variable cannot be accessed outside of the function in which it is defined. If you try to access a local variable outside of its function, a `NameError` will occur.

## Recursion&#x20;

Recursion is a programming technique where a function calls itself repeatedly until a specific condition is met. In Python, as in many other programming languages, recursion is a powerful tool that can be used to solve complex problems.

The basic idea behind recursion is to break down a problem into smaller subproblems that are easier to solve, and then combine the results to solve the original problem. Recursive functions have a few key components:

1. Base case: The simplest form of the problem that can be solved directly without recursion.
2. Recursive case: The problem is broken down into smaller subproblems that are solved recursively, until the base case is reached.

Recursion can be used to solve a wide variety of problems, such as traversing complex data structures like trees and graphs, searching for patterns in data, and generating fractal images. However, it's important to use recursion judiciously, since it can be computationally expensive and lead to stack overflow errors if not used properly.&#x20;

### Example:

```arduino
def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)
```

This is a function that calculates the factorial of a number using recursion. The base case is when `n` is equal to 1, and the function simply returns 1. Otherwise, it calculates `n` times the factorial of `n-1`, which is done by calling the function recursively.

For example, `factorial(5)` would return `120` because 5 x 4 x 3 x 2 x 1 = 120.

## Function Decorators&#x20;

Function decorators are a way to add extra functionality to existing functions in Python. Decorators allow you to modify or extend the behavior of a function without changing its source code. They are a powerful tool for code reuse and can help you write more efficient and maintainable code.

In Python, a decorator is a special type of function that takes another function as its argument and returns a new function with some additional functionality. The syntax for using decorators is simply to place the decorator function name above the function definition you want to decorate.

Here's an example of a simple decorator that adds a timer to a function:

```python
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Elapsed time: {end_time - start_time:.2f} seconds")
        return result
    return wrapper

@timer
def my_function():
    time.sleep(1)
    return "Hello, World!"

my_function()
```

In this example, the `timer` function is a decorator that takes another function `func` as an argument. It defines a new function `wrapper` that wraps the original function `func` with the timer functionality. The `wrapper` function uses the `time` module to measure the elapsed time of the original function, then prints the elapsed time to the console.

The `@timer` decorator syntax is used to decorate the `my_function` function with the `timer` decorator. When `my_function` is called, it is actually the decorated `wrapper` function that gets executed. The `wrapper` function calls the original `my_function` and returns its result, while also printing the elapsed time.

Function decorators can be used for a variety of purposes, such as caching, logging, authentication, and more. They are a powerful and flexible tool for extending the functionality of your Python code.

\
\
