← Back to course

JSON: сохранение structured data

JSON: сохранение structured data

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

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

Твои programs научились split code into multiple files.

Ты писал projects like:

main.py
tasks.py
safe_input.py

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

Твой code теперь more organized.

Меньше giant file.

Меньше code lasagna.

Меньше “где я положил ту function?”

Excellent progress.

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

В предыдущих уроках мы saved data in plain text files.

Например:

Anna,anna@example.com,123456
Marco,marco@example.com,987654

This works.

Но это не perfect.

What if data becomes more complex?

What if one contact has more fields?

What if you want to save a list of dictionaries?

What if user writes a comma in the name?

Chaos.

Text files useful.

Но для structured data, JSON is better.

JSON позволяет save data like this:

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

into a file.

Потом можно load it back later.

Это очень important.

JSON used everywhere.

APIs.

Web apps.

Configuration files.

Databases.

Frontend and backend communication.

Tiny scripts that accidentally become real software.

Very useful.

Very practical.

Very Python-friendly.

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

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

К концу этого урока твои programs смогут save structured data properly.

Не просто simple lines.

Real data.

Lists.

Dictionaries.

Nested information.

Very powerful.

Very useful.

Very “now this is starting to look like a real app”.

Что такое JSON?

JSON means:

JavaScript Object Notation

Не паникуй.

Even though name says JavaScript, JSON is used by many languages.

Python uses JSON.

JavaScript uses JSON.

Java uses JSON.

APIs use JSON.

Web apps use JSON.

Everybody uses JSON.

JSON — это text format for storing and exchanging data.

Он выглядит так:

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

Looks familiar?

Он очень similar to a Python dictionary.

Python dictionary:

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

JSON:

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

Very similar.

Not exactly the same.

Но close enough to feel friendly.

Like cousins.

One speaks Python.

One speaks web.

Почему JSON useful

JSON useful, потому что может store structured data.

For example, one contact:

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

A list of contacts:

[
  {
    "name": "Anna",
    "email": "anna@example.com",
    "phone": "123456"
  },
  {
    "name": "Marco",
    "email": "marco@example.com",
    "phone": "987654"
  }
]

Это much better than plain text like:

Anna,anna@example.com,123456
Marco,marco@example.com,987654

Why?

Потому что JSON keeps structure.

Он knows that each contact has:

name
email
phone

Он can store lists.

Он can store dictionaries.

Он can store nested data.

Plain text — это как writing everything on a napkin.

JSON — это как small organized form.

Still text.

But with structure.

Very nice.

Importing json module

Python has built-in module for JSON.

It is called:

json

To use it, import it:

import json

You do not need to install anything.

Python already includes it.

Very convenient.

Very civilized.

Very “finally, something works without installing seventeen packages”.

Basic idea:

import json

Then you can use:

json.dump()
json.load()

These two functions are very important.

dump saves data to a file.

load loads data from a file.

Simple.

Almost too simple.

Do not worry.

We will make it confusing later.

That is how programming works.

Saving a dictionary to JSON

Создай file:

save_contact.py

Напиши:

import json

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

with open("contact.json", "w") as file:
    json.dump(contact, file)

Run:

python save_contact.py

или:

python3 save_contact.py

Python creates a file:

contact.json

Inside it, you may see:

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

This is valid JSON.

Not very pretty.

But valid.

This line saves the dictionary:

json.dump(contact, file)

Important:

json.dump(data, file)

means:

Save this Python data into this file as JSON.

Very useful.

Very clean.

Very structured.

Pretty JSON with indent

Previous JSON works, but it is all on one line.

Можем сделать prettier.

Use indent=4.

Example:

import json

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

with open("contact.json", "w") as file:
    json.dump(contact, file, indent=4)

Now contact.json looks like:

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

Much better.

Much easier to read.

Much less “JSON spaghetti”.

Use indent=4 when you want human-readable JSON.

Computers do not care.

Humans care.

And unfortunately, you are human.

Most days.

Loading a dictionary from JSON

Теперь прочитаем JSON file back.

Создай file:

load_contact.py

Напиши:

import json

with open("contact.json", "r") as file:
    contact = json.load(file)

print(contact)
print(contact["name"])
print(contact["email"])
print(contact["phone"])

Output:

{'name': 'Anna', 'email': 'anna@example.com', 'phone': '123456'}
Anna
anna@example.com
123456

This line loads JSON from the file:

contact = json.load(file)

After loading, contact is a Python dictionary again.

That is the magic.

Not fake magic.

Useful magic.

Workflow:

Python dictionary
save as JSON
load from JSON
Python dictionary again

Very important.

Very practical.

Very real-world.

json.dump() vs json.load()

These two names are important.

json.dump(data, file)

saves data to a file.

json.load(file)

loads data from a file.

Remember:

dump = save
load = read

Example:

json.dump(contact, file)

means:

Save contact into file.

Example:

contact = json.load(file)

means:

Read JSON from file and convert it into Python data.

This pair is used constantly.

If you remember only one thing from this lesson, remember:

json.dump() saves.
json.load() loads.

That is the heart of JSON file handling.

Very small heart.

Very useful heart.

Saving a list to JSON

JSON can store lists too.

Создай:

save_tasks_json.py

Напиши:

import json

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

with open("tasks.json", "w") as file:
    json.dump(tasks, file, indent=4)

File tasks.json will contain:

[
    "Buy milk",
    "Study Python",
    "Drink coffee"
]

This is a JSON array.

In Python, we call it a list.

In JSON, it is called an array.

Same idea.

Different vocabulary.

Programming loves giving the same thing different names.

Keeps us humble.

And slightly annoyed.

Loading a list from JSON

Создай:

load_tasks_json.py

Напиши:

import json

with open("tasks.json", "r") as file:
    tasks = json.load(file)

for task in tasks:
    print(f"- {task}")

Output:

- Buy milk
- Study Python
- Drink coffee

JSON array became a Python list.

Very useful.

This is better than reading lines manually.

With plain text, we did:

for line in file:
    tasks.append(line.strip())

With JSON, Python can load the whole structure automatically:

tasks = json.load(file)

Cleaner.

More powerful.

Less manual string surgery.

Excellent.

Saving a list of dictionaries

This is where JSON becomes very useful.

Создай:

save_contacts_json.py

Напиши:

import json

contacts = [
    {
        "name": "Anna",
        "email": "anna@example.com",
        "phone": "123456"
    },
    {
        "name": "Marco",
        "email": "marco@example.com",
        "phone": "987654"
    }
]

with open("contacts.json", "w") as file:
    json.dump(contacts, file, indent=4)

File contacts.json will contain:

[
    {
        "name": "Anna",
        "email": "anna@example.com",
        "phone": "123456"
    },
    {
        "name": "Marco",
        "email": "marco@example.com",
        "phone": "987654"
    }
]

This is much better than:

Anna,anna@example.com,123456
Marco,marco@example.com,987654

Because structure is clear.

Each contact is an object.

Each object has keys.

The list contains contacts.

Beautiful.

Organized.

Like a filing cabinet.

But less dusty.

Loading a list of dictionaries

Создай:

load_contacts_json.py

Напиши:

import json

with open("contacts.json", "r") as file:
    contacts = json.load(file)

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

Output:

-----
Name: Anna
Email: anna@example.com
Phone: 123456
-----
Name: Marco
Email: marco@example.com
Phone: 987654

Now you can save and load structured contact data.

This is real.

This pattern appears everywhere.

A list of dictionaries is one of the most common beginner data structures.

JSON saves it beautifully.

Python loads it easily.

Very nice.

Very practical.

Very backend-friendly.

Python and JSON types

Python data becomes JSON data.

Basic conversion:

Python dict       -> JSON object
Python list       -> JSON array
Python string     -> JSON string
Python int/float  -> JSON number
Python True       -> JSON true
Python False      -> JSON false
Python None       -> JSON null

Example Python:

data = {
    "name": "Anna",
    "age": 25,
    "active": True,
    "skills": ["Python", "HTML", "CSS"],
    "address": None
}

JSON:

{
    "name": "Anna",
    "age": 25,
    "active": true,
    "skills": [
        "Python",
        "HTML",
        "CSS"
    ],
    "address": null
}

Notice:

True becomes true
False becomes false
None becomes null

Small differences.

Important differences.

JSON is not exactly Python.

It just looks like Python after drinking tea with JavaScript.

Important JSON rules

JSON has rules.

Very strict rules.

Strings must use double quotes:

"name"

Not single quotes:

'name'

Correct JSON:

{
    "name": "Anna"
}

Invalid JSON:

{
    'name': 'Anna'
}

Also, JSON does not allow trailing commas.

Correct:

{
    "name": "Anna",
    "age": 25
}

Wrong:

{
    "name": "Anna",
    "age": 25,
}

Python dictionaries allow more flexibility.

JSON is stricter.

Very strict.

Like a teacher with a ruler.

But for data.

Handling missing JSON files

If you try to load JSON file that does not exist, Python gives:

FileNotFoundError

Example:

import json

with open("missing.json", "r") as file:
    data = json.load(file)

Safer version:

import json

try:
    with open("contacts.json", "r") as file:
        contacts = json.load(file)
except FileNotFoundError:
    contacts = []

print(contacts)

If file exists, contacts are loaded.

If it does not exist, contacts becomes an empty list.

This is useful for first run.

New program.

No data yet.

No disaster.

Just an empty list waiting for life.

Very poetic.

For a file.

Saving after changes

When working with JSON, usual pattern is:

load data
change data
save data

Example:

import json

try:
    with open("contacts.json", "r") as file:
        contacts = json.load(file)
except FileNotFoundError:
    contacts = []

new_contact = {
    "name": "Sofia",
    "email": "sofia@example.com",
    "phone": "555000"
}

contacts.append(new_contact)

with open("contacts.json", "w") as file:
    json.dump(contacts, file, indent=4)

This does:

Load contacts.
If file missing, start with empty list.
Add new contact.
Save updated list.

This pattern is extremely important.

You will use it again and again.

Load.

Modify.

Save.

The holy triangle of small data programs.

Very useful.

Very practical.

Very easy to forget one side and wonder why nothing saved.

Мини-программа: save profile as JSON

Создай:

profile_json.py

Напиши:

import json

profile = {
    "name": input("Name: "),
    "city": input("City: "),
    "job": input("Job: ")
}

with open("profile.json", "w") as file:
    json.dump(profile, file, indent=4)

print("Profile saved.")

Example input:

Name: Anna
City: Rome
Job: Developer

File profile.json:

{
    "name": "Anna",
    "city": "Rome",
    "job": "Developer"
}

This is simple.

But powerful.

You saved a dictionary as structured data.

You can read it later.

You can edit it.

You can use it in another program.

Small project.

Real idea.

Мини-программа: load profile from JSON

Создай:

show_profile_json.py

Напиши:

import json

try:
    with open("profile.json", "r") as file:
        profile = json.load(file)

    print("----- Profile -----")
    print(f"Name: {profile['name']}")
    print(f"City: {profile['city']}")
    print(f"Job: {profile['job']}")
except FileNotFoundError:
    print("No profile found.")

Output:

----- Profile -----
Name: Anna
City: Rome
Job: Developer

Now your program can load structured data.

This is a big step.

Plain text profile would require manual parsing.

JSON makes it direct.

No splitting.

No commas.

No string surgery.

Just load and use.

Beautiful.

Мини-программа: JSON Task Manager

Создай:

json_task_manager.py

Напиши:

import json

FILE_NAME = "tasks.json"

def load_tasks():
    try:
        with open(FILE_NAME, "r") as file:
            return json.load(file)
    except FileNotFoundError:
        return []

def save_tasks(tasks):
    with open(FILE_NAME, "w") as file:
        json.dump(tasks, file, indent=4)

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

def add_task(tasks):
    task = {
        "title": input("Task title: "),
        "done": False
    }

    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):
            status = "done" if task["done"] else "not done"
            print(f"{index}. {task['title']} - {status}")

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['title']}")
    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.")

This task manager saves tasks as dictionaries.

Each task has:

title
done

Example JSON:

[
    {
        "title": "Study Python",
        "done": false
    },
    {
        "title": "Drink coffee",
        "done": false
    }
]

This is better than a plain list of task names.

Because now each task can have more information.

Later you can add:

priority
deadline
category
created_at

JSON grows better than plain text.

Plain text is good for simple data.

JSON is better for structured data.

Мини-программа: JSON Contact Book

Создай:

json_contact_book.py

Напиши:

import json

FILE_NAME = "contacts.json"

def load_contacts():
    try:
        with open(FILE_NAME, "r") as file:
            return json.load(file)
    except FileNotFoundError:
        return []

def save_contacts(contacts):
    with open(FILE_NAME, "w") as file:
        json.dump(contacts, file, indent=4)

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

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']}")

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.")

This is a real beginner app.

It uses:

Very strong.

Very useful.

Very real.

Your contact data is now structured and saved properly.

This is much better than comma-separated text.

Because if later you add:

address
birthday
notes
company

JSON can handle it nicely.

Plain text starts sweating.

Типичная ошибка: forgetting import json

Wrong:

with open("data.json", "w") as file:
    json.dump(data, file)

If you did not write:

import json

Python gives:

NameError

Correct:

import json

with open("data.json", "w") as file:
    json.dump(data, file)

Always import the module before using it.

Python is powerful.

But it does not automatically guess your imports.

It is not a mind reader.

Thankfully.

Типичная ошибка: using dump and load backwards

Wrong:

data = json.dump(file)

Wrong:

json.load(data, file)

Correct:

json.dump(data, file)

Correct:

data = json.load(file)

Remember:

dump takes data and file
load takes file and returns data

Simple memory trick:

dump data into a file
load data from a file

If this feels confusing, that is normal.

The names are short.

The confusion is long.

Practice helps.

Типичная ошибка: trying to save unsupported data

JSON can save common data types:

dict
list
str
int
float
bool
None

But not everything.

For example, this may fail:

data = {
    "numbers": {1, 2, 3}
}

Why?

Because {1, 2, 3} is a set.

JSON does not support Python sets directly.

If you need to save a set, convert it to a list:

data = {
    "numbers": list({1, 2, 3})
}

For beginners, use:

dictionaries
lists
strings
numbers
booleans
None

These work well with JSON.

Keep it simple.

Simple survives.

Complicated asks for coffee.

Типичная ошибка: invalid JSON file

If JSON file is broken, json.load() can fail.

Example invalid JSON:

{
    "name": "Anna",
}

The trailing comma makes it invalid.

Python may raise:

json.JSONDecodeError

Safer loading:

import json

try:
    with open("data.json", "r") as file:
        data = json.load(file)
except FileNotFoundError:
    data = []
except json.JSONDecodeError:
    print("JSON file is broken.")
    data = []

This handles:

missing file
broken JSON file

Very useful.

Especially when humans edit JSON manually.

Humans and commas are a dangerous combination.

Very dangerous.

Типичная ошибка: forgetting to save after append

Wrong:

contacts = load_contacts()

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

contacts.append(contact)

print("Contact added.")

This adds contact only in memory.

But it does not save to file.

When program ends, new contact disappears.

Correct:

contacts.append(contact)
save_contacts(contacts)

Remember the pattern:

load
modify
save

If you modify data but do not save it, file does not change.

Python is not going to save it emotionally.

You must tell it.

Clearly.

With code.

Типичная ошибка: opening JSON with append mode

This is usually wrong:

with open("contacts.json", "a") as file:
    json.dump(contact, file)

Appending JSON objects directly can create invalid JSON.

Example broken file:

{"name": "Anna"}{"name": "Marco"}

That is not a valid JSON list.

For JSON files, usually do this:

load existing list
append item to list
save whole list again

Example:

contacts = load_contacts()
contacts.append(new_contact)
save_contacts(contacts)

This keeps JSON file valid.

Append mode useful for plain text logs.

For JSON structured data, be careful.

Very careful.

JSON likes structure.

Not random objects glued together.

Практика

Создай:

practice_json.py

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

Example solution:

import json

book = {
    "title": input("Title: "),
    "author": input("Author: "),
    "year": input("Year: ")
}

with open("book.json", "w") as file:
    json.dump(book, file, indent=4)

with open("book.json", "r") as file:
    loaded_book = json.load(file)

print("----- Book -----")
print(f"Title: {loaded_book['title']}")
print(f"Author: {loaded_book['author']}")
print(f"Year: {loaded_book['year']}")

This practice teaches:

Simple.

Useful.

Very structured.

Very good.

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

Создай:

library_json.py

Build a small library program that:

Example structure:

import json

FILE_NAME = "books.json"

def load_books():
    try:
        with open(FILE_NAME, "r") as file:
            return json.load(file)
    except FileNotFoundError:
        return []

def save_books(books):
    with open(FILE_NAME, "w") as file:
        json.dump(books, file, indent=4)

def add_book(books):
    book = {
        "title": input("Title: "),
        "author": input("Author: "),
        "year": input("Year: ")
    }

    books.append(book)
    save_books(books)

    print("Book saved.")

def show_books(books):
    if len(books) == 0:
        print("No books yet.")
    else:
        print("Books:")

        for book in books:
            print("-----")
            print(f"Title: {book['title']}")
            print(f"Author: {book['author']}")
            print(f"Year: {book['year']}")

def show_menu():
    print("----- Library -----")
    print("1. Add book")
    print("2. Show books")
    print("q. Quit")

books = load_books()

while True:
    show_menu()

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

    if choice == "1":
        add_book(books)
    elif choice == "2":
        show_books(books)
    elif choice == "q":
        print("Goodbye.")
        break
    else:
        print("Unknown option.")

This is a real small application.

It uses JSON to store a list of dictionaries.

That is a very important pattern.

Very useful for future projects.

You can adapt this structure for:

contacts
tasks
products
students
courses
expenses
workouts

The idea is the same.

Load data.

Modify data.

Save data.

Congratulations.

You are building reusable patterns.

That is how developers grow.

Slowly.

Painfully.

With snacks.

Extra challenge: improve the task manager

Take JSON task manager and add a new option:

4. Mark task as done

Each task already has:

"done": False

Your job:

Hint:

tasks[index]["done"] = True
save_tasks(tasks)

This is a very good challenge.

It teaches updating structured data.

Not just adding.

Not just deleting.

Updating.

That is what real apps do all the time.

Create.

Read.

Update.

Delete.

Later you will hear this called CRUD.

Very serious word.

Very simple idea.

Very useful.

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

When JSON code does not work, check:

Did I import json?
Am I using json.dump(data, file)?
Am I using data = json.load(file)?
Did I open the file in the correct mode?
Did I use indent=4 for readable JSON?
Does the file exist before reading?
Should I handle FileNotFoundError?
Is the JSON file valid?
Did I accidentally leave a trailing comma?
Am I trying to save an unsupported Python type?
Did I save after changing the data?
Am I appending to JSON incorrectly?

JSON bugs are usually about:

file missing
invalid JSON
wrong dump/load usage
forgotten save
wrong data structure

Fix calmly.

Read the error message.

Check the file.

Check the data.

Drink coffee if needed.

But do not throw the laptop.

The laptop is innocent.

Usually.

Итог

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

Это большой step.

Твои programs теперь могут save real structured data.

Not just lines of text.

They can save contacts.

Tasks.

Books.

Profiles.

Products.

Anything that fits into dictionaries and lists.

This is the kind of data structure used in real applications.

Small beginner programs are now becoming serious.

Still small.

But serious.

Like a tiny engineer with a clipboard.

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

В следующем уроке мы изучим virtual environments и installing packages.

So far, we used only Python’s built-in tools.

But real Python projects often use external packages.

Ты научишься create a virtual environment:

python -m venv .venv

Activate it.

Install packages with pip.

And keep project dependencies organized.

Это очень important before building bigger projects.

Потому что installing packages globally is how chaos begins.

And we already have enough chaos.

Very Python.

Very real-world.

Very necessary.