Behold the Dictionary Dispatch Monster

A function that receives a payload and converts it to any file format imaginable.

Behold the Dictionary Dispatch Monster
Created with https://openai.com/dall-e-2

Well, well, well, what do we have here? I'll tell you what. It's a thing that will stop you from writing functions that contain lots and lots of if statements. Why? Because it's a pain in the a$$, it creates spaghetti code that is difficult to maintain, debug and test blah blah blah.

Say, you want to write a function that receives a payload and converts it to any file format imaginable. Here's an example of what to avoid:

from pathlib import Path
from typing import Dict, Any


def convert_payload(
        payload: Dict[str, Any],
        output_file_name: Path,
        output_format: str
) -> None:
    if output_format == "json":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am json")
    elif output_format in {"yaml", "yml"}:
        with open(file=output_file_name, mode="w") as f:
            f.write("I am yaml")
    elif output_format == "csv":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am csv")
    elif output_format == "tsv":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am tsv")
    elif output_format == "avro":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am avro")
    elif output_format == "parquet":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am parquet")
    elif output_format == "arrow":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am arrow")
    elif output_format == "pickle":
        with open(file=output_file_name, mode="w") as f:
            f.write("I am pickle")
    else:
        raise ValueError("unexpected file conversion")

We haven't really written any of the conversion code yet and the function already looks like it's going to explode. Each file format has it's own quirks and before you know it you may have one 500+ line function. Fabulous? No. Before we go down that route, let's think about slicing convert_payload  to smaller independently testable pieces. For example:

def to_json(payload: Dict[str, Any]) -> Any:
    return "I am json"
def to_yaml(payload: Dict[str, Any]) -> Any:
    return "I am yaml"
def to_pickle(payload: Dict[str, Any]) -> Any:
    return "I am pickle"
def to_...(payload: Dict[str, Any]) -> Any:
    return "I am ..."

We shouldn't really be using pickle for a number of reasons but let's go ahead and use it for illustration purposes and because it's cringeworthy.

The next step would be to create a dictionary with each convert function assigned to it's name.

converter_dispatch = {
    "json": to_json,
    "yaml": to_yaml,
    "yml": to_yaml,
    "pickle": to_pickle
}

Hopefully, it all starts to become clearer now. Our convert_payload function becomes something like this:

def convert_payload(
    payload: Dict[str, Any],
    output_file_name: Path,
    output_format: str
):
    func = converter_dispatch[output_format]
    converted_payload = func(payload=payload)
    with open(file=output_file_name, mode="w") as f:
        f.write(converted_payload)

Let's unpack as per the blog's tradition:

  1. Get  the function to call, that corresponds to each file format. If output_format is json then func will be equivalent to to_json. Magic huh?
    func = converter_dispatch[output_format]

2. Therefore, func(payload=payload) is identical to to_json(payload=payload).

     converted_payload = func(payload=payload)

3. Finally the file is written.

    with open(file=output_file_name, mode="w") as f:
    	f.write(converted_payload)

理解。- ¿Comprende? - verstanden?

See ya.