← 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.