Splitting our code

Day 14: Exercise Solutions

Python Guru with a screen instead of a face, typing on a computer keyboard with a dark green background to match the day 14 image.

Here are our solutions for the day 14 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Rewrite the following piece of code using a context manager.

f = open("hello_world.txt", "w")
f.write("Hello, World!")
f.close()

The first line for our context manager is going to look like this:

with open("hello_world.txt", "w") as f:
    pass

First we have the with keyword, then the open call, then we provide a variable name using as so we can easily refer to the file contents.

Underneath this line we have an indented block containing everything we want to do while the file is open. Python will then close the file for us when these operations have been completed.

with open("hello_world.txt", "w") as f:
    f.write("Hello, World!")

2) Use append mode to write "How are you?" on the second line of the hello_world.txt file above.

Once again, we should be using a context manager here, and the first line is going to be nearly identical. We just have to swap out "w" for "a".

with open("hello_world.txt", "a") as f:
    pass

If you prefer, you can use keyword arguments for any of the values, and you can find the names of the open parameters in the documentation.

Now we just need to call write and pass in "\nHow are you?" as a string.

with open("hello_world.txt", "a") as f:
    f.write("\nHow are you?")

Make sure you don't miss of the \\n, because we want this line to appear on the second line. We therefore need to add a line break after the first line.

3) Take the list of dictionaries we created from the Iris flower data set and write it to a new file in CSV format.

Here we're basically performing the same steps as before, just in reverse.

You can work in the same repl as before if you like, but if you're working in a new repl, here is the list of dictionaries for your convenience:

irises = [
    {'sepal_length': '5.1', 'sepal_width': '3.5', 'petal_length': '1.4', 'petal_width': '0.2', 'species': 'Iris-setosa'},
    {'sepal_length': '4.9', 'sepal_width': '3',   'petal_length': '1.4', 'petal_width': '0.2', 'species': 'Iris-setosa'},
    {'sepal_length': '4.7', 'sepal_width': '3.2', 'petal_length': '1.3', 'petal_width': '0.2', 'species': 'Iris-setosa'},
    {'sepal_length': '4.6', 'sepal_width': '3.1', 'petal_length': '1.5', 'petal_width': '0.2', 'species': 'Iris-setosa'},
    {'sepal_length': '5',   'sepal_width': '3.6', 'petal_length': '1.4', 'petal_width': '0.2', 'species': 'Iris-setosa'},
    {'sepal_length': '7',   'sepal_width': '3.2', 'petal_length': '4.7', 'petal_width': '1.4', 'species': 'Iris-versicolor'},
    {'sepal_length': '6.4', 'sepal_width': '3.2', 'petal_length': '4.5', 'petal_width': '1.5', 'species': 'Iris-versicolor'},
    {'sepal_length': '6.9', 'sepal_width': '3.1', 'petal_length': '4.9', 'petal_width': '1.5', 'species': 'Iris-versicolor'},
    {'sepal_length': '5.5', 'sepal_width': '2.3', 'petal_length': '4',   'petal_width': '1.3', 'species': 'Iris-versicolor'},
    {'sepal_length': '6.5', 'sepal_width': '2.8', 'petal_length': '4.6', 'petal_width': '1.5', 'species': 'Iris-versicolor'},
    {'sepal_length': '6.3', 'sepal_width': '3.3', 'petal_length': '6',   'petal_width': '2.5', 'species': 'Iris-virginica'},
    {'sepal_length': '5.8', 'sepal_width': '2.7', 'petal_length': '5.1', 'petal_width': '1.9', 'species': 'Iris-virginica'},
    {'sepal_length': '7.1', 'sepal_width': '3',   'petal_length': '5.9', 'petal_width': '2.1', 'species': 'Iris-virginica'},
    {'sepal_length': '6.3', 'sepal_width': '2.9', 'petal_length': '5.6', 'petal_width': '1.8', 'species': 'Iris-virginica'},
    {'sepal_length': '6.5', 'sepal_width': '3',   'petal_length': '5.8', 'petal_width': '2.2', 'species': 'Iris-virginica'}
]

First, things first, let's focus on just printing out the values in CSV format.

Since we're going to need to perform some conversion for each dictionary in the list, we know we're probably going to need something like a for loop, so let's set that up.

for iris in irises:
    pass

Converting the dictionary to CSV format is actually relatively straightforward. We can just create an f-string where the values are comma separated.

Because this line is going to be very long, I'd recommend breaking the string up over two lines and concatenating them, like this:

for iris in irises:
    print(
        f"{iris['sepal_length']},{iris['sepal_width']},{iris['petal_length']}," +
        f"{iris['petal_width']},{iris['species']}"
    )

This is fine, but I think we can do a little better here.

If we want to stick with the f-string approach, one thing we can do is get the values with iris.values() and destructure them into a series of variables. This will save us using all these subscription expressions in the f-string.

for iris in irises:
    sepal_length, sepal_width, petal_length, petal_width, species = iris.values()
    print(f"{sepal_length},{sepal_width},{petal_length},{petal_width},{species}")

That's definitely a step in the right direction, but I think we can still do better.

All of our dictionary values are strings, and we're trying to join those strings together using a comma, so let's just use the join method.

for iris in irises:
    print(",".join(iris.values()))

As you can see, join can be extremely powerful in situations like this. The code is incredibly short, and fairly easy to understand as well.

At this stage we should definitely run our code and make sure everything looks correct. If there aren't any problems, we can replace print with a call to write so that we can write to the file.

with open("iris_2.csv", "w") as iris_file:
    for iris in irises:
        iris_file.write(",".join(iris.values()))

If you run this code, we're not quite going to get what we want, because we forgot one vital detail: we didn't add a newline character at the end of the string. As such, everything is going to get written on a single line.

We can just concatenate the string, "\\n" to each of the string we write to the file:

with open("iris_2.csv", "w") as iris_file:
    for iris in irises:
        iris_file.write(",".join(iris.values()) + "\n")

If we run the code and take a look at iris_2.csv, things should look like this:

5.1,3.5,1.4,0.2,Iris-setosa
4.9,3,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5,3.6,1.4,0.2,Iris-setosa
7,3.2,4.7,1.4,Iris-versicolor
6.4,3.2,4.5,1.5,Iris-versicolor
6.9,3.1,4.9,1.5,Iris-versicolor
5.5,2.3,4,1.3,Iris-versicolor
6.5,2.8,4.6,1.5,Iris-versicolor
6.3,3.3,6,2.5,Iris-virginica
5.8,2.7,5.1,1.9,Iris-virginica
7.1,3,5.9,2.1,Iris-virginica
6.3,2.9,5.6,1.8,Iris-virginica
6.5,3,5.8,2.2,Iris-virginica