# Packages, __init__.py and if __name__ == "__main__"<no value>

## What will we learn?

- **Package** — a folder that contains modules.
- The file **`__init__.py`** and its role.
- Importing from inside a Package.
- The special variable **`__name__`**, and the pattern **`if __name__ == "__main__":`**.

## Why do we need this?

When there are 3 modules, they can sit in the same folder. When there are 30, you need **folders**: everything related to users in one folder, everything related to payments in another. That is how all real projects are built, and also all the libraries you will install (FastAPI is a huge Package with dozens of sub-Packages).

And `if __name__ == "__main__":` solves the problem from the previous lesson: test code that runs every time someone imports the file.

## Explanation from the basics

### Package = a folder of modules

A **Package** is a folder that contains modules (`.py` files), and usually also a file named **`__init__.py`**.

```text
store/                    ← project folder
├── main.py               ← the program you run
└── inventory/            ← a PACKAGE
    ├── __init__.py       ← marks this folder as a package
    ├── products.py       ← module
    └── stock.py          ← module
```

### `__init__.py`

- **Marks** the folder as a Package, explicitly and clearly.
- **Runs automatically** the first time something is imported from the Package.
- Usually **empty**. You can put convenient imports in it, so that you can write `from inventory import add_product` instead of `from inventory.products import add_product`.

(In modern Python you can also import from a folder without `__init__.py`, but the accepted convention is to include it, so that it is clear this is a package and not just a folder.)

### Importing from a Package

The dot separates a **folder** from a module, exactly like `/` in a path:

```python
import inventory.products                 # inventory/products.py
from inventory import products            # same module, shorter use
from inventory.products import add_product   # one function
```

### `__name__` — "who am I?"

Every module has a built-in variable named **`__name__`**. Python sets its value according to **how the file was started**:

| How the file was started | The value of `__name__` |
|---|---|
| **Run directly**: `python prices.py` | `"__main__"` |
| **Imported** from another file: `import prices` | `"prices"` (the module's name) |

And therefore:

```python
if __name__ == "__main__":
    # runs ONLY when this file is run directly, NOT when it is imported
```

{{< box "analogy" "Analogy: a chef who is also a supplier" >}}
A chef cooks in their own restaurant (running directly), and at the same time sells sauces to shops (importing). When they are in the restaurant, they also serve customers: that is the code inside `if __name__ == "__main__"`. When a shop buys a sauce, it gets **only the sauce** (the functions), and not a whole meal forced on it.
{{< /box >}}

## Syntax

```text
project/
├── main.py
└── package_name/
    ├── __init__.py
    └── module_name.py
```

```python
# main.py
from package_name.module_name import some_function
from package_name import module_name

# any module that can also be run directly:
def main():
    ...          # what happens when the file is run as a program

if __name__ == "__main__":
    main()
```

The pattern of a `main()` function + the condition at the end of the file is **the standard** in every Python file meant to be run.

## First code example

Let's see `__name__` in action. `week-2/name_demo/greetings.py`:

```python
def hello(name):
    return "Hello, " + name + "!"

print("greetings.py: __name__ is", __name__)

if __name__ == "__main__":
    print("Running greetings.py directly - quick self test:")
    print(hello("Tester"))
```

`week-2/name_demo/app.py`:

```python
import greetings

print("app.py: __name__ is", __name__)
print(greetings.hello("Dana"))
```

**Run 1:** `python greetings.py`

```text
greetings.py: __name__ is __main__
Running greetings.py directly - quick self test:
Hello, Tester!
```

**Run 2:** `python app.py`

```text
greetings.py: __name__ is greetings
app.py: __name__ is __main__
Hello, Dana!
```

## Breaking down the code line by line

| | Run 1 (`python greetings.py`) | Run 2 (`python app.py`) |
|---|---|---|
| `__name__` of `greetings.py` | `"__main__"` (it is the file that was run) | `"greetings"` (it was imported) |
| The first `print` in greetings | Runs | **Runs** (code at the top level always runs on import) |
| The `if __name__ == "__main__"` block | **Runs** (self test) | **Does not run** |
| `__name__` of `app.py` | — | `"__main__"` |

**The conclusion:** everything that should run **only when the file is run directly** (tests, demos, starting the program) goes inside the condition. Definitions of functions and constants stay outside, so that they can be imported.

## Another example

**A project with a real Package.** The structure:

```text
week-2/store/
├── main.py
└── inventory/
    ├── __init__.py
    ├── products.py
    └── stock.py
```

`inventory/__init__.py`:

```python
from inventory.products import create_product
from inventory.stock import add_stock, remove_stock
```

`inventory/products.py`:

```python
def create_product(name, price):
    if price < 0:
        raise ValueError("price cannot be negative, got " + str(price))
    return {"name": name, "price": price, "quantity": 0}

if __name__ == "__main__":
    print(create_product("Test item", 10))
```

`inventory/stock.py`:

```python
def add_stock(product, amount):
    product["quantity"] = product["quantity"] + amount

def remove_stock(product, amount):
    if amount > product["quantity"]:
        raise ValueError("not enough " + product["name"] + " in stock")
    product["quantity"] = product["quantity"] - amount
```

`main.py`:

```python
from inventory import create_product, add_stock, remove_stock

def main():
    laptop = create_product("Laptop", 3500)
    add_stock(laptop, 10)
    remove_stock(laptop, 3)
    print(laptop)

    try:
        remove_stock(laptop, 50)
    except ValueError as error:
        print("Error:", error)

if __name__ == "__main__":
    main()
```

**Run** (from `week-2/store`): `python main.py`

```text
{'name': 'Laptop', 'price': 3500, 'quantity': 7}
Error: not enough Laptop in stock
```

**Breakdown:**

- `__init__.py` **gathers** the important functions of the Package. Thanks to it, `main.py` writes `from inventory import create_product`, and does not need to know which internal file exactly it sits in. From outside, the Package looks like "one unit".
- `add_stock(laptop, 10)` **changes the dict itself**, because a dict is Mutable (the data structures and functions topic!). The function does not need to return anything.
- `products.py` includes a self test inside `if __name__ == "__main__"`. You can run it alone to test it, and it does not "make a mess" when it is imported.
- `main.py` is wrapped in `main()` + the condition. If someone imports it in the future, nothing will run by itself.

{{< box "tip" "How do you run a file that is inside a Package?" >}}
If you try `python inventory/products.py`, you sometimes get a `ModuleNotFoundError`, because Python looks for modules from the folder **of the file that was run** (`inventory/`), and not from the project folder. The right way to run a module inside a Package is from the project folder, with the `-m` (module) flag and **dots instead of slashes**: `python -m inventory.products`.
{{< /box >}}

## Common mistake

**Mistake 1: writing `"main"` instead of `"__main__"`.**

```python
if __name__ == "main":
    main()
```

Nothing runs, and there is no error! The value is `"__main__"`, with **two underscores on each side**. A silent Logical Error.

**Mistake 2: a Circular Import.**

`a.py` imports `b`, and `b.py` imports `a`:

```text
ImportError: cannot import name 'x' from partially initialized module 'a' (most likely due to a circular import)
```

Two modules that depend on each other are a sign of a bad split. Move the shared part into a third module, which both of them import from.

**Mistake 3: putting all the logic inside the `if` block.**

```python
if __name__ == "__main__":
    def calculate(x):
        return x * 2
    print(calculate(5))
```

Now `calculate` cannot be imported from another file, because it is defined only when the file is run directly. The functions go **outside**, and only **starting the program** goes inside.

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Practice

The exercises use only what was taught in this lesson and the lessons before it. Try on your own first, and only then open the solution.

### Exercise 1: The structure of a Package

Draw the folder structure of a project `store` with a file `main.py` and a Package named `inventory`, which has two modules: `products.py` and `stock.py`. Which file must be inside `inventory`, and why?

{{< solution >}}
```text
store/
├── main.py
└── inventory/
    ├── __init__.py
    ├── products.py
    └── stock.py
```

`__init__.py` marks the folder as a **Package** — a folder of modules that you can import from. It can be empty.
{{< /solution >}}

### Exercise 2: Importing from a Package

In `inventory/products.py` there is a function `create_product(name, price)` that returns a dictionary. Write in `main.py` three ways to import it and use it.

{{< solution >}}
```py
import inventory.products
laptop = inventory.products.create_product("Laptop", 3500)

from inventory import products
mouse = products.create_product("Mouse", 80)

from inventory.products import create_product
desk = create_product("Desk", 900)
```

The dot in the path (`inventory.products`) is like `/` in folders: the module `products` inside the Package `inventory`.
{{< /solution >}}

### Exercise 3: What is __name__?

In the file `greetings.py`:

```text
def hello(name):
    return "Hello, " + name + "!"

print("__name__ is", __name__)
```

What will be printed in each case?

1. You run `python greetings.py`.
2. You run `main.py`, which contains `import greetings`.

{{< solution >}}
1. When run directly: `__name__ is __main__`.
2. When imported: `__name__ is greetings` — the module's name.

Python sets `__name__` according to **how** the file was started. That is the basis of the main guard.
{{< /solution >}}

### Exercise 4: The main guard

Add to `greetings.py` (from the previous exercise, with the function `hello`) a self test that runs **only** when the file is run directly, and not when it is imported. The test prints `quick self test:` and then the result of `hello("Tester")`.

Delete the line `print("__name__ is", __name__)` from the previous exercise.

**Expected output (python greetings.py):**

```text
quick self test:
Hello, Tester!
```

{{< solution >}}
```python
def hello(name):
    return "Hello, " + name + "!"


if __name__ == "__main__":
    print("quick self test:")
    print(hello("Tester"))
```

```text
quick self test:
Hello, Tester!
```

When another file does `import greetings`, the condition is `False` — the test does not run, and only the function is available.
{{< /solution >}}

### Exercise 5: The mathtools package

Build a Package named `mathtools` with two modules: `basic.py` with `add(a, b)`, and `stats.py` with `mean(numbers)` and `maximum(numbers)`. In `main.py`, use all three.

```text
add(2, 3)
mean([10, 20, 30])
maximum([10, 20, 30])
```

**Expected output:**

```text
add: 5
mean: 20.0
maximum: 30
```

{{< solution >}}
```text
math_project/
├── main.py
└── mathtools/
    ├── __init__.py
    ├── basic.py
    └── stats.py
```

**mathtools/basic.py**

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

**mathtools/stats.py**

```py
def mean(numbers):
    return sum(numbers) / len(numbers)


def maximum(numbers):
    return max(numbers)
```

**main.py**

```py
from mathtools.basic import add
from mathtools import stats

print("add:", add(2, 3))
print("mean:", stats.mean([10, 20, 30]))
print("maximum:", stats.maximum([10, 20, 30]))
```
{{< /solution >}}

<!-- exercises:end -->

## Summary

- **Package** = a folder of modules, with an **`__init__.py`** that runs on the first import and can "expose" convenient names.
- Importing from a Package: `from package.module import name`. The dot = going into a folder.
- **`__name__`** is `"__main__"` when the file was run directly, and the module's name when it was imported.
- **`if __name__ == "__main__": main()`** — start the program only when run directly. Define functions outside.
- A module inside a Package is run from the project folder with `python -m package.module`.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

## Official documentation

- [Python Tutorial — Packages](https://docs.python.org/3/tutorial/modules.html#packages)
- [__main__ — Top-level code environment](https://docs.python.org/3/library/__main__.html#name-main)

<!-- docs:end -->
