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!
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!
JSON to najważniejszy format danych w świecie web - lekki, czytelny, uniwersalny!
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 - numbertrue, false - booleannull - brak wartości[1, 2, 3] - array (lista){"key": "value"} - object (słownik)jsonPython 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"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| 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]}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 to prosty format tabelaryczny - doskonały do arkuszy kalkulacyjnych i baz danych!
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,lasCechy:
csv1import 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ów1import 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}")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 to rozbudowany, strukturalny format - używany w enterprise, konfiguracjach, wymianie danych między systemami.
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:
<tag>wartość</tag><tag attribute="value"><tag />xml.etree.ElementTree1import 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 to czytelny dla ludzi format - popularny w konfiguracjach (Docker, Kubernetes, CI/CD)!
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: 85Cechy:
- oznacza element listykey: value - pary klucz-wartośćPyYAML1import 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)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ą!")| 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) |
W tej lekcji nauczyłeś/aś się:
json.dumps(), json.loads(), json.dump(), json.load()csv.DictWriter, csv.DictReader, różne separatoryxml.etree.ElementTree, tworzenie i parsowanieyaml.dump(), yaml.safe_load(), czytelnośćPrzed przejściem dalej:
dumps a dumpAnalogia 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! 🌐📡