How to Save Data?

Existing Options

Getting Started

i
bool:True
int:123
i
# input
this is
two lines
i
# output
str:2
this is
two lines

Implementation

i
def save(writer, thing):
    if isinstance(thing, bool):
        print(f"bool:{thing}", file=writer)

    elif isinstance(thing, float):
        print(f"float:{thing}", file=writer)

    elif isinstance(thing, int):
        print(f"int:{thing}", file=writer)

# ...29 lines not shown...
    else:
        raise ValueError(f"unknown type of thing {type(thing)}")

Collections

i
    elif isinstance(thing, list):
        print(f"list:{len(thing)}", file=writer)
        for item in thing:
            save(writer, item)

What This Looks Like

i
save(sys.stdout, [False, 3.14, "hello", {"left": 1, "right": [2, 3]}])
i
list:4
bool:False
float:3.14
str:1
hello
dict:2
str:1
left
int:1
str:1
right
list:2
int:2
int:3

Reading Data

i
def load(reader):
    line = reader.readline()[:-1]
    assert line, "Nothing to read"
    fields = line.split(":", maxsplit=1)
    assert len(fields) == 2, f"Badly-formed line {line}"
    key, value = fields

    if key == "bool":
        names = {"True": True, "False": False}
        assert value in names, f"Unknown Boolean {value}"
        return names[value]

    elif key == "float":
        return float(value)

    elif key == "int":
        return int(value)

# ...20 lines not shown...
    else:
        raise ValueError(f"unknown type of thing {line}")

Reading Multi-line Values

i
    elif key == "list":
        return [load(reader) for _ in range(int(value))]

Open-Closed Principle

Saving

i
class SaveObjects:
    def __init__(self, writer):
        self.writer = writer

    def save(self, thing):
        typename = type(thing).__name__
        method = f"save_{typename}"
        assert hasattr(self, method), \
            f"Unknown object type {typename}"
        getattr(self, method)(thing)

Next Steps

Aliasing

A shared data structure
Figure 1: A shared data structure
i
shared = ["shared"]
fixture = [shared, shared]

Aliasing

Saving

i
    def save(self, thing):
        thing_id = id(thing)
        if thing_id in self.seen:
            self._write("alias", thing_id, "")
            return

        self.seen.add(thing_id)
        typename = type(thing).__name__
        method = f"save_{typename}"
        assert hasattr(self, method), \
            f"Unknown object type {typename}"
        getattr(self, method)(thing)

What It Looks Like

i
word = "word"
child = [word, word]
parent = []
parent.append(parent)
parent.append(child)

saver = SaveAlias(sys.stdout)
saver.save(parent)
i
list:4539747200:2
alias:4539747200:
list:4539552960:2
str:4539552048:1
word
alias:4539552048:

Summary

Concept map of persistence
Figure 2: Concept map.