Welcome to Module 4, @name! Darwin here with a new chapter of our adventure.
So far you've learned Python from the basics to advanced OOP. Now it's time for data flow - how to store, exchange, and transport information between systems, just like animals communicate in the jungle!
In nature, animals convey information in various ways - birds through song, bees through dance, wolves through howling. In the programming world, we use data formats - standardized ways of recording information!
A data format is a standardized way of organizing and recording information that can be read by different systems.
Safari Analogy: It's like a universal communication language - whether you're a biologist from Poland, a scientist from Japan, or a guide from Kenya, you all understand a table with lion population data!
JSON is the most important data format in the web world - lightweight, readable, universal!
1{
2 "species": "Panthera leo",
3 "common_name": "Lion",
4 "population": 120,
5 "endangered": true,
6 "habitats": ["savanna", "steppe"],
7 "last_observation": {
8 "date": "2024-01-15",
9 "location": "Serengeti",
10 "count": 12
11 }
12}Data types in JSON:
"text" - string (always in quotes)123, 45.67 - numbertrue, false - booleannull - no value[1, 2, 3] - array (list){"key": "value"} - object (dictionary)json modulePython has a built-in
json module for working with this format:1import json
2
3# Python → JSON (serialization)
4species_data = {
5 "species": "Panthera leo",
6 "common_name": "Lion",
7 "population": 120,
8 "endangered": True,
9 "habitats": ["savanna", "steppe"],
10 "last_observation": {
11 "date": "2024-01-15",
12 "location": "Serengeti",
13 "count": 12
14 }
15}
16
17# Convert to JSON string
18json_string = json.dumps(species_data, indent=2)
19print(json_string)
20"""
21{
22 "species": "Panthera leo",
23 "common_name": "Lion",
24 "population": 120,
25 "endangered": true,
26 "habitats": [
27 "savanna",
28 "steppe"
29 ],
30 "last_observation": {
31 "date": "2024-01-15",
32 "location": "Serengeti",
33 "count": 12
34 }
35}
36"""
37
38# JSON → Python (deserialization)
39json_text = '{"species": "Loxodonta africana", "population": 450}'
40python_dict = json.loads(json_text)
41print(python_dict["species"]) # "Loxodonta africana"1import json
2
3# Write to file
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# Read from file
17with open("species_data.json", "r", encoding="utf-8") as file:
18 loaded_data = json.load(file)
19 print(loaded_data["species"]) # "Panthera leo"Key difference:
json.dumps() / json.loads() - string (dumps = dump string)json.dump() / json.load() - file| 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]}By default, JSON does not support custom class objects - you need a 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 """Convert to dictionary"""
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 """Restore from dictionary"""
21 return cls(
22 name=data["name"],
23 population=data["population"],
24 last_seen=datetime.fromisoformat(data["last_seen"])
25 )
26
27# Serialization
28lion = Species("Lion", 120, datetime.now())
29json_data = json.dumps(lion.to_dict(), indent=2)
30print(json_data)
31
32# Deserialization
33loaded_dict = json.loads(json_data)
34lion_restored = Species.from_dict(loaded_dict)
35print(lion_restored.name) # "Lion"CSV is a simple tabular format - perfect for spreadsheets and databases!
1species,common_name,population,habitat
2Panthera leo,Lion,120,savanna
3Loxodonta africana,Elephant,450,savanna
4Python regius,Ball Python,85,jungle
5Gorilla gorilla,Gorilla,230,forestCharacteristics:
csv module1import csv
2
3# WRITE CSV
4species_data = [
5 {"species": "Panthera leo", "common_name": "Lion", "population": 120},
6 {"species": "Loxodonta africana", "common_name": "Elephant", "population": 450},
7 {"species": "Python regius", "common_name": "Ball Python", "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() # Write headers
15 writer.writerows(species_data) # Write all rows
16
17# READ 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']} individuals")
23# Lion: 120 individuals
24# Elephant: 450 individuals
25# Ball Python: 85 individuals1import csv
2
3# Write lists
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# Read lists
15with open("species_simple.csv", "r", encoding="utf-8") as file:
16 reader = csv.reader(file)
17 headers = next(reader) # First row = headers
18
19 for row in reader:
20 species, population, endangered = row
21 print(f"{species}: {population}")1import csv
2
3# Separator: semicolon (popular in Europe)
4with open("data_eu.csv", "w", newline="", encoding="utf-8") as file:
5 writer = csv.writer(file, delimiter=";")
6 writer.writerow(["species", "population"])
7 writer.writerow(["Lion", "120"])
8
9# Separator: tab
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 is an extensive, structural format - used in enterprise, configurations, and data exchange between systems.
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>Lion</common_name>
6 <population>120</population>
7 <habitats>
8 <habitat>savanna</habitat>
9 <habitat>steppe</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>Characteristics:
<tag>value</tag><tag attribute="value"><tag />xml.etree.ElementTree module1import xml.etree.ElementTree as ET
2
3# CREATING XML
4root = ET.Element("species_catalog")
5
6# Add a species
7species = ET.SubElement(root, "species")
8species.set("endangered", "true") # Attribute
9
10ET.SubElement(species, "scientific_name").text = "Panthera leo"
11ET.SubElement(species, "common_name").text = "Lion"
12ET.SubElement(species, "population").text = "120"
13
14# Habitats
15habitats = ET.SubElement(species, "habitats")
16ET.SubElement(habitats, "habitat").text = "savanna"
17ET.SubElement(habitats, "habitat").text = "steppe"
18
19# Write to file
20tree = ET.ElementTree(root)
21ET.indent(tree, space=" ") # Python 3.9+ - formatting
22tree.write("species.xml", encoding="utf-8", xml_declaration=True)
23
24# READING 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") # Attribute
32
33 print(f"{name}: {population} individuals (endangered: {endangered})")
34
35 # Habitats
36 habitats = species.find("habitats")
37 for habitat in habitats.findall("habitat"):
38 print(f" - {habitat.text}")YAML is a human-readable format - popular in configurations (Docker, Kubernetes, CI/CD)!
1# Comment in YAML
2species:
3 scientific_name: Panthera leo
4 common_name: Lion
5 population: 120
6 endangered: true
7 habitats:
8 - savanna
9 - steppe
10 last_observation:
11 date: 2024-01-15
12 location: Serengeti
13 count: 12
14
15# List of species
16all_species:
17 - name: Lion
18 population: 120
19 - name: Elephant
20 population: 450
21 - name: Ball Python
22 population: 85Characteristics:
- denotes a list elementkey: value - key-value pairsPyYAML library1import yaml
2
3# Installation: pip install pyyaml
4
5# Python → YAML
6species_data = {
7 "species": "Panthera leo",
8 "common_name": "Lion",
9 "population": 120,
10 "endangered": True,
11 "habitats": ["savanna", "steppe"],
12 "last_observation": {
13 "date": "2024-01-15",
14 "location": "Serengeti",
15 "count": 12
16 }
17}
18
19# Convert to 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# File read/write
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 """Species class with export to various formats"""
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 """Add an observation"""
21 self.observations.append({
22 "date": date,
23 "location": location,
24 "count": count
25 })
26
27 # === EXPORT TO JSON ===
28
29 def to_json_dict(self) -> dict:
30 """Convert to dictionary for 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 """Restore from JSON dictionary"""
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 # === EXPORT TO CSV ===
54
55 def to_csv_row(self) -> dict:
56 """Convert to CSV row (simplified - without observations)"""
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 # === EXPORT TO XML ===
66
67 def to_xml_element(self) -> ET.Element:
68 """Convert to XML element"""
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 """Species database with export to various formats"""
94
95 def __init__(self):
96 self.species: List[Species] = []
97
98 def add_species(self, species: Species):
99 """Add a species"""
100 self.species.append(species)
101
102 # === JSON ===
103
104 def export_json(self, filename: str):
105 """Export to 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"Exported {len(self.species)} species to {filename}")
116
117 def import_json(self, filename: str):
118 """Import from 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"Imported {len(self.species)} species from {filename}")
127
128 # === CSV ===
129
130 def export_csv(self, filename: str):
131 """Export to CSV"""
132 if not self.species:
133 print("No species to export")
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"Exported {len(self.species)} species to {filename}")
146
147 def import_csv(self, filename: str):
148 """Import from 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"Imported {len(self.species)} species from {filename}")
165
166 # === XML ===
167
168 def export_xml(self, filename: str):
169 """Export to 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"Exported {len(self.species)} species to {filename}")
182
183 def list_species(self):
184 """Display all species"""
185 print(f"\n=== SPECIES DATABASE ({len(self.species)}) ===")
186 for i, species in enumerate(self.species, 1):
187 status = "Warning: Endangered" if species.endangered else "Safe"
188 print(f"{i}. {species.common_name} ({species.scientific_name})")
189 print(f" Population: {species.population}, Habitat: {species.habitat}, Status: {status}")
190
191
192# === DEMONSTRATION ===
193
194print("=== SAFARI DATA MANAGEMENT SYSTEM ===\n")
195
196# Create database
197db = SpeciesDatabase()
198
199# Add species
200lion = Species("Panthera leo", "Lion", 120, "savanna", endangered=True)
201lion.add_observation("2024-01-15", "Serengeti", 12)
202lion.add_observation("2024-01-20", "Masai Mara", 8)
203
204elephant = Species("Loxodonta africana", "African Elephant", 450, "savanna", endangered=True)
205elephant.add_observation("2024-01-16", "Amboseli", 35)
206
207python_snake = Species("Python regius", "Ball Python", 85, "jungle", endangered=False)
208
209db.add_species(lion)
210db.add_species(elephant)
211db.add_species(python_snake)
212
213# Display data
214db.list_species()
215
216# EXPORT to various formats
217print("\n=== EXPORT ===")
218db.export_json("safari_data.json")
219db.export_csv("safari_data.csv")
220db.export_xml("safari_data.xml")
221
222# IMPORT from JSON
223print("\n=== IMPORT FROM JSON ===")
224db2 = SpeciesDatabase()
225db2.import_json("safari_data.json")
226db2.list_species()
227
228# IMPORT from CSV
229print("\n=== IMPORT FROM CSV ===")
230db3 = SpeciesDatabase()
231db3.import_csv("safari_data.csv")
232db3.list_species()
233
234print("\nAll formats work correctly!")| Format | Pros | Cons | Usage | |--------|------|------|-------| | JSON | Lightweight, readable, universal in web | No comments | Web APIs, configs, data exchange | | CSV | Simple, Excel-friendly, small size | Tables only, no hierarchy | Tabular data, spreadsheet export/import | | XML | Structural, schema validation | Verbose, more complex | Enterprise, SOAP, legacy systems | | YAML | Very readable, supports comments | Sensitive to indentation | Configurations (Docker, K8s, CI/CD) |
In this lesson you learned:
json.dumps(), json.loads(), json.dump(), json.load()csv.DictWriter, csv.DictReader, different separatorsxml.etree.ElementTree, creating and parsingyaml.dump(), yaml.safe_load(), readabilityBefore moving on:
dumps and dumpSafari Analogy: Data formats are universal communication languages - just as biologists from different countries use Latin species names, programmers use JSON/CSV/XML to exchange data!
In the next lesson, Darwin will teach you HTTP and requests - how to fetch data from the internet and communicate with APIs!