← Back to course

Moduły i importy: organizowanie większych programów

Moduły i importy: organizowanie większych programów

Witaj z powrotem.

W poprzedniej lekcji nauczyłeś się obsługi błędów.

Twoje programy nauczyły się przetrwać zły input, brakujące pliki i dramatyczne eksplozje Pythona.

Pisałeś rzeczy takie jak:

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

Bardzo dobrze.

Teraz twoje programy są bezpieczniejsze.

Nie mdleją od razu, kiedy ktoś wpisze:

banana

Świetny postęp.

Ale teraz mamy kolejny problem.

Twoje programy robią się większe.

Na początku jeden plik wystarczał.

Coś takiego:

main.py

Ładnie.

Prosto.

Przyjaźnie.

Ale potem dodałeś funkcje.

Potem listy.

Potem słowniki.

Potem pliki.

Potem obsługę błędów.

I nagle main.py robi się ogromny.

Gigantyczny plik.

Lasagne z kodu.

Cyfrowa szafa, w której jest wszystko, ale nikt nie wie, gdzie są skarpetki.

Tutaj pomagają moduły i importy.

Moduły pozwalają dzielić kod na wiele plików.

Importy pozwalają używać kodu z jednego pliku w innym pliku.

Zamiast jednego gigantycznego pliku możesz zorganizować projekt tak:

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

Dużo czyściej.

Dużo bardziej profesjonalnie.

Dużo mniej “gdzie ukryła się ta funkcja?”

Czego się nauczysz

W tej lekcji nauczysz się:

Pod koniec tej lekcji twój kod będzie bardziej uporządkowany.

Będziesz potrafił dzielić większe programy na mniejsze pliki.

Będziesz używać funkcji ponownie zamiast je kopiować.

Twoje projekty będą łatwiejsze do czytania.

A twój przyszły ty będzie cierpiał mniej.

Szlachetny cel.

Czym jest moduł?

Moduł to po prostu plik Pythona.

Tak.

Naprawdę.

Jeśli masz plik o nazwie:

helpers.py

Ten plik jest modułem.

Jeśli masz plik o nazwie:

calculator.py

Ten plik jest modułem.

Moduł może zawierać:

Na razie będziemy używać modułów głównie do przechowywania funkcji.

Przykład:

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

Potem inny plik może zaimportować i użyć tej funkcji.

To jest główna idea.

Piszesz kod w jednym pliku.

Używasz go w innym pliku.

Bardzo użyteczne.

Bardzo czyste.

Bardzo Python.

Dlaczego używać modułów?

Moduły pomagają organizować kod.

Zamiast jednego ogromnego pliku możesz podzielić program na mniejsze części.

Przykład:

main.py        uruchamia program
helpers.py     ogólne funkcje pomocnicze
tasks.py       funkcje związane z zadaniami
contacts.py    funkcje związane z kontaktami

To sprawia, że projekt jest łatwiejszy do zrozumienia.

Gigantyczny plik jest trudny do czytania.

Projekt z jasnymi plikami jest łatwiejszy do nawigacji.

Pomyśl o modułach jak o szufladach.

Jedna szuflada na skarpetki.

Jedna szuflada na koszulki.

Jedna szuflada na tajemnicze kable, których odmawiasz wyrzucenia.

Kod też potrzebuje szuflad.

Bez organizacji wszystko staje się chaosem.

A chaos i tak ma już dużo pracy.

Twój pierwszy moduł

Utwórz folder:

python_modules_lesson

W środku utwórz dwa pliki:

main.py
helpers.py

Folder powinien wyglądać tak:

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

W helpers.py napisz:

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

W main.py napisz:

import helpers

helpers.greet_user("Anna")

Uruchom:

python main.py

albo:

python3 main.py

Output:

Hello, Anna!

Gratulacje.

Stworzyłeś własny moduł.

Bardzo elegancko.

Bardzo uporządkowanie.

Bardzo “patrz, mój kod ma teraz osobne pokoje”.

Jak działa import

Ta linia importuje moduł:

import helpers

Mówi Pythonowi:

Załaduj plik helpers.py, żebym mógł używać tego, co jest w środku.

Potem możesz wywołać funkcję tak:

helpers.greet_user("Anna")

Dlaczego helpers.?

Bo funkcja żyje w module helpers.

Pełna nazwa to:

helpers.greet_user

To użyteczne, bo pokazuje, skąd pochodzi funkcja.

Jasny kod.

Bez zgadywania.

Bez pracy detektywa.

Bez “który plik stworzył tę funkcję?”

Python ci pokazuje.

Importowanie przez from

Jest też inny sposób.

Zamiast importować cały moduł, możesz importować jedną funkcję bezpośrednio.

W main.py napisz:

from helpers import greet_user

greet_user("Anna")

Output:

Hello, Anna!

Teraz nie potrzebujesz:

helpers.greet_user()

Możesz wywołać:

greet_user()

bo zaimportowałeś funkcję bezpośrednio.

Oba style działają.

Styl 1:

import helpers

helpers.greet_user("Anna")

Styl 2:

from helpers import greet_user

greet_user("Anna")

Oba są użyteczne.

Pierwszy styl jest jaśniejszy, jeśli chodzi o pochodzenie funkcji.

Drugi styl jest krótszy.

Programowanie jest pełne kompromisów.

Jak życie.

Ale z większą liczbą nawiasów.

Importowanie wielu funkcji

W helpers.py napisz:

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

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

W main.py napisz:

from helpers import greet_user, say_goodbye

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

Output:

Hello, Anna!
Goodbye, Anna!

Możesz importować wiele funkcji z tego samego modułu.

Oddziel je przecinkami:

from helpers import greet_user, say_goodbye

To użyteczne, kiedy moduł ma kilka funkcji pomocniczych.

Ale nie importuj zbyt wielu rzeczy na ślepo.

Jeśli linia importu robi się bardzo długa, może moduł robi za dużo.

Albo projekt rośnie.

Obie możliwości zasługują na uwagę.

Importowanie wszystkiego

Możesz zobaczyć coś takiego:

from helpers import *

To importuje wszystko z helpers.py.

Działa.

Ale początkujący powinni uważać.

Dlaczego?

Bo robi się niejasne, skąd pochodzą rzeczy.

Przykład:

from helpers import *

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

To działa.

Ale kiedy projekt rośnie, może robić się mylące.

Skąd pochodzi greet_user()?

Skąd pochodzi say_goodbye()?

Który moduł?

Który plik?

Która szuflada?

Tajemnica.

Zwykle lepiej być konkretnym:

from helpers import greet_user, say_goodbye

Jasność jest lepsza niż magia.

Magia jest dobra w filmach.

Mniej dobra w debugowaniu.

Nazwy modułów

Nazwy modułów powinny być proste.

Dobre:

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

Złe:

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

Używaj małych liter i podkreśleń.

Dobre:

file_utils.py
safe_input.py
task_manager.py

Unikaj spacji.

Unikaj myślników.

Unikaj nazw, które są słowami kluczowymi Pythona.

Na przykład nie nazywaj pliku:

import.py

To proszenie się o kłopoty.

Python już używa import.

Nie myl Pythona.

Jest potężny, ale nie jest twoim psychologiem.

Moduł dla funkcji kalkulatora

Utwórz pliki:

main.py
calculator.py

W calculator.py napisz:

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

W main.py napisz:

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

Teraz logika kalkulatora żyje w:

calculator.py

A program zaczyna się w:

main.py

To jest czyściej.

Główny plik nie musi zawierać każdej funkcji.

Może używać funkcji z innych modułów.

Tak rosną projekty.

Powoli.

Potem nagle.

Potem potrzebujesz folderów.

Ale jeszcze nie.

Jeden potwór naraz.

Moduł dla bezpiecznego inputu

W poprzedniej lekcji napisaliśmy funkcje do bezpiecznego inputu.

Przenieśmy je do modułu.

Utwórz:

safe_input.py

Napisz:

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

Teraz w main.py napisz:

from safe_input import get_integer, get_float

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

total = price * quantity

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

To bardzo ładne.

Logika bezpiecznego inputu jest wielokrotnego użytku.

Każdy program może ją zaimportować.

Nie trzeba kopiować i wklejać tych samych funkcji znowu i znowu.

To postęp.

To organizacja.

To mniej cierpienia.

Świetnie.

Importowanie modułów standard library

Python ma już wiele modułów wbudowanych.

To nazywa się standard library.

Przykłady:

math
random
datetime
os
pathlib
json

Możesz je też importować.

Przykład z math:

import math

print(math.sqrt(16))

Output:

4.0

Przykład z random:

import random

number = random.randint(1, 10)

print(number)

To wypisuje losową liczbę od 1 do 10.

Python daje ci wiele narzędzi za darmo.

Nie musisz pisać wszystkiego sam.

Bardzo miło.

Bardzo hojnie.

Bardzo “użyj skrzynki narzędziowej, zanim zbudujesz młotek od zera”.

Przykład: random choice

Utwórz plik:

random_example.py

Napisz:

import random

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

chosen_name = random.choice(names)

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

Output może być:

Chosen name: Sofia

Albo:

Chosen name: Marco

Bo to losowe.

Moduł random ma użyteczne funkcje takie jak:

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

To dobre do:

gier
losowych ćwiczeń
danych testowych
małych eksperymentów

Losowość jest użyteczna.

Też niebezpieczna.

Szczególnie przy nazywaniu plików.

Nie nazywaj plików produkcyjnych losowo.

Przyszły ty będzie płakał.

Przykład: moduł math

Utwórz:

math_example.py

Napisz:

import math

radius = 5

area = math.pi * radius ** 2

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

Output:

Area: 78.54

Moduł math daje nam:

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

Bardzo użyteczne do obliczeń.

Nie musisz definiować pi samodzielnie.

Nie pisz:

pi = 3.14

chyba że naprawdę chcesz małe przybliżenie w tanich butach.

Używaj:

math.pi

Dużo lepiej.

Kod, który uruchamia się przy imporcie

Ważne.

Bardzo ważne.

Utwórz helpers.py:

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

print("This is helpers.py")

Utwórz main.py:

import helpers

helpers.greet_user("Anna")

Uruchom main.py.

Output:

This is helpers.py
Hello, Anna!

Dlaczego Python wypisał:

This is helpers.py

Bo kiedy importujesz moduł, Python uruchamia kod top-level w tym pliku.

To znaczy, że kod poza funkcjami może uruchomić się podczas importu.

To bardzo zaskakuje początkujących.

Bardzo.

Dlatego uważaj.

Moduł zwykle powinien zawierać funkcje i stałe.

Nie losowe uruchamianie programu.

Inaczej importowanie modułu robi się pikantne.

I nie w dobrym sensie.

Pattern name == "main"

Czasem chcesz, żeby kod uruchamiał się tylko wtedy, gdy plik jest uruchomiony bezpośrednio.

Nie wtedy, gdy jest importowany.

Python ma popularny pattern do tego:

if __name__ == "__main__":
    code_here

Przykład:

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

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

Teraz:

To bardzo użyteczne.

Pozwala testować moduł bez tworzenia niespodzianek przy imporcie.

Na początku ta linia wygląda dziwnie:

if __name__ == "__main__":

Nie panikuj.

W praktyce oznacza:

Uruchom ten kod tylko wtedy, gdy ten plik jest głównym uruchamianym plikiem.

Wygląda dziwnie.

Bardzo użyteczne.

Bardzo Python.

Bezpieczne testowanie modułu

Utwórz helpers.py:

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

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

Jeśli uruchomisz:

python helpers.py

Output:

Hello, Anna!

Teraz utwórz main.py:

from helpers import greet_user

message = greet_user("Marco")

print(message)

Uruchom:

python main.py

Output:

Hello, Marco!

Zauważ, że kod testowy wewnątrz:

if __name__ == "__main__":

nie uruchomił się podczas importu.

Perfekcyjnie.

Czysto.

Profesjonalnie.

Mniej niespodzianek.

A w programowaniu mniej niespodzianek zwykle jest dobre.

Chyba że to twoje urodziny.

Ale nawet wtedy nie na produkcji.

Dzielenie programu na pliki

Zorganizujmy mały projekt.

Utwórz taką strukturę:

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

W safe_input.py napisz:

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

W tasks.py napisz:

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

W main.py napisz:

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

Ten projekt jest dużo lepiej zorganizowany.

main.py kontroluje flow programu.

tasks.py zawiera logikę zadań.

safe_input.py zawiera logikę bezpiecznego inputu.

To czyste.

To czytelne.

To struktura prawdziwego projektu.

Mały projekt.

Ale prawdziwa struktura.

Bardzo dobrze.

Dlaczego ta struktura jest lepsza

Spójrz na pliki:

main.py
tasks.py
safe_input.py

Każdy plik ma zadanie.

main.py:

Uruchamia program.
Pokazuje menu.
Obsługuje wybory użytkownika.

tasks.py:

Ładuje zadania.
Zapisuje zadania.
Dodaje zadania.
Pokazuje zadania.
Usuwa zadania.

safe_input.py:

Pobiera bezpieczny input integer.

To nazywa się separacja odpowiedzialności.

Eleganckie zdanie.

Prosta idea:

Nie wkładaj wszystkiego wszędzie.

Dobra organizacja sprawia, że kod jest łatwiejszy do utrzymania.

Kiedy potrzebujesz logiki zadań, idziesz do tasks.py.

Kiedy potrzebujesz logiki inputu, idziesz do safe_input.py.

Kiedy potrzebujesz flow programu, idziesz do main.py.

Bez poszukiwania skarbów.

Bez archeologii kodu.

Dużo lepiej.

Typowy błąd: ModuleNotFoundError

Możesz zobaczyć:

ModuleNotFoundError

Przykład:

import helpers

Ale Python mówi:

ModuleNotFoundError: No module named 'helpers'

Możliwe powody:

helpers.py nie istnieje
helpers.py jest w innym folderze
źle napisałeś nazwę pliku
uruchamiasz Pythona z niewłaściwego miejsca

Dla początkujących najlepiej trzymać pliki w tym samym folderze.

Przykład:

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

Potem uruchom z tego folderu:

python main.py

Prosto.

Mniej dramatu.

Importy Pythona są potężne.

Ale ścieżki mogą robić się pikantne.

Zacznij prosto.

Typowy błąd: zła nazwa pliku

Jeśli twój plik nazywa się:

helper.py

Ale piszesz:

import helpers

Python go nie znajdzie.

Nazwy muszą się zgadzać.

Plik:

helpers.py

Import:

import helpers

Bez .py w imporcie.

Poprawnie:

import helpers

Źle:

import helpers.py

Python importuje nazwy modułów, nie nazwy plików z rozszerzeniem.

Mały szczegół.

Duże zamieszanie.

Bardzo normalne.

Typowy błąd: circular imports

Circular imports dzieją się, kiedy dwa pliki importują siebie nawzajem.

Przykład:

a.py importuje b.py
b.py importuje a.py

To może powodować mylące błędy.

Początkujący powinni tego unikać.

Prosta zasada:

main.py może importować inne moduły.
Moduły pomocnicze zwykle nie powinny importować main.py.

Dobrze:

main.py importuje tasks.py
main.py importuje safe_input.py

Ryzykownie:

tasks.py importuje main.py
main.py importuje tasks.py

To tworzy pętlę.

Wąż jedzący własny ogon.

Ciekawy symbol.

Irytujący bug.

Unikaj.

Typowy błąd: logika programu w importowanych modułach

Zły helpers.py:

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

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

Jeśli zaimportujesz ten moduł, od razu zapyta o input.

Niespodzianka.

Niedobrze.

Lepiej:

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

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

Teraz input pojawia się tylko wtedy, gdy uruchamiasz helpers.py bezpośrednio.

Nie wtedy, gdy go importujesz.

To dużo bezpieczniejsze.

Pamiętaj:

Moduły zwykle powinny definiować rzeczy wielokrotnego użytku.
main.py zwykle powinien uruchamiać program.

Bardzo dobra zasada.

Typowy błąd: importowanie zbyt dużo

To może stać się bałaganem:

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

Teraz twój namespace jest pełny importowanych nazw.

Możesz nie wiedzieć, skąd coś przyszło.

Lepiej:

import helpers
import tasks

albo:

from helpers import greet_user
from tasks import load_tasks, save_tasks

Bądź jasny.

Jawne importy sprawiają, że kod jest łatwiejszy do zrozumienia.

Przyszły ty lubi jawne importy.

Przyszły ty jest zmęczony i nie ma cierpliwości do tajemnic.

Szanuj przyszłego siebie.

Praktyka

Utwórz taki projekt:

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

W calculator.py utwórz funkcje:

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

W main.py zaimportuj funkcje i zapytaj użytkownika o dwie liczby.

Przykładowe rozwiązanie:

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

Ta praktyka uczy:

Bardzo użyteczne.

Bardzo czyste.

Bardzo przyjazne dla początkujących.

Mini wyzwanie

Utwórz taki projekt:

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

W notes.py utwórz funkcje:

add_note()
show_notes()

Użyj pliku:

notes.txt

Przykład 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.")

Przykład 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.")

To bardzo dobry projekt dla początkujących.

Używa:

Mała aplikacja.

Dobra struktura.

Bardzo użyteczne.

Bardzo realne.

Extra challenge: podziel contact book

Utwórz:

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

contacts.py powinien zawierać:

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

main.py powinien zawierać:

menu
main loop
user choices

To większe wyzwanie.

Znasz już wszystkie części.

Teraz celem jest organizacja.

Nie pisz wszystkiego w jednym pliku.

Niech każdy plik odpowiada za jedną część.

Tak większe projekty pozostają zrozumiałe.

Albo przynajmniej mniej przerażające.

Mniej przerażające jest dobre.

Checklist dla początkujących

Kiedy importy nie działają, sprawdź:

Czy pliki są w tym samym folderze?
Czy dobrze napisałem nazwę modułu?
Czy napisałem import bez .py?
Czy uruchamiam Pythona z poprawnego folderu?
Czy stworzyłem circular imports?
Czy w importowanym module jest za dużo uruchamianego kodu?
Czy ten kod powinien być w if __name__ == "__main__"?
Czy importuję za dużo przez *?
Czy każdy plik ma jasne zadanie?

Problemy z importami są częste.

Bardzo częste.

Nie panikuj.

Zwykle problem to:

zła nazwa pliku
zły folder
zły styl importu
kod uruchamiający się podczas importu

Napraw spokojnie.

Komputery są dosłowne.

Robią dokładnie to, co mówisz.

Nie to, co miałeś na myśli.

Irytujące.

Ale uczciwe.

Podsumowanie

Dzisiaj nauczyłeś się:

To ogromny krok.

Twoje projekty mogą teraz rosnąć bez zamieniania się w jeden gigantyczny plik.

Możesz używać kodu ponownie.

Możesz organizować funkcje.

Możesz oddzielać flow programu od logiki pomocniczej.

Tak zaczynają się prawdziwe projekty.

Nie od jednego magicznego pliku, który robi wszystko.

Ale od małych plików, które pracują razem.

Czysta struktura.

Kod wielokrotnego użytku.

Mniej chaosu.

Bardzo Python.

Bardzo profesjonalnie.

Następna lekcja

W następnej lekcji nauczymy się JSON.

JSON to bardzo popularny format danych.

Wygląda bardzo podobnie do słowników i list Pythona.

Nauczysz się zapisywać strukturalne dane takie jak:

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

do pliku.

A potem ładować je później z powrotem.

To bardzo ważne w prawdziwych aplikacjach.

Pliki tekstowe są fajne.

Ale JSON jest lepszy do danych strukturalnych.

Jest używany w API, plikach konfiguracyjnych, aplikacjach webowych i wielu realnych projektach.

Bardzo użyteczne.

Bardzo praktyczne.

Bardzo następny poziom.