# “def” Keyword in Python: Defining Functions the Right Way

In Python, the `def` keyword is used for creating functions. Functions are one of the fundamental building blocks of an application. They help in code reuse and make it easier to understand and debug the code. The `def` keyword is used for defining both simple and complex functions, with or without arguments.

This article will explain the `def` keyword in detail, along with various examples and use cases.

## Creating a Simple Function using the def keyword

Let’s start by looking at how to create a simple function using the `def` keyword. Here’s a simple example:

```def my_function():
print("Hello World!")

# Call the function
my_function()```

In the above code snippet, we have defined a simple function `my_function()` using the `def` keyword. The function does not take any arguments and simply prints “Hello World!” when called.

To call the function, we simply write the name of the function followed by an opening and closing parenthesis `()`. In this case, we call the `my_function()` by writing it as `my_function()`.

When we execute the above Python code, we get the following output:

`Hello World!`

## Using Arguments in Functions

Functions can also take arguments. Arguments are the values that are passed to the function when the function is called. These arguments can be used inside the function to perform some operation.

Here’s an example of a function with arguments:

```def multiply_numbers(x, y):
result = x * y
print("The result is:", result)

# Call the function
multiply_numbers(5, 10)```

In the above code snippet, we have defined a function `multiply_numbers(x, y)` that takes two arguments `x` and `y`. The function multiplies `x` and `y` and then prints the result.

When we call the function with `({x_value}, {y_value}).`, the values of `x` and `y` are passed to the function. In our case, we’re passing `5` and `10` as arguments. The function then multiplies these numbers and prints the result.

When we execute the above Python code, we get the following output:

`The result is: 50`

## Returning Values from Functions

So far, we have only seen functions that print some output. But what if you want to return a value from a function? This is where the `return` keyword comes in. The `return` keyword is used to return values from a function back to the caller.

Here’s an example:

```def add_numbers(x, y):
result = x + y
return result

# Call the function
print("The sum is:", sum)```

In the above code snippet, we have defined a function `add_numbers(x, y)` that takes two arguments `x` and `y`. The function adds `x` and `y` and then returns the result.

When we call the function with `({x_value}, {y_value}).`, the values of `x` and `y` are passed to the function. In our case, we’re passing `5` and `3` as arguments. The function returns the sum of these numbers, which we then store in a variable called `sum`.

We then print the value of the `sum` variable to see the result.

When we execute the above Python code, we get the following output:

`The sum is: 8`

## Using Default Arguments

Sometimes, you may want to define a function with default arguments. Default arguments are the values that are used by the function if no argument is passed in their place. Python allows you to set default arguments by specifying a default value for the argument in the function definition.

Here’s an example of a function with default arguments:

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

# Call the function
greet()
greet("Alice")```

In the above code snippet, we have defined a function called `greet(name="John")` with a default value of `"John"` for the `name` argument.

When we call the function without any arguments, the default value of `"John"` is used. When we call the function with the argument `"Alice"`, the value of `name` is set to `"Alice"`.

When we execute the above Python code, we get the following output:

```Hello John
Hello Alice```

## Using *args and **kwargs Parameters

Python also supports the use of variable length arguments. The `*args` and `**kwargs` parameters can be used to pass multiple arguments to a function without specifying the number of arguments beforehand.

The `*args` parameter is used to pass a variable number of non-keyword arguments to a function. Here’s an example:

```def my_sum(*numbers):
result = 0
for num in numbers:
result += num
return result

# Call the function
sum = my_sum(1, 2, 3, 4, 5)
print("The sum is:", sum)```

In the above code snippet, we have defined a function `my_sum(*numbers)` that takes a variable number of arguments using the `*args` parameter. The function then adds all the numbers together and returns the sum.

When we call the function with `(*args_values).`, the values of all the arguments are passed to the function. In our case, we’re passing `1, 2, 3, 4, 5` as arguments. The function then adds these numbers together and returns the sum, which we then store in a variable called `sum`.

We then print the value of the `sum` variable to see the result.

When we execute the above Python code, we get the following output:

`The sum is: 15`

The `**kwargs` parameter is used to pass a variable number of keyword arguments to a function. Here’s an example:

```def print_values(**values):
for key, value in values.items():
print(key, ":", value)

# Call the function
print_values(a=1, b=2, c=3)```

In the above code snippet, we have defined a function `print_values(**values)` that takes a variable number of keyword arguments using the `**kwargs` parameter. The function then iterates over the arguments and prints their key-value pairs.

When we call the function with `({arg_key_1}={arg_value_1}, {arg_key_2}={arg_value_2}, {arg_key_3}={arg_value_3}).` In our case, we’re passing `a=1, b=2, c=3` as keyword arguments. The function then iterates over these arguments and prints their key-value pairs.

When we execute the above Python code, we get the following output:

```a : 1
b : 2
c : 3```

## Closures and Nested Functions

In Python, functions can be nested inside other functions. These nested functions can be used to create closures. A closure is a function that has access to variables in its outer (enclosing) function’s scope, even when called outside the scope.

Here’s an example of a nested function that creates a closure:

```def outer_function(x):
def inner_function(y):
return x * y
return inner_function

# Create a closure
closure = outer_function(10)

# Call the closure
result = closure(5)

# Print the result
print("The result is:", result)```

In the above code snippet, we have defined a function called `outer_function(x)`, which takes a variable `x` as an argument. This function then defines another function called `inner_function(y)` that takes a variable `y` as an argument. The `inner_function(y)` function returns the product of `x` and `y`.

We then create a closure by calling the `outer_function(x)` function and passing the value `10` to it. This creates a new function that has access to the variable `x` in the outer function’s scope.

We then call the closure function with the value `5`, which multiplies `x` and `y` and returns the result. We then print the result to see the output.

When we execute the above Python code, we get the following output:

`The result is: 50`

## Conclusion

In this article, we have seen how to define functions using the `def` keyword in Python. We have looked at simple and complex functions, how to use arguments and return values, how to use default arguments, and how to use variable length arguments.

We have also looked at how to create closures using nested functions and how to use them to access variables in an outer function’s scope.

Hopefully, this article has given you a good understanding of how functions work in Python, allowing you to write better and more efficient code.