Python from First PrinciplesPost 14 of 20 · 20 of 20 written
- How to use this guide
- 01What Python actually is
- 02Names, objects and references
- 03Built-in types and what they cost
- 04Control flow and expressions
- 05Functions in depth
- 06Iteration and generators
- 07Classes and the data model
- 08Context managers and exceptions
- 09Modules, packages, imports and environments
- 10Type hints and Pydantic
- 11The performance model
- 12Concurrency and parallelism
- 13NumPy: the array model everything else copies
- 14Data and serialization
- 15PyTorch mental model
- 16AI systems engineering in Python
- 17Tooling, debugging and testing
- 18Asking the right questions
- 19Roadmap and build-to-learn projects
- 20Glossary and resources
14. Data and serialization
Python · 14 of 202 min readOct 2026
Python · Post 14 of 202 min readOct 2026
Choose data formats by who reads them and whether the source can be trusted: text formats for interchange, columnar formats for analytics, safe tensor formats for weights. Never deserialize a pickle you did not create.
Formats at a glance
| Format | Good for | Watch out for |
|---|---|---|
| JSON | API payloads, configs, LLM input and output | no NaN or infinity in strict JSON; tuples come back as lists |
| JSONL | datasets, logs, eval results (one record per line) | none serious; stream it and append safely |
| CSV | quick tables, spreadsheet exchange | no types; quoting and encoding problems |
| Parquet | large typed tables, columnar and compressed | binary; read with pyarrow, polars or pandas |
| YAML, TOML | human-edited configuration | YAML needs yaml.safe_load, never plain load |
| pickle | Python objects between trusted Python processes | runs code when loaded: never load untrusted files |
| safetensors | model weights | none serious; safe, fast and memory-mappable |
.pt / .bin from torch.save |
PyTorch checkpoints | pickle underneath; load with weights_only=True |
.npy / .npz |
NumPy arrays | none serious; simple and fast |
Why pickle is dangerous
Unpickling can call arbitrary functions while reconstructing objects. A malicious file can therefore run code on your machine the moment you load it. That is why model hubs moved to safetensors and why recent PyTorch versions default torch.load to weights_only=True.
pandas, polars and DuckDB
- pandas: a DataFrame is a set of named columns, each backed by an array, aligned on an index. Use column operations;
df.apply(fn, axis=1)is a Python loop in disguise. - pandas assignment: chained assignment warnings come from the view-versus-copy question (Part 13). Write
df.loc[mask, "col"] = value, and know that pandas is moving to copy-on-write semantics. - polars: a Rust engine on Arrow memory, multi-threaded, with a lazy query optimizer:
pl.scan_parquet(path).filter(...).collect(). It is often much faster on large data and uses an expression API instead of an index. - DuckDB: in-process SQL that queries Parquet, CSV and DataFrames directly. Excellent for exploration.
- Hugging Face
datasets: Arrow-backed, memory-mapped datasets withmapand a streaming mode for corpora too large for disk.
Files and paths
- Use
pathlib.Path:Path("data") / "train.jsonl",.exists(),.glob("*.parquet"),.read_text(encoding="utf-8"). - Write important outputs atomically: write to a temporary file, then
os.replace(tmp, final). A crash then never leaves a half-written checkpoint behind. - Memory-map huge arrays with
np.load(path, mmap_mode="r")so only the parts you touch are read.
JSON in practice
import json
record = {"id": 1, "text": "Grüße aus Bonn", "score": 0.93}
line = json.dumps(record, ensure_ascii=False) # keeps umlauts readable
back = json.loads(line)- The standard
jsonmodule cannot serializedatetime, NumPy numbers or sets. Convert them first, or use Pydantic’smodel_dump_json(). - Model output that “is JSON” often arrives wrapped in prose or code fences. Prefer the API’s structured-output feature over regex extraction, and always validate (Part 10).
Questions to ask:
- Can this file be trusted enough to deserialize?
- Is this DataFrame operation vectorized, or a hidden Python loop?
- What happens if the job dies halfway through writing?