# Mastering Functional Programming in Python

## Index

1. Introduction to Functional Programming
    
2. Pure Functions
    
3. The `map()` Function
    
4. The `filter()` Function
    
5. The `zip()` Function
    
6. The `reduce()` Function
    
7. Lambda Expressions
    
8. List Comprehensions
    
9. Set and Dictionary Comprehensions
    
10. Decorators
    
11. Higher-Order Functions vs. First-Class Functions
    

---

## 1\. Introduction to Functional Programming

Functional Programming (FP) is a programming paradigm that treats computation as the evaluation of mathematical functions. It emphasizes immutability, first-class functions, and pure functions, making code easier to understand and debug. Python supports functional programming features alongside its object-oriented and procedural programming capabilities.

## 2\. Pure Functions

A **pure function** is a function that:

1. Always produces the same output for the same input.
    
2. Has no side effects (it does not modify external states or variables).
    

Example:

```python
def add(a, b):
    return a + b  # No side effects, always returns the same output for the same input
```

## 3\. The `map()` Function

The `map()` function applies a given function to all items in an iterable and returns an iterator.

Example:

```python
def square(num):
    return num * num

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

## 4\. The `filter()` Function

The `filter()` function filters elements from an iterable based on a condition provided by a function.

Example:

```python
def is_even(num):
    return num % 2 == 0

even_numbers = list(filter(is_even, numbers))
print(even_numbers)  # Output: [2, 4]
```

## 5\. The `zip()` Function

The `zip()` function combines multiple iterables element-wise into tuples.

Example:

```python
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
combined = list(zip(names, ages))
print(combined)  # Output: [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
```

## 6\. The `reduce()` Function

The `reduce()` function (from `functools` module) applies a function cumulatively to elements of an iterable.

Example:

```python
from functools import reduce

def multiply(x, y):
    return x * y

numbers = [1, 2, 3, 4, 5]
result = reduce(multiply, numbers)
print(result)  # Output: 120
```

## 7\. Lambda Expressions

A **lambda expression** is an anonymous function defined using the `lambda` keyword.

Example:

```python
square = lambda x: x * x
print(square(5))  # Output: 25
```

Using `lambda` with `map()`:

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

## 8\. List Comprehensions

List comprehensions provide a concise way to create lists.

Example:

```python
squared_numbers = [x ** 2 for x in range(1, 6)]
print(squared_numbers)  # Output: [1, 4, 9, 16, 25]
```

## 9\. Set and Dictionary Comprehensions

Set Comprehension:

```python
unique_numbers = {x for x in [1, 2, 2, 3, 4, 4, 5]}
print(unique_numbers)  # Output: {1, 2, 3, 4, 5}
```

Dictionary Comprehension:

```python
squared_dict = {x: x**2 for x in range(1, 6)}
print(squared_dict)  # Output: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
```

## 10\. Decorators

A **decorator** is a function that takes another function and extends its behavior without modifying it.

Example:

```python
def decorator_function(original_function):
    def wrapper_function():
        print("Wrapper executed before", original_function.__name__)
        return original_function()
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()
```

Output:

```python
Wrapper executed before say_hello
Hello!
```

## 11\. Higher-Order Functions vs. First-Class Functions

* **First-Class Functions:** Functions that can be assigned to variables, passed as arguments, and returned from other functions.
    
* **Higher-Order Functions:** Functions that take other functions as arguments or return functions as results.
    

Example of **First-Class Function**:

```python
def greet(name):
    return f"Hello, {name}!"

message = greet  # Assigning function to variable
print(message("Alice"))  # Output: Hello, Alice!
```

Example of **Higher-Order Function**:

```python
def apply_function(func, value):
    return func(value)

double = lambda x: x * 2
print(apply_function(double, 5))  # Output: 10
```

---
