> For the complete documentation index, see [llms.txt](https://py.d19.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://py.d19.in/chapter-7-modules-and-packages.md).

# Chapter 7: Modules and Packages

In Python, modules and packages help organize code, promote reusability, and manage complexity in large projects. A module is a file containing Python code, and a package is a collection of modules organized in directories.

#### Modules

A module is simply a Python file with a `.py` extension. Modules can contain functions, classes, and variables that can be reused in other scripts.

**Creating and Importing a Module**

1. **Create a Module**: Save the following as `mymodule.py`:

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

   pi = 3.14159
   ```
2. **Import the Module**: Use the `import` keyword to use the module in another script.

   ```python
   import mymodule

   print(mymodule.greet("Alice"))  # Output: Hello, Alice!
   print(mymodule.pi)  # Output: 3.14159
   ```
3. **Import Specific Items**: Use the `from` keyword to import specific elements.

   ```python
   from mymodule import greet

   print(greet("Bob"))  # Output: Hello, Bob!
   ```
4. **Alias Modules**: Use the `as` keyword to give a module an alias.

   ```python
   import mymodule as mm

   print(mm.pi)  # Output: 3.14159
   ```

#### Built-in Modules

Python comes with a rich standard library of built-in modules. Some commonly used modules include:

| **Module** | **Description**                        |
| ---------- | -------------------------------------- |
| `math`     | Mathematical functions and constants.  |
| `os`       | Interacting with the operating system. |
| `sys`      | Accessing system-specific parameters.  |
| `random`   | Generating random numbers.             |
| `datetime` | Working with dates and times.          |

**Example:**

```python
import math

print(math.sqrt(16))  # Output: 4.0
print(math.pi)  # Output: 3.141592653589793
```

#### Packages

A package is a collection of related modules grouped into a directory. It contains an `__init__.py` file, which can be empty or include package initialization code.

**Creating a Package**

1. Create a directory named `mypackage`.
2. Add an empty `__init__.py` file to the directory.
3. Add modules to the package:
   * `module1.py`:

     ```python
     def add(a, b):
         return a + b
     ```
   * `module2.py`:

     ```python
     def subtract(a, b):
         return a - b
     ```
4. Import and use the package:

   ```python
   from mypackage import module1, module2

   print(module1.add(5, 3))  # Output: 8
   print(module2.subtract(5, 3))  # Output: 2
   ```

**Nested Packages**

Packages can contain sub-packages for better organization.

```plaintext
mypackage/
    __init__.py
    subpackage/
        __init__.py
        module.py
```

#### The `__name__` Variable

Every Python module has a special variable `__name__`. When a module is run directly, `__name__` is set to `"__main__"`. This is useful for writing code that behaves differently when a module is imported versus executed directly.

**Example:**

```python
# mymodule.py
if __name__ == "__main__":
    print("This script is being run directly.")
else:
    print("This script is being imported.")
```

#### Exercises

**Exercise 1:**

Create a module `calculator.py` with functions `add`, `subtract`, `multiply`, and `divide`. Use it in another script.

**Solution:**

```python
# calculator.py
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

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

def divide(a, b):
    if b != 0:
        return a / b
    return "Cannot divide by zero"

# main.py
import calculator

print(calculator.add(10, 5))  # Output: 15
print(calculator.divide(10, 0))  # Output: Cannot divide by zero
```

**Exercise 2:**

Create a package `shapes` with modules `circle` and `rectangle`. Implement functions to calculate the area of each shape.

**Solution:**

```python
# shapes/circle.py
def area(radius):
    return 3.14 * radius ** 2

# shapes/rectangle.py
def area(length, width):
    return length * width

# main.py
from shapes import circle, rectangle

print(circle.area(5))  # Output: 78.5
print(rectangle.area(4, 6))  # Output: 24
```

#### Best Practices

1. Use meaningful names for modules and packages.
2. Avoid circular imports (modules importing each other).
3. Keep modules small and focused on a specific task.
4. Use packages to organize related functionality.

In the next chapter, we will explore file handling, including reading, writing, and managing files in Python.
