Fishy: An ASCII Programming Language
Restructuring and optimization

The initial approach introduces inefficient file processing as get_content function reads all lines from the input file into a list at once and holds that list in memory throughout the entire processing. The traversal of the lines that were read is then redundantly repeated in run_code function.The more efficient way is to convert get_content into a generator function and consume one line from file at a time on demand.

The optimized get_content function:

def get_content(file: str) -&gt; List[str]:
    """
    Yields lines from the passed file path
    :param file -&gt; str: File to read content
    :return List[str]: Content in file
    """
    with open(file, "r") as file:
        for line in file:
            yield line.rstrip()




run_code function is renamed to parse_code



Inefficiency of validating and traversing commands

In parse_code (formerly run_code) function the commands sequence is potentially being traversed twice:
once on correct_syntax(commands) call and then - on getting numbers chr(get_number(fish)) for fish in commands.Moreover, consequent validations in this case may lead to redundant calculations.Consider the following situation: commands contains 10 items, all of them passed correct_syntax check but then, the 9th item fails on get_number check. That causes 10 redundant operations/checks.

To optimize validations we notice that is_fish and get_number are conceptually dependent on the same context - "fish" and are intended to validate the same "fish" object.Thus, those 2 validations are reasonably combined/consolidated into one validation function is_fish:

def is_fish(fish: str) -&gt; bool:
    """
    Validates "fish" item
    Fish: Starts with &gt;&lt; ends with &gt; and has number inside
    A fish like so &gt;&lt;98g&gt; will fail the check

    """
    return fish.startswith("&gt;&lt;") and fish.endswith("&gt;") and fish[2:-1].isdigit()


get_number function is now removed. The correct_syntax function is renamed to get_fish_numbers and its responsibility now is "Collect fish numbers from valid fishes":

def get_fish_numbers(pond: List[str]) -&gt; bool:
    """
    Collects fish numbers with checking the syntax of the passed list of commands on the following criteria:

    Is a fish &gt;&lt;..&gt;

    Correct Example:
    &gt;&lt;98&gt; &gt;&lt;108&gt; &gt;&lt;56&gt;

    Incorrect Example:
    &gt;&lt;98&gt; &gt;&gt;&lt;&lt;76&gt;&gt; &gt;&lt;[108&gt;

    """
    fish_numbers = []
    for fish in pond:
        if not is_fish(fish):
            sys.exit(f"Incorrect Syntax: {fish}")
        fish_numbers.append(int(fish[2:-1]))

    return fish_numbers




And finally the optimized parse_code function:

def parse_code(code: List[str]):
    """
    Parse and output the passed Fishy Code
    """
    for line in code:
        # Clean up code and separate commands#
        commands = line.split(" ")

        # Check if line has multiple statements in it
        fish_numbers = get_fish_numbers(commands)
        if len(fish_numbers) &gt; 1:
            output = "".join(chr(num) for num in fish_numbers)
            print(output)
        else:
            print(chr(fish_numbers[0]))