Python task manager from scratch, part 3: Separating the data

We don't have a very useful task manager yet, for a few reasons. We can only interact with it by running a file that lives in one place as a Python script. We can't add or delete anything. And so on.

These are related, more intimately than you might think, to a few general principles of software engineering: 1. Try to disentangle the data itself from the code that operates on that data. 1. It's very hard to design good interfaces to data.

Let's start addressing these! The first step is to take the tasks that are currently listed explicitly in our tasks object in main.py and put them in a separate text file. This latter file will be a plain old text file: we'll call it task_list.txt, but if you call it something else that's fine too. For now, it will be our "database."

(Martin Kleppmann's wonderful Designing Data-Intensive Applications also begins by contemplating the use of a plain text file as a database. If you want to learn a lot more about to think about computers storing data, that's the book to check out. As this project aspires to be, the book is advanced but requires remarkably little prior knowledge.)

So! Your text file should look like this:

Move shelves
Move air conditioners
Empty dishwasher
Take vitamins
task_list.txt

...and we'll correspondingly modify the tasks list in main.py to read from that "database" instead of holding the strings itself from the start:

tasks = []
with open('task_list.txt') as f:
    for task_line in f.readlines():
        tasks.append(task_line.strip())

for task in tasks:
    print(task)

There's a lot of new Python stuff in that code block!

  1. The first line, tasks = [], causes us to begin with an empty list in the tasks variable.
  2. You don't need to understand the details of what's going on in the second line (it's a context manager, and it's great to know what a context manager is, but roughly 1% of working professional Python programmers can describe in any detail the mechanics of a context manager). For now, you can think of it as an incantation that opens a file named task_list.txt and gives you a "file handler" named f that you can manipulate in the indented block right below that line.
  3. f.readlines() gives you the lines in the file one by one; as you "iterated over" the tasks list in the previous version of this file, you can "iterate over" the lines in the file, assigning them to the task_line variable one by one and executing whatever code is in the indented block below that.
  4. So, in particular, you can have indented blocks inside of indented blocks, representing nested levels of execution of the code.
  5. tasks is a list, and lists are "mutable": you can change what they refer to. And, in particular, you can append things to them.
  6. .strip() is a method you can call on a string to take the newline off the end of it. (When f.readlines() hands task_line the lines in the file one-by-one, each of those lines includes a character that your on-screen text editor represents by breaking that line off and starting a new one. The task I want to describe is Move shelves, not Move shelves\n, so I ask Python to strip off the \n.
  7. Again: If this is all new to you, you are not supposed to understand this just by reading it once. I'm going through it quickly to give you a clear sense of what to read elsewhere, not because you should be able to know what's going on by just reading this post. Many many people have explained these things elsewhere, and you can Google for those other people's explanations.

And, again: if this is all very familiar to you, just keep on reading.

Our directory should now look like:

veery/

    main.py
    task_list.txt

And you should still get the same output if you run main.py (see the previous post).


Next post: Python task manager from scratch, part 4: Making functions


Home page