# Functions in Python

# 🔹 1. What is a Function in Python?

A **function** is a reusable block of code that performs a specific task.

Instead of writing the same code again and again, you **define once, use many times**.

### Why functions?

* Reduce code repetition
    
* Improve readability
    
* Make code modular & testable
    
* Easier debugging
    

---

## 🔹 2. Basic Function (No Parameters)

### Syntax

```python
def function_name():
    statements
```

### Example

```python
def greet():
    print("Hello, World!")

greet()
```

📌 Output:

```plaintext
Hello, World!
```

---

### 📝 Task 1

Create a function `welcome()` that prints:

```plaintext
Welcome to Python Programming
```

---

# 🔹 3. Function with Parameters (Arguments)

Parameters allow us to **pass data into a function**.

### Example

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

greet("Aarav")
greet("Python")
```

📌 Output:

```plaintext
Hello Aarav
Hello Python
```

---

### 📝 Task 2

Write a function `square(n)` that prints the square of a number.

---

# 🔹 4. Function with Return Value

Instead of printing, functions can **return values**.

### Example

```python
def add(a, b):
    return a + b

result = add(5, 3)
print(result)
```

📌 Output:

```plaintext
8
```

👉 `return` sends data back to the caller.

---

### 📝 Task 3

Create a function `is_even(n)` that returns `True` if number is even, else `False`.

---

# 🔹 5. Types of Arguments in Python

Python supports **multiple ways to pass arguments**:

---

## ✅ 5.1 Positional Arguments

Order matters.

```python
def student(name, age):
    print(name, age)

student("Ram", 20)
```

❌ Wrong order:

```python
student(20, "Ram")  # logical error
```

---

### 📝 Task 4

Create a function `multiply(a, b, c)` and call it using positional arguments.

---

## ✅ 5.2 Keyword Arguments

You specify parameter names → order doesn’t matter.

```python
def student(name, age):
    print(name, age)

student(age=21, name="Sita")
```

---

### 📝 Task 5

Call `multiply()` using keyword arguments.

---

## ✅ 5.3 Default Arguments

Provide default values.

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

greet()
greet("Aarav")
```

---

### 📝 Task 6

Create a function `power(base, exp=2)` that returns base raised to power.

---

# 🔹 6. \*args (Variable Length Arguments)

Sometimes you **don’t know how many arguments** will be passed.

👉 `*args` stores values as a **tuple**.

---

### Example

```python
def total(*args):
    print(args)
    print(sum(args))

total(1, 2, 3)
total(5, 10, 15, 20)
```

📌 Output:

```plaintext
(1, 2, 3)
6
(5, 10, 15, 20)
50
```

---

### Key Points

* `args` is just a name (convention)
    
* `*` is important
    
* Access like a tuple
    

---

### 📝 Task 7

Write a function `average(*numbers)` that returns the average.

---

# 🔹 7. \*\*kwargs (Keyword Variable Length Arguments)

Used when passing **named arguments** dynamically.

👉 `**kwargs` stores data as a **dictionary**.

---

### Example

```python
def student_details(**kwargs):
    print(kwargs)

student_details(name="Aarav", age=21, course="CS")
```

📌 Output:

```plaintext
{'name': 'Aarav', 'age': 21, 'course': 'CS'}
```

---

### Accessing values

```python
def student_details(**kwargs):
    for key, value in kwargs.items():
        print(key, ":", value)
```

---

### 📝 Task 8

Create a function `profile(**info)` that prints all key-value pairs.

---

# 🔹 8. Combining Arguments (Advanced)

### Correct Order

```plaintext
1. Positional
2. *args
3. Default
4. **kwargs
```

---

### Example

```python
def demo(a, b, *args, x=10, **kwargs):
    print(a, b)
    print(args)
    print(x)
    print(kwargs)

demo(1, 2, 3, 4, x=50, name="Ram", age=20)
```

---

### 📝 Task 9

Create a function `bill(customer, *items, discount=0, **details)`  
Print customer, items, discount, and details.

---

# 🔹 9. Functions as Objects (Advanced Concept)

Functions can be:

* Stored in variables
    
* Passed as arguments
    
* Returned from functions
    

---

### Example

```python
def add(a, b):
    return a + b

operation = add
print(operation(3, 4))
```

---

### 📝 Task 10

Write a function `apply(func, a, b)` that applies any function to two numbers.

---

# 🔹 10. Lambda Functions (Short Functions)

One-line anonymous functions.

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

---

### With args

```python
add = lambda *args: sum(args)
print(add(1, 2, 3))
```

---

### 📝 Task 11

Create a lambda to check if a number is divisible by 5.

---

# 🔹 11. Real-World Example (Mini Project)

### Student Marks Calculator

```python
def calculate_marks(name, *marks, **extra):
    total = sum(marks)
    avg = total / len(marks)
    
    print("Name:", name)
    print("Total:", total)
    print("Average:", avg)
    
    if "grade" in extra:
        print("Grade:", extra["grade"])

calculate_marks(
    "Aarav",
    80, 75, 90,
    grade="A",
    remark="Excellent"
)
```

---

# ✅ Final Practice Assignment (Exam-Level)

1. Write a function using **default arguments**
    
2. Write a function using \**only args*
    
3. Write a function using \*\*only **kwargs**
    
4. Combine all argument types in one function
    
5. Explain difference between `print` and `return`
    
6. Write a real-life example of `*args` and `**kwargs`
    

---
