We use cookies to enhance your experience on the site
CodeWorlds

Data formats in the jungle

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!

What are data formats?

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!

Most popular formats:

  • JSON - JavaScript Object Notation - most popular in web APIs
  • CSV - Comma-Separated Values - simple, tabular
  • XML - eXtensible Markup Language - structural, extensive
  • YAML - YAML Ain't Markup Language - human-readable, configurations

JSON - JavaScript Object Notation

JSON is the most important data format in the web world - lightweight, readable, universal!

JSON Structure

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
    - number
  • true
    ,
    false
    - boolean
  • null
    - no value
  • [1, 2, 3]
    - array (list)
  • {"key": "value"}
    - object (dictionary)

JSON in Python - the
json
module

Python 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"

Reading and writing JSON files

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

JSON and Python - type mapping

| 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]}

Serializing custom class objects

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 - Comma-Separated Values

CSV is a simple tabular format - perfect for spreadsheets and databases!

CSV Structure

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,forest

Characteristics:

  • First row = column headers
  • Subsequent rows = data
  • Separator: comma (sometimes semicolon, tab)

CSV in Python - the
csv
module

1import 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 individuals

CSV with lists (not dictionaries)

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

Different separators

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 - eXtensible Markup Language

XML is an extensive, structural format - used in enterprise, configurations, and data exchange between systems.

XML Structure

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:

  • Hierarchical tags:
    <tag>value</tag>
  • Attributes:
    <tag attribute="value">
  • Self-closing:
    <tag />
  • More verbose than JSON

XML in Python - the
xml.etree.ElementTree
module

1import 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 - YAML Ain't Markup Language

YAML is a human-readable format - popular in configurations (Docker, Kubernetes, CI/CD)!

YAML Structure

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: 85

Characteristics:

  • Indentation determines hierarchy (like Python!)
  • -
    denotes a list element
  • key: value
    - key-value pairs
  • Very readable

YAML in Python - the
PyYAML
library

1import 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)

Safari example - complete data management system

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 comparison

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

Summary

In this lesson you learned:

  • What data formats are and why we use them
  • JSON -
    json.dumps()
    ,
    json.loads()
    ,
    json.dump()
    ,
    json.load()
  • CSV -
    csv.DictWriter
    ,
    csv.DictReader
    , different separators
  • XML -
    xml.etree.ElementTree
    , creating and parsing
  • YAML -
    yaml.dump()
    ,
    yaml.safe_load()
    , readability
  • Converting objects between formats
  • A practical data export/import system

Checkpoint

Before moving on:

  • [ ] You can read and write JSON
  • [ ] You understand the difference between
    dumps
    and
    dump
  • [ ] You can work with CSV (DictWriter/DictReader)
  • [ ] You know when to use which format
  • [ ] You can convert objects to dictionaries

Safari 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!

Go to CodeWorlds