Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Formaty danych w dżungli

Witaj w Module 4, @name! Darwin tutaj z nowym rozdziałem naszej przygody.

Do tej pory poznałeś/aś Python od podstaw do zaawansowanego OOP. Teraz czas na przepływ danych - jak przechowywać, wymieniać i transportować informacje między systemami, jak zwierzęta komunikują się w dżungli!

W naturze zwierzęta przekazują informacje na różne sposoby - ptaki śpiewem, pszczoły tańcem, wilki wyciem. W świecie programowania używamy formatów danych - standardowych sposobów zapisu informacji!

Czym są formaty danych?

Format danych to ustandaryzowany sposób organizacji i zapisu informacji, który mogą odczytać różne systemy.

Analogia Safari: To jak uniwersalny język komunikacji - niezależnie czy jesteś biologiem z Polski, naukowcem z Japonii czy przewodnikiem z Kenii, wszyscy rozumiecie tabelę z danymi o populacji lwów!

Najpopularniejsze formaty:

  • JSON - JavaScript Object Notation - najpopularniejszy w web API
  • CSV - Comma-Separated Values - prosty, tabelaryczny
  • XML - eXtensible Markup Language - strukturalny, rozbudowany
  • YAML - YAML Ain't Markup Language - czytelny dla ludzi, konfiguracje

JSON - JavaScript Object Notation

JSON to najważniejszy format danych w świecie web - lekki, czytelny, uniwersalny!

Struktura JSON

1{
2  "species": "Panthera leo",
3  "common_name": "Lew",
4  "population": 120,
5  "endangered": true,
6  "habitats": ["sawanna", "step"],
7  "last_observation": {
8    "date": "2024-01-15",
9    "location": "Serengeti",
10    "count": 12
11  }
12}

Typy danych w JSON:

  • "tekst"
    - string (zawsze w cudzysłowach)
  • 123
    ,
    45.67
    - number
  • true
    ,
    false
    - boolean
  • null
    - brak wartości
  • [1, 2, 3]
    - array (lista)
  • {"key": "value"}
    - object (słownik)

JSON w Pythonie - moduł
json

Python ma wbudowany moduł

json
do pracy z tym formatem:

1import json
2
3# Python → JSON (serializacja)
4species_data = {
5    "species": "Panthera leo",
6    "common_name": "Lew",
7    "population": 120,
8    "endangered": True,
9    "habitats": ["sawanna", "step"],
10    "last_observation": {
11        "date": "2024-01-15",
12        "location": "Serengeti",
13        "count": 12
14    }
15}
16
17# Konwersja do JSON string
18json_string = json.dumps(species_data, indent=2)
19print(json_string)
20"""
21{
22  "species": "Panthera leo",
23  "common_name": "Lew",
24  "population": 120,
25  "endangered": true,
26  "habitats": [
27    "sawanna",
28    "step"
29  ],
30  "last_observation": {
31    "date": "2024-01-15",
32    "location": "Serengeti",
33    "count": 12
34  }
35}
36"""
37
38# JSON → Python (deserializacja)
39json_text = '{"species": "Loxodonta africana", "population": 450}'
40python_dict = json.loads(json_text)
41print(python_dict["species"])  # "Loxodonta africana"

Zapis i odczyt plików JSON

1import json
2
3# Zapis do pliku
4species_data = {
5    "species": "Panthera leo",
6    "population": 120,
7    "observations": [
8        {"date": "2024-01-15", "count": 12},
9        {"date": "2024-01-20", "count": 8}
10    ]
11}
12
13with open("species_data.json", "w", encoding="utf-8") as file:
14    json.dump(species_data, file, indent=2, ensure_ascii=False)
15
16# Odczyt z pliku
17with open("species_data.json", "r", encoding="utf-8") as file:
18    loaded_data = json.load(file)
19    print(loaded_data["species"])  # "Panthera leo"

Różnica:

  • json.dumps()
    /
    json.loads()
    - string (dumps = dump string)
  • json.dump()
    /
    json.load()
    - plik

JSON i Python - mapowanie typów

| Python | JSON | |--------|------| |

dict
|
object
| |
list
,
tuple
|
array
| |
str
|
string
| |
int
,
float
|
number
| |
True
|
true
| |
False
|
false
| |
None
|
null
|

1import json
2
3# Python → JSON
4python_data = {
5    "name": "Darwin",
6    "age": None,
7    "active": True,
8    "coordinates": (51.5, -0.1)  # Tuple → array
9}
10
11json_str = json.dumps(python_data)
12print(json_str)
13# {"name": "Darwin", "age": null, "active": true, "coordinates": [51.5, -0.1]}

Serializacja obiektów własnych klas

Domyślnie JSON nie obsługuje obiektów własnych klas - potrzebujesz custom encoder:

1import json
2from datetime import datetime
3
4class Species:
5    def __init__(self, name, population, last_seen):
6        self.name = name
7        self.population = population
8        self.last_seen = last_seen  # datetime object
9
10    def to_dict(self):
11        """Konwersja do słownika"""
12        return {
13            "name": self.name,
14            "population": self.population,
15            "last_seen": self.last_seen.isoformat()  # datetime → string
16        }
17
18    @classmethod
19    def from_dict(cls, data):
20        """Odtworzenie z słownika"""
21        return cls(
22            name=data["name"],
23            population=data["population"],
24            last_seen=datetime.fromisoformat(data["last_seen"])
25        )
26
27# Serializacja
28lion = Species("Lew", 120, datetime.now())
29json_data = json.dumps(lion.to_dict(), indent=2)
30print(json_data)
31
32# Deserializacja
33loaded_dict = json.loads(json_data)
34lion_restored = Species.from_dict(loaded_dict)
35print(lion_restored.name)  # "Lew"

CSV - Comma-Separated Values

CSV to prosty format tabelaryczny - doskonały do arkuszy kalkulacyjnych i baz danych!

Struktura CSV

1species,common_name,population,habitat
2Panthera leo,Lew,120,sawanna
3Loxodonta africana,Słoń,450,sawanna
4Python regius,Pyton,85,dżungla
5Gorilla gorilla,Goryl,230,las

Cechy:

  • Pierwszy wiersz = nagłówki kolumn
  • Kolejne wiersze = dane
  • Separator: przecinek (czasem średnik, tabulator)

CSV w Pythonie - moduł
csv

1import csv
2
3# ZAPIS CSV
4species_data = [
5    {"species": "Panthera leo", "common_name": "Lew", "population": 120},
6    {"species": "Loxodonta africana", "common_name": "Słoń", "population": 450},
7    {"species": "Python regius", "common_name": "Pyton", "population": 85}
8]
9
10with open("species.csv", "w", newline="", encoding="utf-8") as file:
11    fieldnames = ["species", "common_name", "population"]
12    writer = csv.DictWriter(file, fieldnames=fieldnames)
13
14    writer.writeheader()  # Zapisz nagłówki
15    writer.writerows(species_data)  # Zapisz wszystkie wiersze
16
17# ODCZYT CSV
18with open("species.csv", "r", encoding="utf-8") as file:
19    reader = csv.DictReader(file)
20
21    for row in reader:
22        print(f"{row['common_name']}: {row['population']} osobników")
23# Lew: 120 osobników
24# Słoń: 450 osobników
25# Pyton: 85 osobników

CSV z listami (nie słownikami)

1import csv
2
3# Zapis list
4data = [
5    ["species", "population", "endangered"],
6    ["Panthera leo", 120, "True"],
7    ["Loxodonta africana", 450, "True"]
8]
9
10with open("species_simple.csv", "w", newline="", encoding="utf-8") as file:
11    writer = csv.writer(file)
12    writer.writerows(data)
13
14# Odczyt list
15with open("species_simple.csv", "r", encoding="utf-8") as file:
16    reader = csv.reader(file)
17    headers = next(reader)  # Pierwszy wiersz = nagłówki
18
19    for row in reader:
20        species, population, endangered = row
21        print(f"{species}: {population}")

Różne separatory

1import csv
2
3# Separator: średnik (popularne w Polsce/Europie)
4with open("data_pl.csv", "w", newline="", encoding="utf-8") as file:
5    writer = csv.writer(file, delimiter=";")
6    writer.writerow(["gatunek", "populacja"])
7    writer.writerow(["Lew", "120"])
8
9# Separator: tabulator
10with open("data_tab.tsv", "w", newline="", encoding="utf-8") as file:
11    writer = csv.writer(file, delimiter="\t")
12    writer.writerow(["species", "population"])
13    writer.writerow(["Lion", "120"])

XML - eXtensible Markup Language

XML to rozbudowany, strukturalny format - używany w enterprise, konfiguracjach, wymianie danych między systemami.

Struktura XML

1<?xml version="1.0" encoding="UTF-8"?>
2<species_catalog>
3    <species endangered="true">
4        <scientific_name>Panthera leo</scientific_name>
5        <common_name>Lew</common_name>
6        <population>120</population>
7        <habitats>
8            <habitat>sawanna</habitat>
9            <habitat>step</habitat>
10        </habitats>
11        <observations>
12            <observation>
13                <date>2024-01-15</date>
14                <location>Serengeti</location>
15                <count>12</count>
16            </observation>
17        </observations>
18    </species>
19</species_catalog>

Cechy:

  • Tagi hierarchiczne:
    <tag>wartość</tag>
  • Atrybuty:
    <tag attribute="value">
  • Samozamykające:
    <tag />
  • Bardziej gadatliwy niż JSON

XML w Pythonie - moduł
xml.etree.ElementTree

1import xml.etree.ElementTree as ET
2
3# TWORZENIE XML
4root = ET.Element("species_catalog")
5
6# Dodaj gatunek
7species = ET.SubElement(root, "species")
8species.set("endangered", "true")  # Atrybut
9
10ET.SubElement(species, "scientific_name").text = "Panthera leo"
11ET.SubElement(species, "common_name").text = "Lew"
12ET.SubElement(species, "population").text = "120"
13
14# Habitats
15habitats = ET.SubElement(species, "habitats")
16ET.SubElement(habitats, "habitat").text = "sawanna"
17ET.SubElement(habitats, "habitat").text = "step"
18
19# Zapis do pliku
20tree = ET.ElementTree(root)
21ET.indent(tree, space="  ")  # Python 3.9+ - formatowanie
22tree.write("species.xml", encoding="utf-8", xml_declaration=True)
23
24# ODCZYT XML
25tree = ET.parse("species.xml")
26root = tree.getroot()
27
28for species in root.findall("species"):
29    name = species.find("common_name").text
30    population = species.find("population").text
31    endangered = species.get("endangered")  # Atrybut
32
33    print(f"{name}: {population} osobników (zagrożony: {endangered})")
34
35    # Habitats
36    habitats = species.find("habitats")
37    for habitat in habitats.findall("habitat"):
38        print(f"  - {habitat.text}")

YAML - YAML Ain't Markup Language

YAML to czytelny dla ludzi format - popularny w konfiguracjach (Docker, Kubernetes, CI/CD)!

Struktura YAML

1# Komentarz w YAML
2species:
3  scientific_name: Panthera leo
4  common_name: Lew
5  population: 120
6  endangered: true
7  habitats:
8    - sawanna
9    - step
10  last_observation:
11    date: 2024-01-15
12    location: Serengeti
13    count: 12
14
15# Lista gatunków
16all_species:
17  - name: Lew
18    population: 120
19  - name: Słoń
20    population: 450
21  - name: Pyton
22    population: 85

Cechy:

  • Wcięcia określają hierarchię (jak Python!)
  • -
    oznacza element listy
  • key: value
    - pary klucz-wartość
  • Bardzo czytelny

YAML w Pythonie - biblioteka
PyYAML

1import yaml
2
3# Instalacja: pip install pyyaml
4
5# Python → YAML
6species_data = {
7    "species": "Panthera leo",
8    "common_name": "Lew",
9    "population": 120,
10    "endangered": True,
11    "habitats": ["sawanna", "step"],
12    "last_observation": {
13        "date": "2024-01-15",
14        "location": "Serengeti",
15        "count": 12
16    }
17}
18
19# Konwersja do YAML string
20yaml_string = yaml.dump(species_data, default_flow_style=False, allow_unicode=True)
21print(yaml_string)
22
23# YAML → Python
24yaml_text = """
25species: Loxodonta africana
26population: 450
27endangered: true
28"""
29
30python_dict = yaml.safe_load(yaml_text)
31print(python_dict["species"])  # "Loxodonta africana"
32
33# Zapis/odczyt plików
34with open("config.yaml", "w", encoding="utf-8") as file:
35    yaml.dump(species_data, file, default_flow_style=False, allow_unicode=True)
36
37with open("config.yaml", "r", encoding="utf-8") as file:
38    loaded_data = yaml.safe_load(file)

Safari przykład - kompletny system zarządzania danymi

1import json
2import csv
3import xml.etree.ElementTree as ET
4from datetime import datetime
5from typing import List, Dict, Any
6
7class Species:
8    """Klasa gatunku z eksportem do różnych formatów"""
9
10    def __init__(self, scientific_name: str, common_name: str,
11                 population: int, habitat: str, endangered: bool = False):
12        self.scientific_name = scientific_name
13        self.common_name = common_name
14        self.population = population
15        self.habitat = habitat
16        self.endangered = endangered
17        self.observations: List[Dict[str, Any]] = []
18
19    def add_observation(self, date: str, location: str, count: int):
20        """Dodaj obserwację"""
21        self.observations.append({
22            "date": date,
23            "location": location,
24            "count": count
25        })
26
27    # === EKSPORT DO JSON ===
28
29    def to_json_dict(self) -> dict:
30        """Konwersja do słownika dla JSON"""
31        return {
32            "scientific_name": self.scientific_name,
33            "common_name": self.common_name,
34            "population": self.population,
35            "habitat": self.habitat,
36            "endangered": self.endangered,
37            "observations": self.observations
38        }
39
40    @classmethod
41    def from_json_dict(cls, data: dict) -> 'Species':
42        """Odtworzenie z słownika JSON"""
43        species = cls(
44            scientific_name=data["scientific_name"],
45            common_name=data["common_name"],
46            population=data["population"],
47            habitat=data["habitat"],
48            endangered=data.get("endangered", False)
49        )
50        species.observations = data.get("observations", [])
51        return species
52
53    # === EKSPORT DO CSV ===
54
55    def to_csv_row(self) -> dict:
56        """Konwersja do wiersza CSV (uproszczone - bez obserwacji)"""
57        return {
58            "scientific_name": self.scientific_name,
59            "common_name": self.common_name,
60            "population": self.population,
61            "habitat": self.habitat,
62            "endangered": "Yes" if self.endangered else "No"
63        }
64
65    # === EKSPORT DO XML ===
66
67    def to_xml_element(self) -> ET.Element:
68        """Konwersja do elementu XML"""
69        species_elem = ET.Element("species")
70        species_elem.set("endangered", str(self.endangered).lower())
71
72        ET.SubElement(species_elem, "scientific_name").text = self.scientific_name
73        ET.SubElement(species_elem, "common_name").text = self.common_name
74        ET.SubElement(species_elem, "population").text = str(self.population)
75        ET.SubElement(species_elem, "habitat").text = self.habitat
76
77        # Observations
78        if self.observations:
79            obs_elem = ET.SubElement(species_elem, "observations")
80            for obs in self.observations:
81                obs_item = ET.SubElement(obs_elem, "observation")
82                ET.SubElement(obs_item, "date").text = obs["date"]
83                ET.SubElement(obs_item, "location").text = obs["location"]
84                ET.SubElement(obs_item, "count").text = str(obs["count"])
85
86        return species_elem
87
88    def __repr__(self) -> str:
89        return f"Species('{self.common_name}', pop={self.population})"
90
91
92class SpeciesDatabase:
93    """Baza danych gatunków z eksportem do różnych formatów"""
94
95    def __init__(self):
96        self.species: List[Species] = []
97
98    def add_species(self, species: Species):
99        """Dodaj gatunek"""
100        self.species.append(species)
101
102    # === JSON ===
103
104    def export_json(self, filename: str):
105        """Eksport do JSON"""
106        data = {
107            "export_date": datetime.now().isoformat(),
108            "species_count": len(self.species),
109            "species": [s.to_json_dict() for s in self.species]
110        }
111
112        with open(filename, "w", encoding="utf-8") as file:
113            json.dump(data, file, indent=2, ensure_ascii=False)
114
115        print(f"✓ Wyeksportowano {len(self.species)} gatunków do {filename}")
116
117    def import_json(self, filename: str):
118        """Import z JSON"""
119        with open(filename, "r", encoding="utf-8") as file:
120            data = json.load(file)
121
122        self.species.clear()
123        for species_data in data["species"]:
124            self.species.append(Species.from_json_dict(species_data))
125
126        print(f"✓ Zaimportowano {len(self.species)} gatunków z {filename}")
127
128    # === CSV ===
129
130    def export_csv(self, filename: str):
131        """Eksport do CSV"""
132        if not self.species:
133            print("Brak gatunków do eksportu")
134            return
135
136        fieldnames = ["scientific_name", "common_name", "population", "habitat", "endangered"]
137
138        with open(filename, "w", newline="", encoding="utf-8") as file:
139            writer = csv.DictWriter(file, fieldnames=fieldnames)
140            writer.writeheader()
141
142            for species in self.species:
143                writer.writerow(species.to_csv_row())
144
145        print(f"✓ Wyeksportowano {len(self.species)} gatunków do {filename}")
146
147    def import_csv(self, filename: str):
148        """Import z CSV"""
149        self.species.clear()
150
151        with open(filename, "r", encoding="utf-8") as file:
152            reader = csv.DictReader(file)
153
154            for row in reader:
155                species = Species(
156                    scientific_name=row["scientific_name"],
157                    common_name=row["common_name"],
158                    population=int(row["population"]),
159                    habitat=row["habitat"],
160                    endangered=(row["endangered"].lower() == "yes")
161                )
162                self.species.append(species)
163
164        print(f"✓ Zaimportowano {len(self.species)} gatunków z {filename}")
165
166    # === XML ===
167
168    def export_xml(self, filename: str):
169        """Eksport do XML"""
170        root = ET.Element("species_database")
171        root.set("export_date", datetime.now().isoformat())
172        root.set("species_count", str(len(self.species)))
173
174        for species in self.species:
175            root.append(species.to_xml_element())
176
177        tree = ET.ElementTree(root)
178        ET.indent(tree, space="  ")
179        tree.write(filename, encoding="utf-8", xml_declaration=True)
180
181        print(f"✓ Wyeksportowano {len(self.species)} gatunków do {filename}")
182
183    def list_species(self):
184        """Wyświetl wszystkie gatunki"""
185        print(f"\n=== BAZA GATUNKÓW ({len(self.species)}) ===")
186        for i, species in enumerate(self.species, 1):
187            status = "⚠️ Zagrożony" if species.endangered else "✓ Bezpieczny"
188            print(f"{i}. {species.common_name} ({species.scientific_name})")
189            print(f"   Populacja: {species.population}, Siedlisko: {species.habitat}, Status: {status}")
190
191
192# === DEMONSTRACJA ===
193
194print("=== SYSTEM ZARZĄDZANIA DANYMI SAFARI ===\n")
195
196# Tworzenie bazy danych
197db = SpeciesDatabase()
198
199# Dodaj gatunki
200lion = Species("Panthera leo", "Lew", 120, "sawanna", endangered=True)
201lion.add_observation("2024-01-15", "Serengeti", 12)
202lion.add_observation("2024-01-20", "Masai Mara", 8)
203
204elephant = Species("Loxodonta africana", "Słoń afrykański", 450, "sawanna", endangered=True)
205elephant.add_observation("2024-01-16", "Amboseli", 35)
206
207python_snake = Species("Python regius", "Pyton królewski", 85, "dżungla", endangered=False)
208
209db.add_species(lion)
210db.add_species(elephant)
211db.add_species(python_snake)
212
213# Wyświetl dane
214db.list_species()
215
216# EKSPORT do różnych formatów
217print("\n=== EKSPORT ===")
218db.export_json("safari_data.json")
219db.export_csv("safari_data.csv")
220db.export_xml("safari_data.xml")
221
222# IMPORT z JSON
223print("\n=== IMPORT Z JSON ===")
224db2 = SpeciesDatabase()
225db2.import_json("safari_data.json")
226db2.list_species()
227
228# IMPORT z CSV
229print("\n=== IMPORT Z CSV ===")
230db3 = SpeciesDatabase()
231db3.import_csv("safari_data.csv")
232db3.list_species()
233
234print("\n✓ Wszystkie formaty działają!")

Porównanie formatów

| Format | Zalety | Wady | Użycie | |--------|--------|------|--------| | JSON | Lekki, czytelny, uniwersalny w web | Brak komentarzy | Web API, konfiguracje, wymiana danych | | CSV | Prosty, excel-friendly, mało miejsca | Tylko tabele, brak hierarchii | Dane tabelaryczne, eksport/import do arkuszy | | XML | Strukturalny, walidacja schematami | Gadatliwy, trudniejszy | Enterprise, SOAP, legacy systems | | YAML | Bardzo czytelny, komentarze | Wrażliwy na wcięcia | Konfiguracje (Docker, K8s, CI/CD) |

Podsumowanie

W tej lekcji nauczyłeś/aś się:

  • ✅ Czym są formaty danych i po co ich używać
  • ✅ JSON -
    json.dumps()
    ,
    json.loads()
    ,
    json.dump()
    ,
    json.load()
  • ✅ CSV -
    csv.DictWriter
    ,
    csv.DictReader
    , różne separatory
  • ✅ XML -
    xml.etree.ElementTree
    , tworzenie i parsowanie
  • ✅ YAML -
    yaml.dump()
    ,
    yaml.safe_load()
    , czytelność
  • ✅ Konwersji obiektów między formatami
  • ✅ Praktycznego systemu eksportu/importu danych

Checkpoint

Przed przejściem dalej:

  • [ ] Potrafisz zapisać i odczytać JSON
  • [ ] Rozumiesz różnicę między
    dumps
    a
    dump
  • [ ] Potrafisz pracować z CSV (DictWriter/DictReader)
  • [ ] Wiesz kiedy używać którego formatu
  • [ ] Potrafisz konwertować obiekty do słowników

Analogia Safari: Formaty danych to uniwersalne języki komunikacji - jak biologowie z różnych krajów używają łacińskich nazw gatunków, programiści używają JSON/CSV/XML do wymiany danych! 📊🌍

W następnej lekcji Darwin nauczy Cię HTTP i requests - jak pobierać dane z internetu i komunikować się z API! 🌐📡

Vai a CodeWorlds