Here’s how to program in Python – Part 5


script, laptop, programming, code

In the previous lesson, we showed a variety of ways to adjust the output of text on the screen. In this lesson we take the step from your screen to files: we are going to read data from files and write to files. You also learn to respond to exceptions: error messages that Python gives you when something goes wrong.

You used the function two lessons ago input to record what the user types on his keyboard. And in the previous lesson, we showed you how to use the function print output on the screen. But import and export can also take place via files. Let’s see how that goes.

Here you can watch lesson four.

In this lesson we will limit ourselves to reading and writing text files. You can also work with binary files, which can contain arbitrary data in a form other than text, but that’s a bit more work as you still have to interpret the data. For the rest this works the same.

Read a text file

We show here in an example how to read the file with the list of users on a Linux machine such as a Raspberry Pi with Raspberry Pi OS (until recently called Raspbian). This example also works on macOS. If you use Windows, create a file yourself with the content that we show in our example and adjust the location of the file to be opened in your Python code.

The easiest way to read a full text file and display it on the screen requires only two lines:

with open (‘/ etc / passwd’, ‘rt’) as file:

print (file.read ())

In the first line we open the file with the function open. The first argument is the file we want to open. We used a full path here: ‘/ etc / passwd’. If you want to read a file that is in the same directory where you started the Python interpreter, you do not need to provide a full path: the file name will suffice. With the second argument ‘rt’ we indicate that we want to read the file and that it is a text file.

The construction with with is what Python calls a ‘context manager’. In the withblock you have access to the object file representing the opened file. After withblock, the file is automatically closed so that you can no longer read it. This may seem obvious, but it is not: even without it with you can open files, but if you forget to close the file after use, it can lead to problems. So never work with files without them with.

In the second line we call the function read on the object file On. This function returns the entire content of the text file as a string, which we then add print on the screen. On a typical Linux system, the output looks like this (we’re just showing a few lines here):

root: x: 0: 0: root: / root: / bin / bash

daemon: x: 1: 1: daemon: / usr / sbin: / usr / sbin / nologin

bin: x: 2: 2: bin: / bin: / usr / sbin / nologin

And so on

Read a text file line by line

But what if we do not want to read the entire file at once, but line by line, for example because we want to test whether the rules meet specific conditions? No problem, that is also very simple in Python. Instead of the function read to apply to your file, go with a forloop through the elements of the file. The text file you get from the function Open after all, behaves like a list whose elements are the consecutive lines in the file.

Split a string

But if we read those lines one by one, we also have to do something with them. As you can see, the file contains / etc / passwd on each line all kinds of information about the user, separated by a colon. We want to read each of that data separately. That is easy with the function split that we can run on a string. For instance:

>>> ‘root: x: 0: 0: root: / root: /bin/bash’.split (‘: ‘)

[‘root’, ‘x’, ‘0’, ‘0’, ‘root’, ‘/root’, ‘/bin/bash’]

You can see here that we are on the job split pass the character separating the different components of the string: ‘:’. The result is a list of strings that are part of our long string, without the separators ‘:’.

The consecutive components in the lines of the file / etc / passwd otherwise have the following meaning: username, unused, user ID, group ID, full username, user’s home directory, user’s shell.

Extract a list

You can now refer to the elements in the split string with an index, for example:

>>> information = “root: x: 0: 0: root: / root: / bin / bash” .split (‘:’)

>>> information[0]

‘root’

>>> information[6]

‘/ bin / bash’

But that is not very clear. That’s how we want information[0] actually user call and information[6] the name shell to give. Fortunately, you can easily assign the elements of a list to a few variables at once in Python. That is called unpacking. In our example this goes as follows:

>>> user, * _, name, directory, shell = “root: x: 0: 0: root: / root: / bin / bash”. split (‘:’)

>>> user

‘root’

>>> _

[‘x’, ‘0’, ‘0’]

>>> name

‘root’

>>> directory

‘/ root’

>>> shell

‘/ bin / bash’

Use the * format to extract any number of elements. Since we are not interested in these elements in this case, we assign them to the variable named _, which is why we use * _ when extracting. We could also replace this with this user, _, _, _, name, directory, shell.

Filter data from a text file

Then you now know enough to run the following command: read the password file line by line and if the shell does not ‘/ usr / sbin / nologin’ or ‘/ bin / false’ shows you the username, full username and home folder.

The code looks like this:

with open (‘/ etc / passwd’, ‘rt’) as file:

for line in file:

user, * _, name, directory, shell = line.strip (). split (‘:’)

if shell not in [‘/bin/false’, ‘/usr/sbin/nologin’]:

print (‘{1} ({0}): {2} ({3})’. format (user, name, directory, shell))

So we open the file / etc / passwd as a text file to read. For each line in the file we extract the different elements into a few variables. We then check whether the shell is not the same as the two previously mentioned shells. If that condition is met, we will show the user, his full name, his home folder and his shell.

There is only one novelty in this code: the function strip. This removes whitespace and newlines at the beginning and end of a string. We need that here because the shell is at the end of the line and there is therefore a character before a new line. Without that call to strip, the equation would normally not work after it.

Write to a text file

Writing to a text file is similar to reading a text file. We start one withblock in which we open the file and in it we write to the file:

with open (‘file.txt’, ‘wt’) as file:

file.write (‘This is the first line. n’)

file.write (‘This is the second line. n’)

file.write (‘This is the third line. n’)

At the end of each line you have to add a character for a new line yourself: n. Another way to write a line to a text file is with the function print, which automatically adds a new line:

print (‘This is the first line.’, file = file)

Note that we open the file with the second argument ‘wt’, indicating that we want to write to the file. This way we will overwrite any existing content of the file, so be careful with this!

If you want to avoid this situation, you can call open with file mode ‘xt’. If the file doesn’t already exist, it will do the same as ‘wt‘: you can write to the file. But if the file already exists, you will get an error:

with open (‘file.txt’, ‘xt’) as file:

print (‘This is a test.’, file = file)

with open (‘file.txt’, ‘xt’) as file:

print (‘This is another test.’, file = file)

Traceback (most recent call last):

File ““, line 1, in

FileExistsError: [Errno 17] File exists: ‘file.txt’

Another interesting file mode is ‘at’ (from ‘append’): Adds lines to the end of an existing text file.

Handling exceptions

In the example above, you would probably want to handle the error message that the file already exists in a neater way. What we’ve called an error so far is called an exception in Python. There are different types of exceptions and you can easily catch the occurrence of exceptions in your Python code. It goes like this:

try:

with open (‘file.txt’, ‘xt’) as file:

print (‘This is another test.’, file = file)

except FileExistsError:

print (‘ERROR: The file already exists.’)

The code within the tryblock will run as normal. But if there is an exception within this block, the program will skip to the except-block. In it, we specified that we are only in exceptions of type FileExistsError be interested. In case one of them occurs, we show our own error message. Then the program continues after the except-block.

If you want to catch multiple types of exceptions, add multiple exceptblocks with each the different type of exception. If you want to run the same code for multiple types of exceptions, put those exceptions in parentheses, like this:

except (ZeroDivisionError, ValueError):

And if you want to respond the same to all possible exceptions, just add one exceptblock without adding the name of an exception, although that is not often useful.

Summary

In this lesson we learned how to read text files and split strings into parts. You can now also work with text files in the other direction: you can write arbitrary text to a file. And because you’ve learned how to catch exceptions, your program’s users will no longer receive cryptic errors from Python. Because you can already write more complex Python programs with this knowledge, in the next lesson you will learn how to structure your program more in functions and modules.

Order

Ask the user for a line such as root: x: 0: 0: root: / root: / bin / bash for use in a password file. Write the main elements of the line to a separate line in a file, in the form:

User: root

Name: root

Directory: / root

Shell: / bin / bash

Make sure your program gives a clear error message if the line is not in the correct form for a password file.

Elaboration

line = input (‘Enter a line for the password file:’)

try:

user, _, _, _, name, directory, shell = line.strip (). split (‘:’)

with open (‘password file’, ‘wt’) as file:

print (‘User: {}’. format (user), file = file)

print (‘Name: {}’. format (name), file = file)

print (‘Directory: {}’. format (directory), file = file)

print (‘Shell: {}’. format (shell), file = file)

except ValueError:

print (‘Enter the line in the following form:’)

print (‘user: x: 0: 0: name: directory: shell’)

This is a direct combination of everything you have learned in this lesson. Note: we do need user, _, _, _, name, directory, shell and not the shorter version user, * _, name, directory, shell. After all, with the latter rule we do not guarantee that the rule consists of exactly seven elements.

Cheat sheet

exception: an error message in Python
path: The location of a file, including all parent directory names

.

Recent Articles

Related Stories

Stay on op - Ge the daily news in your inbox