← Back to course

Error Handling: помогаем programs выжить

Error Handling: помогаем programs выжить

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

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

Твои programs научились save data и read it later.

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

with open("tasks.txt", "r") as file:
    content = file.read()

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

Теперь твои programs могут remember things.

Tasks.

Notes.

Contacts.

Small pieces of digital memory.

Beautiful.

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

Programs crash.

Много.

Иногда потому, что file missing.

Иногда потому, что user enters text instead of a number.

Иногда потому, что ты divide by zero.

Иногда потому, что code имел tiny mistake, который прятался как ninja за bracket.

Пример:

age = int(input("Age: "))

Если user напишет:

banana

Python скажет:

ValueError

И program crashes.

Очень dramatic.

Очень Python.

Очень normal.

Error handling помогает твоей program survive problems.

Вместо crash, program может respond calmly.

Например:

Please enter a valid number.

Намного лучше.

Намного more professional.

Намного меньше “program exploded because someone typed banana”.

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

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

К концу этого урока твои programs будут more stable.

Они не будут panic immediately.

Они будут handle common problems.

Они survive users.

А users опасны.

Especially when the user is you at midnight.

Что такое error?

Error — это problem, который останавливает program от correct work.

Пример:

number = int("banana")

Python не может convert "banana" to a number.

Поэтому он даёт error:

ValueError

Другой пример:

result = 10 / 0

Python даёт:

ZeroDivisionError

Потому что division by zero is not allowed.

Другой пример:

with open("missing.txt", "r") as file:
    content = file.read()

Python даёт:

FileNotFoundError

Потому что file does not exist.

Errors нормальны.

Это не proof, что ты плохой в programming.

Это proof, что programming is programming.

Welcome.

Что такое exception?

В Python много runtime errors называются exceptions.

Exception happens, когда Python runs into a problem while the program is running.

Examples:

ValueError
FileNotFoundError
ZeroDivisionError
NameError
TypeError
IndexError
KeyError

Ты уже видел некоторые из них.

Возможно, too many.

Это нормально.

Exception обычно stops the program.

Unless you handle it.

Error handling означает:

If something goes wrong, do something safe instead of crashing.

Для этого нужны try и except.

Очень useful.

Очень important.

Очень “please do not explode”.

Твой первый try и except

Создай файл:

error_handling.py

Напиши:

try:
    number = int(input("Enter a number: "))
    print(f"You entered: {number}")
except ValueError:
    print("That was not a valid number.")

Запусти.

Если введёшь:

25

Output:

You entered: 25

Если введёшь:

banana

Output:

That was not a valid number.

Program не crashes.

Excellent.

Python tried to run risky code.

Когда failed, Python jumped to except.

Очень civilized.

Очень useful.

Much better than screaming in red text.

Как работают try и except

Basic structure:

try:
    risky_code
except SomeError:
    code_to_run_if_error_happens

Пример:

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

try block содержит code that might fail.

except block содержит code, который runs if selected error happens.

Думай об этом так:

Try this.
If this specific problem happens, do this instead.

Это как safety net.

Without safety net, program falls.

With safety net, program says:

Nice try, banana input.

And continues.

Handling ValueError

ValueError часто happens when converting input.

Пример:

age = int(input("Age: "))

Если user enters:

hello

Python cannot convert it to an integer.

So it raises:

ValueError

Safer version:

try:
    age = int(input("Age: "))
    print(f"You are {age} years old.")
except ValueError:
    print("Age must be a number.")

Это very common.

User input dangerous.

Users type strange things.

Sometimes by mistake.

Sometimes because they are testing your program.

Sometimes because they are chaos with fingers.

Поэтому always be careful with user input.

Ask again after an error

Вместо того, чтобы print error и stop, можно ask again.

Пример:

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

print(f"You are {age} years old.")

Как это works:

Start an infinite loop.
Ask for age.
Try to convert it.
If it works, break the loop.
If it fails, show a message and ask again.

Пример:

Age: banana
Please enter a valid number.
Age: hello
Please enter a valid number.
Age: 25
You are 25 years old.

Это much better.

Program does not die.

Она educates the user.

Gently.

Like a patient teacher.

But inside, it is probably tired.

Helper function для safe integer input

Можем положить эту logic в function.

Создай файл:

safe_input.py

Напиши:

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

age = get_integer("Age: ")

print(f"You are {age} years old.")

Теперь get_integer() keeps asking until user enters valid integer.

Это very useful.

Можешь reuse it many times.

Пример:

quantity = get_integer("Quantity: ")
year = get_integer("Year: ")
score = get_integer("Score: ")

Functions plus error handling.

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

Очень clean.

Очень “we are becoming serious now”.

Handling float input

Иногда нужны decimal numbers.

Пример:

price = float(input("Price: "))

Это тоже может raise ValueError.

Safer function:

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

price = get_float("Price: ")

print(f"Price: {price:.2f}")

Если user enters:

abc

Program asks again.

Если user enters:

19.99

It works.

Это useful для:

prices
measurements
averages
discounts
percentages

Basically, anything where decimals enter the room wearing serious shoes.

Handling ZeroDivisionError

Division by zero is not allowed.

Пример:

result = 10 / 0

Python даёт:

ZeroDivisionError

Safer example:

try:
    number = float(input("Number: "))
    result = 100 / number
    print(f"Result: {result}")
except ZeroDivisionError:
    print("You cannot divide by zero.")
except ValueError:
    print("Please enter a valid number.")

Если user enters:

0

Output:

You cannot divide by zero.

Если user enters:

banana

Output:

Please enter a valid number.

Это handles two possible problems.

Очень practical.

Очень useful.

Очень “the program has seen things”.

Multiple except blocks

Можно handle different errors separately.

Пример:

try:
    number = int(input("Enter a number: "))
    result = 100 / number
    print(result)
except ValueError:
    print("That was not a valid number.")
except ZeroDivisionError:
    print("You cannot divide by zero.")

Это good, потому что different errors need different messages.

ValueError означает:

The input was not a number.

ZeroDivisionError означает:

The number was zero.

Different problem.

Different response.

Good programs explain problems clearly.

Bad programs say:

Something went wrong.

And then disappear into the fog.

Do not be fog.

Handling FileNotFoundError

Ты уже видел files.

Reading a missing file causes FileNotFoundError.

Пример:

try:
    with open("notes.txt", "r") as file:
        content = file.read()

    print(content)
except FileNotFoundError:
    print("The file does not exist yet.")

Если notes.txt exists, program reads it.

Если it does not exist, program prints:

The file does not exist yet.

Это much better than crashing.

File errors common.

Especially when:

the file was never created
the file name is wrong
the file is in another folder
you are running Python from the wrong directory

Classic file drama.

Very normal.

Very fixable.

Loading tasks safely

В предыдущем уроке мы saved tasks in a file.

Теперь можем load them safely.

Пример:

def load_tasks():
    tasks = []

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

    return tasks

If file exists, tasks are loaded.

If file does not exist, function returns empty list.

Это good.

The first time your program runs, there may be no file yet.

That is not a disaster.

It is just a new program with no data.

Very innocent.

Very empty.

Very ready to become messy later.

Using else with try

Python также supports else with try.

else block runs only if no error happens.

Пример:

try:
    number = int(input("Enter a number: "))
except ValueError:
    print("Invalid number.")
else:
    print(f"Good number: {number}")

If input valid:

Enter a number: 10
Good number: 10

If input invalid:

Enter a number: banana
Invalid number.

else block optional.

You do not always need it.

Но sometimes it makes code clearer.

Simple idea:

try risky thing
except if it fails
else if it succeeds

Very tidy.

Very Python.

Like a small legal contract for errors.

Using finally

Python also has finally.

finally block runs no matter what.

Пример:

try:
    number = int(input("Enter a number: "))
    print(number)
except ValueError:
    print("Invalid number.")
finally:
    print("Program finished.")

If user enters a number, finally runs.

If user enters bad input, finally still runs.

Example:

Enter a number: banana
Invalid number.
Program finished.

finally useful, когда надо clean up something.

For beginner programs, you will not need it often.

Но good to know it exists.

Как fire extinguisher.

You may not use it every day.

But you want it there.

Не ловить everything too early

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

try:
    number = int(input("Number: "))
except:
    print("Something went wrong.")

Это catches every error.

It works.

But usually not ideal.

Why?

Потому что it can hide real bugs.

Better:

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

Это handles the specific problem you expect.

Specific error handling better.

It tells you what really happened.

Catching everything is like putting a blanket over the problem.

Problem still there.

Now it is just warmer.

And harder to see.

Не ставить too much code в try

Bad:

try:
    name = input("Name: ")
    age = int(input("Age: "))
    city = input("City: ")
    print(user_name)
except ValueError:
    print("Invalid age.")

Это risky, потому что try block contains too much.

There may be other errors inside.

Например:

print(user_name)

could cause NameError.

Better:

name = input("Name: ")

try:
    age = int(input("Age: "))
except ValueError:
    print("Invalid age.")

city = input("City: ")

Keep try focused on the code that may produce expected error.

This makes debugging easier.

And easier debugging is happiness.

Small happiness.

But still happiness.

Error handling не для hiding bad code

Important lesson.

Error handling is not a trash bin for broken logic.

Bad idea:

try:
    broken_code_here
except:
    pass

This hides problems.

Program may continue, but something is wrong.

And now you do not know what.

except: pass can be useful in rare cases.

But beginners should avoid using it casually.

If you ignore every error, your program becomes a mysterious creature.

It runs.

Maybe.

It does things.

Maybe.

Nobody knows why.

This is not engineering.

This is haunted programming.

Avoid.

Мини-программа: safe age input

Создай файл:

safe_age.py

Напиши:

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

print(f"Your age is {age}.")

Пример:

Age: hello
Please enter a valid age.
Age: 33
Your age is 33.

Эта program keeps asking until user enters valid integer.

Simple.

Useful.

Much better than crashing.

Это very common beginner pattern.

Use it often.

Your users will type strange things.

Your program should not faint.

Мини-программа: safe calculator

Создай файл:

safe_calculator.py

Напиши:

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

    result = first_number / second_number

    print(f"Result: {result:.2f}")
except ValueError:
    print("Please enter valid numbers.")
except ZeroDivisionError:
    print("You cannot divide by zero.")

Пример:

First number: 10
Second number: 2
Result: 5.00

Если user enters:

Second number: 0

Output:

You cannot divide by zero.

Эта program handles two common problems.

Invalid input.

Division by zero.

Очень useful.

Очень practical.

Очень “calculator has survival instincts now”.

Мини-программа: safe notes reader

Создай файл:

safe_notes_reader.py

Напиши:

try:
    with open("notes.txt", "r") as file:
        print("Notes:")

        for line in file:
            print(f"- {line.strip()}")
except FileNotFoundError:
    print("No notes found yet.")

If file exists, it shows notes.

If not, it prints:

No notes found yet.

Это clean.

Missing file is not always a disaster.

Sometimes it just means:

No data yet.

That is a normal situation.

Good programs understand normal situations.

Bad programs panic and throw red text.

We prefer calm programs.

Very Zen.

Very Python.

Мини-программа: safer task manager

Теперь improve task manager.

Создай файл:

safe_task_manager.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 show_menu():
    print("----- Task Manager -----")
    print("1. Add task")
    print("2. Show tasks")
    print("3. Remove task")
    print("q. Quit")

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):
    if len(tasks) == 0:
        print("No tasks to remove.")
        return

    show_tasks(tasks)

    try:
        task_number = int(input("Task number to remove: "))
        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}")
    except ValueError:
        print("Please enter a valid number.")

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":
        remove_task(tasks)
    elif choice == "q":
        print("Goodbye.")
        break
    else:
        print("Unknown option.")

Это stronger program.

It uses:

Это real beginner software.

Small, yes.

But real.

It saves data.

Loads data.

Handles missing files.

Handles bad input.

This is how programs grow.

One safety net at a time.

Что делает enumerate()

В task manager мы used:

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

enumerate() gives both:

number
item

Пример:

tasks = ["Buy milk", "Study Python"]

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

Output:

1. Buy milk
2. Study Python

Это useful, когда showing numbered lists.

User sees task number 1.

Python list index is actually 0.

Поэтому when removing a task, we do:

index = task_number - 1

User-friendly number.

Python-friendly index.

Diplomacy.

Between humans and machines.

Very important.

Типичная ошибка: handling wrong error

Пример:

try:
    age = int(input("Age: "))
except FileNotFoundError:
    print("File not found.")

This does not make sense.

Risky code is converting input to int.

Likely error is:

ValueError

Correct:

try:
    age = int(input("Age: "))
except ValueError:
    print("Invalid age.")

Handle the error that can actually happen.

Otherwise your program is guarding the wrong door.

And the bug comes through the window.

Classic bug behavior.

Типичная ошибка: too broad except

Not ideal:

try:
    age = int(input("Age: "))
except:
    print("Something went wrong.")

Better:

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

Specific is better.

The more specific your error handling is, the easier debugging becomes.

Vague error message helps nobody.

Especially you.

And you are the one who must fix the code.

Be kind to future you.

Future you has already suffered enough.

Типичная ошибка: ignoring the error completely

Dangerous:

try:
    age = int(input("Age: "))
except ValueError:
    pass

If user enters invalid input, nothing happens.

Program silently ignores the problem.

This can create confusing bugs.

Better:

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

At least tell the user what happened.

Silent failure is dangerous.

It is like a smoke alarm that whispers.

Not useful.

Типичная ошибка: using variable that was not created

Пример:

try:
    age = int(input("Age: "))
except ValueError:
    print("Invalid age.")

print(age)

If user enters invalid input, age is never created.

Then:

print(age)

can cause:

NameError

Better:

try:
    age = int(input("Age: "))
    print(age)
except ValueError:
    print("Invalid age.")

Or use a loop until valid input is received.

Очень important.

If variable is created inside try block, make sure it exists before using it later.

Python is not magic.

It will not invent the variable out of pity.

Типичная ошибка: error handling without fixing flow

Bad:

try:
    number = int(input("Number: "))
except ValueError:
    print("Invalid number.")

result = number * 2
print(result)

If input invalid, number may not exist.

Better:

while True:
    try:
        number = int(input("Number: "))
        break
    except ValueError:
        print("Invalid number.")

result = number * 2
print(result)

Now program only continues when number is valid.

That is good flow.

Error handling is not just about printing messages.

It is about controlling what happens next.

Very important.

Very program architecture.

Small architecture.

But still architecture.

Практика

Создай файл:

practice_error_handling.py

Напиши program, которая:

Пример решения:

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

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

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

total = price * quantity

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

Пример:

Price: hello
Please enter a valid number.
Price: 10.50
Quantity: banana
Please enter a valid whole number.
Quantity: 3
Total: 31.50

Это clean program.

It handles bad input.

It reuses functions.

It calculates safely.

Very good practice.

Very shop-like.

Taxes are still hiding nearby.

But not today.

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

Создай файл:

safe_contact_book.py

Построй small contact book, которая:

Simple contact format:

name,email,phone

Example structure:

FILE_NAME = "contacts.txt"

def load_contacts():
    contacts = []

    try:
        with open(FILE_NAME, "r") as file:
            for line in file:
                parts = line.strip().split(",")

                if len(parts) == 3:
                    contact = {
                        "name": parts[0],
                        "email": parts[1],
                        "phone": parts[2]
                    }

                    contacts.append(contact)
    except FileNotFoundError:
        pass

    return contacts

def save_contacts(contacts):
    with open(FILE_NAME, "w") as file:
        for contact in contacts:
            file.write(f"{contact['name']},{contact['email']},{contact['phone']}\n")

def add_contact(contacts):
    contact = {
        "name": input("Name: "),
        "email": input("Email: "),
        "phone": input("Phone: ")
    }

    contacts.append(contact)
    save_contacts(contacts)

    print("Contact saved.")

def show_contacts(contacts):
    if len(contacts) == 0:
        print("No contacts yet.")
    else:
        print("Contacts:")

        for contact in contacts:
            print("-----")
            print(f"Name: {contact['name']}")
            print(f"Email: {contact['email']}")
            print(f"Phone: {contact['phone']}")

def show_menu():
    print("----- Contact Book -----")
    print("1. Add contact")
    print("2. Show contacts")
    print("q. Quit")

contacts = load_contacts()

while True:
    show_menu()

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

    if choice == "1":
        add_contact(contacts)
    elif choice == "2":
        show_contacts(contacts)
    elif choice == "q":
        print("Goodbye.")
        break
    else:
        print("Unknown option.")

Эта program combines many things you learned:

That is a lot.

Это уже не просто “Hello, World!”.

Это small real program.

It saves data.

Loads data.

Uses structured information.

Handles missing files.

Very strong progress.

Very Python.

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

Когда твой error handling не работает, проверь:

Did I put risky code inside try?
Am I catching the correct error?
Did I use ValueError for invalid number conversion?
Did I use FileNotFoundError for missing files?
Did I use ZeroDivisionError for division by zero?
Did I accidentally catch everything with bare except?
Am I hiding errors with pass?
Does the program continue safely after an error?
Could a variable be missing after a failed try block?
Should I use a loop to ask again?
Is my try block too large?

Error handling is not about making errors disappear.

It is about responding correctly.

Good program does not pretend problems do not exist.

Good program says:

I expected this problem.
Here is what we do.

Very calm.

Very adult.

Very useful.

Итог

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

Это большой шаг.

Твои programs now safer.

Они могут handle bad input.

Они могут handle missing files.

Они могут avoid dramatic crashes.

Они могут guide the user instead of exploding.

Это то, что real programs need.

Потому что real life messy.

Files go missing.

Users type bananas.

Numbers become zero.

И sometimes you forget what you wrote yesterday.

Error handling helps your program survive the mess.

Очень useful.

Очень Python.

Очень real.

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

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

Ты научишься split code into different files и reuse code across your project.

Вместо того, чтобы держать everything in one giant file, ты organize code like this:

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

Потом ты будешь import functions from one file into another.

Это ещё один huge step toward real projects.

Потому что real projects are not one giant file.

Usually.

Unless someone suffered.

And we do not want that.

We want clean structure.

Reusable code.

And fewer files named final_final_really_final.py.

Very Python.

Very next level.