Table of Contents
Introduction
Why Python Classes Replace C-Style Structs
Data Classes: The Modern Way to Model Data
Real-World Scenario: Managing IoT Sensor Readings in Smart Agriculture
Implementation with Error Handling and Validation
Best Practices for Custom Data Structures
Conclusion
Introduction
In C and C++, developers often use struct with typedef to bundle related data into a single unit—like a SensorReading containing temperature, humidity, and timestamp. Python doesn’t have structs, but it offers something far more powerful: classes. And since Python 3.7, data classes make this even cleaner, safer, and more maintainable.
This article shows how to model real-world data using Python classes—using a timely, real-life example from smart agriculture, where every sensor byte counts.
Why Python Classes Replace C-Style Structs
While C structs are passive containers, Python classes are active, extensible, and support methods, validation, and inheritance. You can:
Bundle data and behavior
Enforce data integrity
Add logging, conversion, or serialization logic
Easily integrate with modern frameworks (FastAPI, Pydantic, ORMs)
For pure data containers, data classes eliminate boilerplate while keeping all these advantages.
Data Classes: The Modern Way to Model Data
Introduced in Python 3.7 via @dataclass, they auto-generate __init__, __repr__, __eq__, and more:
from dataclasses import dataclass
from datetime import datetime
@dataclass
class SensorReading:
device_id: str
temperature: float
humidity: float
timestamp: datetimeThat’s it—no manual __init__ needed. You get a clean, typed, readable data structure instantly.
Real-World Scenario: Managing IoT Sensor Readings in Smart Agriculture
Problem: A farm uses 500+ soil sensors across fields. Each sensor reports:
Device ID (e.g.,
"FIELD-A-042")Soil temperature (°C)
Moisture level (%)
Timestamp (UTC)
These readings stream into a backend every 10 minutes. Engineers need to:
Validate incoming data
Reject outliers (e.g., humidity > 100%)
Serialize to JSON for dashboards
Compare readings for anomaly detection
A naive dictionary won’t cut it. We need a robust, self-validating data structure.
Implementation with Error Handling and Validation
Here’s a production-ready SensorReading class using data classes and custom validation:
from dataclasses import dataclass
from datetime import datetime
import json
@dataclass
class SensorReading:
device_id: str
temperature: float
humidity: float
timestamp: datetime
def __post_init__(self):
# Validate after initialization
if not self.device_id or not isinstance(self.device_id, str):
raise ValueError("device_id must be a non-empty string")
if not (-50 <= self.temperature <= 80):
raise ValueError("Temperature out of realistic range [-50°C, 80°C]")
if not (0 <= self.humidity <= 100):
raise ValueError("Humidity must be between 0% and 100%")
if not isinstance(self.timestamp, datetime):
raise TypeError("timestamp must be a datetime object")
def to_json(self) -> str:
"""Serialize to JSON-compatible format"""
return json.dumps({
"device_id": self.device_id,
"temperature": round(self.temperature, 2),
"humidity": round(self.humidity, 2),
"timestamp": self.timestamp.isoformat()
})
@classmethod
def from_dict(cls, data: dict):
"""Create instance from dictionary (e.g., from API or MQTT)"""
return cls(
device_id=data["device_id"],
temperature=float(data["temperature"]),
humidity=float(data["humidity"]),
timestamp=datetime.fromisoformat(data["timestamp"])
)

Comments
Join the conversation! Your thoughts help the community grow.