← Back to course

Modules and Imports: организация bigger programs

Modules and Imports: организация bigger programs

Возвращаемся к Python.

В предыдущем уроке ты изучил error handling.

Твои programs научились survive bad input, missing files и dramatic Python explosions.

Ты писал что-то такое:

try:
    age = int(input("Age: "))
except ValueError:
    print("Please enter a valid age.")

Очень хорошо.

Теперь твои programs safer.

Они не падают сразу, когда кто-то вводит:

banana

Excellent progress.

Но теперь у нас другая проблема.

Твои programs становятся bigger.

В начале одного file было достаточно.

Что-то такое:

main.py

Nice.

Simple.

Friendly.

Но потом ты добавил functions.

Потом lists.

Потом dictionaries.

Потом files.

Потом error handling.

И вдруг main.py становится huge.

Giant file.

Code lasagna.

Digital wardrobe, где всё внутри, но никто не знает, где socks.

Именно здесь помогают modules and imports.

Modules позволяют split code into multiple files.

Imports позволяют reuse code из одного file в другом file.

Вместо одного giant file можно organize project так:

main.py
helpers.py
tasks.py
calculator.py

Much cleaner.

Much more professional.

Much less “где прячется эта function?”

Что ты изучишь

В этом уроке ты изучишь:

К концу этого урока твой code будет more organized.

Ты сможешь split bigger programs into smaller files.

Ты будешь reuse functions instead of copying them.

Ты сделаешь projects easier to read.

И твой future self будет suffer less.

Noble goal.

Что такое module?

Module — это просто Python file.

Да.

Серьёзно.

Если у тебя есть file called:

helpers.py

Этот file — module.

Если у тебя есть file called:

calculator.py

Этот file — module.

Module может содержать:

Пока что мы будем использовать modules mostly to store functions.

Пример:

helpers.py
def greet_user(name):
    print(f"Hello, {name}!")

Потом another file может import and use this function.

Это главная idea.

Write code in one file.

Use it in another file.

Very useful.

Very clean.

Very Python.

Почему использовать modules?

Modules помогают organize code.

Вместо одного huge file можно split program into smaller parts.

Пример:

main.py        starts the program
helpers.py     general helper functions
tasks.py       task-related functions
contacts.py    contact-related functions

Это делает project easier to understand.

Giant file hard to read.

Project with clear files easier to navigate.

Думай о modules как о drawers.

One drawer for socks.

One drawer for shirts.

One drawer for mysterious cables, которые ты refuse to throw away.

Code needs drawers too.

Без organization всё становится chaos.

А chaos уже имеет достаточно работы.

Твой первый module

Создай folder:

python_modules_lesson

Inside it, create two files:

main.py
helpers.py

Folder должен выглядеть так:

python_modules_lesson/
├── helpers.py
└── main.py

В helpers.py напиши:

def greet_user(name):
    print(f"Hello, {name}!")

В main.py напиши:

import helpers

helpers.greet_user("Anna")

Запусти:

python main.py

или:

python3 main.py

Output:

Hello, Anna!

Congratulations.

Ты создал own module.

Very fancy.

Very organized.

Very “look, my code has separate rooms now”.

Как работает import

Эта строка imports module:

import helpers

Она говорит Python:

Load the helpers.py file so I can use what is inside it.

Потом можно call function так:

helpers.greet_user("Anna")

Почему helpers.?

Потому что function lives inside helpers module.

Full name:

helpers.greet_user

Это useful, потому что показывает where function comes from.

Clear code.

No guessing.

No detective work.

No “which file created this function?”

Python tells you.

Importing with from

Есть другой способ.

Вместо importing whole module можно import one function directly.

В main.py напиши:

from helpers import greet_user

greet_user("Anna")

Output:

Hello, Anna!

Теперь не нужно:

helpers.greet_user()

Можно call:

greet_user()

потому что ты imported the function directly.

Both styles work.

Style 1:

import helpers

helpers.greet_user("Anna")

Style 2:

from helpers import greet_user

greet_user("Anna")

Both are useful.

First style clearer about where function comes from.

Second style shorter.

Programming full of tradeoffs.

Like life.

But with more brackets.

Importing multiple functions

В helpers.py напиши:

def greet_user(name):
    print(f"Hello, {name}!")

def say_goodbye(name):
    print(f"Goodbye, {name}!")

В main.py напиши:

from helpers import greet_user, say_goodbye

greet_user("Anna")
say_goodbye("Anna")

Output:

Hello, Anna!
Goodbye, Anna!

Можно import multiple functions from same module.

Separate them with commas:

from helpers import greet_user, say_goodbye

Это useful, когда module имеет several helper functions.

Но не import too many things blindly.

Если import line becomes very long, maybe module is doing too much.

Or maybe project is growing.

Both possible.

Both deserve attention.

Importing everything

Можешь увидеть такое:

from helpers import *

Это imports everything from helpers.py.

It works.

Но beginners should be careful.

Why?

Потому что становится unclear where things come from.

Пример:

from helpers import *

greet_user("Anna")
say_goodbye("Anna")

This works.

Но когда project grows, it can become confusing.

Where did greet_user() come from?

Where did say_goodbye() come from?

Which module?

Which file?

Which drawer?

Mystery.

Usually better to be explicit:

from helpers import greet_user, say_goodbye

Clear is better than magical.

Magic nice in movies.

Less nice in debugging.

Module names

Module names should be simple.

Good:

helpers.py
tasks.py
contacts.py
calculator.py
file_utils.py

Bad:

my helper functions.py
task-manager.py
123tasks.py
import.py

Use lowercase letters and underscores.

Good:

file_utils.py
safe_input.py
task_manager.py

Avoid spaces.

Avoid hyphens.

Avoid names that are Python keywords.

Например, не называй file:

import.py

That is asking for trouble.

Python already uses import.

Do not confuse Python.

It is powerful, but it is not your therapist.

Module для calculator functions

Создай files:

main.py
calculator.py

В 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):
    return a / b

В main.py напиши:

import calculator

print(calculator.add(5, 3))
print(calculator.subtract(5, 3))
print(calculator.multiply(5, 3))
print(calculator.divide(10, 2))

Output:

8
2
15
5.0

Теперь calculator logic lives in:

calculator.py

А program starts in:

main.py

Это cleaner.

Main file does not need to contain every function.

It can use functions from other modules.

This is how projects grow.

Slowly.

Then suddenly.

Then you need folders.

But not yet.

One monster at a time.

Module для safe input

В предыдущем уроке мы написали safe input functions.

Перенесём их в module.

Создай:

safe_input.py

Напиши:

def get_integer(prompt):
    while True:
        try:
            value = int(input(prompt))
            return value
        except ValueError:
            print("Please enter a valid whole number.")

def get_float(prompt):
    while True:
        try:
            value = float(input(prompt))
            return value
        except ValueError:
            print("Please enter a valid number.")

Теперь в main.py напиши:

from safe_input import get_integer, get_float

price = get_float("Price: ")
quantity = get_integer("Quantity: ")

total = price * quantity

print(f"Total: {total:.2f}")

Это very nice.

Safe input logic reusable.

Any program can import it.

No need to copy and paste same functions again and again.

This is progress.

This is organization.

This is less suffering.

Excellent.

Importing standard library modules

Python already comes with many modules.

This is called standard library.

Examples:

math
random
datetime
os
pathlib
json

Можно import them too.

Example with math:

import math

print(math.sqrt(16))

Output:

4.0

Example with random:

import random

number = random.randint(1, 10)

print(number)

Это prints random number between 1 and 10.

Python gives you many tools for free.

You do not have to write everything yourself.

Very nice.

Very generous.

Very “please use the toolbox before building a hammer from scratch”.

Example: random choice

Создай файл:

random_example.py

Напиши:

import random

names = ["Anna", "Marco", "Sofia", "Luca"]

chosen_name = random.choice(names)

print(f"Chosen name: {chosen_name}")

Output may be:

Chosen name: Sofia

Or:

Chosen name: Marco

Because it is random.

random module имеет useful functions like:

random.randint(1, 10)
random.choice(names)

Это good for:

games
random exercises
test data
small experiments

Randomness useful.

Also dangerous.

Especially when naming files.

Do not name production files randomly.

Future you will cry.

Example: math module

Создай:

math_example.py

Напиши:

import math

radius = 5

area = math.pi * radius ** 2

print(f"Area: {area:.2f}")

Output:

Area: 78.54

math module gives us:

math.pi
math.sqrt()
math.floor()
math.ceil()

Very useful for calculations.

Не нужно define pi yourself.

Не пиши:

pi = 3.14

unless you really want a tiny approximation wearing cheap shoes.

Use:

math.pi

Much better.

Code that runs when imported

Important.

Very important.

Создай helpers.py:

def greet_user(name):
    print(f"Hello, {name}!")

print("This is helpers.py")

Создай main.py:

import helpers

helpers.greet_user("Anna")

Run main.py.

Output:

This is helpers.py
Hello, Anna!

Почему Python printed:

This is helpers.py

Потому что when you import a module, Python runs top-level code in that file.

That means code outside functions can run during import.

This can surprise beginners.

Very much.

So be careful.

Module should usually contain functions and constants.

Not random program execution.

Otherwise importing module becomes spicy.

And not in a good way.

Pattern name == "main"

Sometimes you want code to run only when file is executed directly.

Not when it is imported.

Python has common pattern:

if __name__ == "__main__":
    code_here

Example:

def greet_user(name):
    print(f"Hello, {name}!")

if __name__ == "__main__":
    greet_user("Test User")

Now:

This is very useful.

It lets you test module without causing surprises when importing it.

At first, this line looks strange:

if __name__ == "__main__":

Do not panic.

It basically means:

Run this code only if this file is the main file being executed.

Weird-looking.

Very useful.

Very Python.

Testing a module safely

Создай helpers.py:

def greet_user(name):
    return f"Hello, {name}!"

if __name__ == "__main__":
    print(greet_user("Anna"))

Если run:

python helpers.py

Output:

Hello, Anna!

Теперь создай main.py:

from helpers import greet_user

message = greet_user("Marco")

print(message)

Run:

python main.py

Output:

Hello, Marco!

Notice that test code inside:

if __name__ == "__main__":

did not run when imported.

Perfect.

Clean.

Professional.

Less surprise.

And in programming, fewer surprises are usually good.

Unless it is your birthday.

But even then, not in production.

Splitting a program into files

Организуем small project.

Создай структуру:

task_project/
├── main.py
├── tasks.py
└── safe_input.py

В safe_input.py напиши:

def get_integer(prompt):
    while True:
        try:
            value = int(input(prompt))
            return value
        except ValueError:
            print("Please enter a valid whole number.")

В tasks.py напиши:

FILE_NAME = "tasks.txt"

def load_tasks():
    tasks = []

    try:
        with open(FILE_NAME, "r") as file:
            for line in file:
                tasks.append(line.strip())
    except FileNotFoundError:
        pass

    return tasks

def save_tasks(tasks):
    with open(FILE_NAME, "w") as file:
        for task in tasks:
            file.write(task + "\n")

def add_task(tasks):
    task = input("Task: ")
    tasks.append(task)
    save_tasks(tasks)
    print("Task saved.")

def show_tasks(tasks):
    if len(tasks) == 0:
        print("No tasks yet.")
    else:
        print("Tasks:")

        for index, task in enumerate(tasks, start=1):
            print(f"{index}. {task}")

def remove_task(tasks, task_number):
    index = task_number - 1

    if index < 0 or index >= len(tasks):
        print("Invalid task number.")
        return

    removed_task = tasks.pop(index)
    save_tasks(tasks)

    print(f"Removed: {removed_task}")

В main.py напиши:

from safe_input import get_integer
from tasks import load_tasks, add_task, show_tasks, remove_task

def show_menu():
    print("----- Task Manager -----")
    print("1. Add task")
    print("2. Show tasks")
    print("3. Remove task")
    print("q. Quit")

tasks = load_tasks()

while True:
    show_menu()

    choice = input("Choose an option: ").lower()

    if choice == "1":
        add_task(tasks)
    elif choice == "2":
        show_tasks(tasks)
    elif choice == "3":
        if len(tasks) == 0:
            print("No tasks to remove.")
        else:
            show_tasks(tasks)
            task_number = get_integer("Task number to remove: ")
            remove_task(tasks, task_number)
    elif choice == "q":
        print("Goodbye.")
        break
    else:
        print("Unknown option.")

This project is much better organized.

main.py controls program flow.

tasks.py contains task logic.

safe_input.py contains safe input logic.

This is clean.

This is readable.

This is real project structure.

Small project.

But real structure.

Very good.

Почему эта structure better

Посмотри на files:

main.py
tasks.py
safe_input.py

Each file has a job.

main.py:

Runs the program.
Shows the menu.
Handles user choices.

tasks.py:

Loads tasks.
Saves tasks.
Adds tasks.
Shows tasks.
Removes tasks.

safe_input.py:

Gets safe integer input.

Это называется separation of responsibilities.

Fancy phrase.

Simple idea:

Do not put everything everywhere.

Good organization makes code easier to maintain.

Когда нужна task logic, go to tasks.py.

Когда нужна input logic, go to safe_input.py.

Когда нужен program flow, go to main.py.

No treasure hunt.

No code archaeology.

Much better.

Типичная ошибка: ModuleNotFoundError

Можешь увидеть:

ModuleNotFoundError

Пример:

import helpers

Но Python says:

ModuleNotFoundError: No module named 'helpers'

Possible reasons:

helpers.py does not exist
helpers.py is in another folder
you misspelled the file name
you are running Python from the wrong place

For beginners, keep files in the same folder.

Example:

project/
├── main.py
└── helpers.py

Then run from that folder:

python main.py

Simple.

Less drama.

Python imports powerful.

But paths can become spicy.

Start simple.

Типичная ошибка: wrong file name

Если твой file called:

helper.py

А ты пишешь:

import helpers

Python will not find it.

Names must match.

File:

helpers.py

Import:

import helpers

No .py in import.

Correct:

import helpers

Wrong:

import helpers.py

Python imports module names, not file names with extensions.

Tiny detail.

Big confusion.

Very normal.

Типичная ошибка: circular imports

Circular imports happen when two files import each other.

Example:

a.py imports b.py
b.py imports a.py

This can cause confusing errors.

Beginners should avoid this.

Simple rule:

main.py can import other modules.
Helper modules should usually not import main.py.

Good:

main.py imports tasks.py
main.py imports safe_input.py

Risky:

tasks.py imports main.py
main.py imports tasks.py

That creates a loop.

Snake eating its own tail.

Interesting symbol.

Annoying bug.

Avoid.

Типичная ошибка: putting program logic in imported modules

Bad helpers.py:

def greet_user(name):
    print(f"Hello, {name}!")

name = input("Name: ")
greet_user(name)

If you import this module, it asks for input immediately.

Surprise.

Not good.

Better:

def greet_user(name):
    print(f"Hello, {name}!")

if __name__ == "__main__":
    name = input("Name: ")
    greet_user(name)

Now input only happens when you run helpers.py directly.

Not when you import it.

This is much safer.

Remember:

Modules should usually define reusable things.
main.py should usually run the program.

Very good rule.

Типичная ошибка: importing too much

This can become messy:

from helpers import *
from tasks import *
from calculator import *

Now your namespace is full of imported names.

You may not know where anything came from.

Better:

import helpers
import tasks

или:

from helpers import greet_user
from tasks import load_tasks, save_tasks

Be clear.

Explicit imports make code easier to understand.

Future you likes explicit imports.

Future you is tired and has no patience for mystery.

Respect future you.

Практика

Создай project:

calculator_project/
├── main.py
└── calculator.py

В calculator.py create functions:

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):
    return a / b

В main.py, import the functions и ask user for two numbers.

Example solution:

from calculator import add, subtract, multiply, divide

first_number = float(input("First number: "))
second_number = float(input("Second number: "))

print(f"Add: {add(first_number, second_number)}")
print(f"Subtract: {subtract(first_number, second_number)}")
print(f"Multiply: {multiply(first_number, second_number)}")

if second_number == 0:
    print("Cannot divide by zero.")
else:
    print(f"Divide: {divide(first_number, second_number)}")

This practice teaches:

Very useful.

Very clean.

Very beginner-friendly.

Мини-задание

Создай project:

notes_project/
├── main.py
└── notes.py

В notes.py, create functions:

add_note()
show_notes()

Use file called:

notes.txt

Example notes.py:

FILE_NAME = "notes.txt"

def add_note():
    note = input("Note: ")

    with open(FILE_NAME, "a") as file:
        file.write(note + "\n")

    print("Note saved.")

def show_notes():
    try:
        with open(FILE_NAME, "r") as file:
            print("Notes:")

            has_notes = False

            for line in file:
                print(f"- {line.strip()}")
                has_notes = True

            if not has_notes:
                print("No notes yet.")
    except FileNotFoundError:
        print("No notes yet.")

Example main.py:

from notes import add_note, show_notes

def show_menu():
    print("----- Notes App -----")
    print("1. Add note")
    print("2. Show notes")
    print("q. Quit")

while True:
    show_menu()

    choice = input("Choose an option: ").lower()

    if choice == "1":
        add_note()
    elif choice == "2":
        show_notes()
    elif choice == "q":
        print("Goodbye.")
        break
    else:
        print("Unknown option.")

Это very good beginner project.

It uses:

Small app.

Good structure.

Very useful.

Very real.

Extra challenge: split contact book

Создай:

contact_project/
├── main.py
├── contacts.py
└── safe_input.py

contacts.py should contain:

load_contacts()
save_contacts()
add_contact()
show_contacts()

main.py should contain:

menu
main loop
user choices

This is bigger challenge.

You already know the pieces.

Now goal is organization.

Do not write everything in one file.

Make each file responsible for one part.

This is how bigger projects stay understandable.

Or at least less terrifying.

Less terrifying is good.

Checklist для начинающих

Когда imports не работают, проверь:

Are the files in the same folder?
Did I spell the module name correctly?
Did I write the import without .py?
Am I running Python from the correct folder?
Did I create circular imports?
Did I put too much running code in the imported module?
Should this code be inside if __name__ == "__main__"?
Am I importing too much with *?
Does each file have a clear job?

Import problems common.

Very common.

Do not panic.

Usually problem is:

wrong file name
wrong folder
wrong import style
code running during import

Fix calmly.

Computers are literal.

They do exactly what you say.

Not what you meant.

Annoying.

But fair.

Итог

Сегодня ты изучил:

Это huge step.

Твои projects теперь могут grow without becoming one giant file.

Ты можешь reuse code.

Ты можешь organize functions.

Ты можешь separate program flow from helper logic.

This is how real projects begin.

Not with one magical file that does everything.

But with small files that work together.

Clean structure.

Reusable code.

Less chaos.

Very Python.

Very professional.

Следующий урок

В следующем уроке мы изучим JSON.

JSON — очень common data format.

Он очень похож на Python dictionaries and lists.

Ты научишься save structured data like this:

contact = {
    "name": "Anna",
    "email": "anna@example.com",
    "phone": "123456"
}

into a file.

And then load it back later.

Это очень important for real applications.

Text files nice.

But JSON better for structured data.

It is used in APIs, configuration files, web apps, and many real projects.

Very useful.

Very practical.

Very next level.