ICTPRG435 - Session 4: Files, Modules, Libraries and Docstrings

Overview: This session introduces Python file handling (reading, writing, appending), modules and libraries (including the Python Standard Library), and documentation via docstrings. A hands-on exercise follows.

Learning outcomes

Working with files

Python is ideal for processing data files such as logs or text files. To work with files, create a file object using the built-in open() function:

open(filename, mode)

Common modes

ModeNameDescription
"r"ReadDefault. Opens for reading; error if file not found.
"w"WriteCreates or overwrites file.
"x"Exclusive creationCreates a new file, but fails if the file already exists.
"a"AppendOpens for appending; creates file if missing.
"b"BinaryOpen file in binary mode (add to another mode, e.g., "rb").
"t"TextOpen file in text mode (default value, add to another mode, e.g., "rt").

Writing to a file

To open a file for writing, use the w mode. You can also use wt, but since text mode t is the default, it's optional and usually omitted. In the example below:

my_file = open("my_file.txt", "w")
my_file.write("Hello World,\nI enjoy Python.")
my_file.close()

Importance of Closing Files

When a file is opened, system resources are allocated to it. If the file is not closed properly, these resources remain in use unnecessarily, which can lead to performance issues or file corruption.

Python provides a safer and more efficient way to handle files using the with statement, which automatically closes the file once the block of code is executed.

Reading from a file

To open a text file for reading, you can use the r or rt mode. However, since r and t are the default modes, they don't need to be explicitly specified. In the example below:

Python ScriptResult
my_file = open("my_file.txt", "r")
my_content = my_file.read()
print(my_content)
my_file.close()
Hello World,
I enjoy Python.

Appending to a file

To open a file for appending, the a or atmode must be specified. In the example below:

my_file = open("my_file.txt", "a")
my_file.write("\nPython Programming")
my_file.close()

Reading line by line

Using readline() method

The readline() method is used to read a file, one line at a time. The example below reads the first and the second lines of the file.

my_file = open("my_file.txt", "r")

# Read first line
line1 = my_file.readline()
print(line1)

# Read next line
line2 = my_file.readline()
print(line2)

my_file.close()

Using a for loop

with open("my_file.txt", "r") as f:
    for line in f:
        print(line.strip())

Reading all lines as a list

with open("my_file.txt", "r") as f:
    lines = f.readlines()
print(lines) # -> ['Hello World,\n', 'I enjoy Python.\n', 'Python Programming']

Using with (context manager)

The with statement ensures the file closes automatically, even if an error occurs.

When the open() method is called using the with statement, the file automatically closes after the with block has been processed. The example below illustrates the use of the with statement which is considered best practice:

with open("my_file.txt", "r") as my_file:
    content = my_file.read()
    print(content)

Modules and libraries

Modules and libraries provide programmers with a means to divide large coding tasks into shorter more adaptable and logical subtasks. Although many new programmers often used the terms interchangeably, they are different.

Creating and importing modules

The example below illustrates the use of a simple python program calculator.py which import a user defined module calculate.py.

# calculate.py
def add(num1, num2):
    result = num1 + num2
    return result

def subtract(num1, num2):
    result = num1 - num2
    return result

if __name__ == "__main__":
    print("10 + 5 =", add(10, 5))
    print("20 - 8 =", subtract(20, 8))

Importing the module:

# calculator.py
import calculate
print(calculate.add(10, 10))

The import statement is a Python command which fetches functions and objects from other files. In the above example we are importing the entire calculate.py module.

The module calculate.py contains tests within the if block.

The tests are only run when the module is run as a standalone, not when it is imported. For a more detailed explanation on this please visit: stackoverflow

To import specific functions only:

from calculate import add
print(add(10, 10))

Note: Only the functions explicitly imported are accessible.

The calculator.py and calculate.py files are located under the Session 4 Files heading on the resources page.

Common standard library modules

Python's Standard Library includes modules for random numbers, OS interaction, strings, and more. Below are a few useful ones.

The random module

The random module can be used to generate a random number or select a random element from a sequence. There are many built-in methods used with random, we will look at a few.

import random

print(random.randrange(5))       # Random integer 0–4
print(random.choice("Python"))   # Random letter form string "Python"
print(random.choice([1, 3, 8]))  # Random list element

The Python random generator (random module) is a pseudo-random number generator and is not cryptographically secure. Pseudo-random numbers generators use an algorithm to produce a sequence of numbers that appear to be random. Although pseudo-random number generators are fine for some applications (such as games and test date), they are not recommended for applications where true randomness is needed, such as cryptography.

The secrets module

Although very similar to the random module, the secrets module provides cryptographically strong (true) random numbers.

import secrets

print(secrets.randbelow(5))      # Random integer 0 - 4
print(secrets.choice("Python"))  # Cryptographically secure choice of a letter from string "Python"

The string module

The string module provides access some string constants as illustrated below.

import string

print(string.ascii_letters)   # -> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.ascii_lowercase) # -> abcdefghijklmnopqrstuvwxyz
print(string.ascii_uppercase) # -> ABCDEFGHIJKLMNOPQRSTUVWXYZ
print(string.digits)          # -> 0123456789
print(string.hexdigits)       # -> 0123456789abcdefABCDEF
print(string.punctuation)     # -> !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

The os module

The os module in provides functions for interacting with the operating system (system shell operators to be precise). The examples below demonstrate how to:

import os

os.rename("my_file.txt", "your_file.txt")  # Rename file from my_file.txt to your_file.txt
os.remove("your_file.txt")                 # Delete the your_file.txt file.
os.mkdir("python")                         # Create a directory named "python" in the current directory

The datetime module

from datetime import datetime
print(datetime.now())    # -> print the current date and time

Python docstrings

Docstrings are string literals that document code elements (functions, classes, modules). They appear immediately below the definition line and are accessible via __doc__ or help().

Function docstrings

def adder(a, b):
    """Return the sum of the two numbers."""
    return a + b

print(adder.__doc__)   # -> Return the sum of the two numbers.

Incorrect placement:

def adder(a, b):
    total = a + b
    """This docstring will not be attached."""
    return total

print(adder.__doc__)   # None

Multi-line docstring example

A functions docstring should summarise the function’s behaviour and document its arguments and return values. The docstring should list all exceptions that may be raised and any other optional arguments.

Our example contained a single line docstring. For multi-lined docstrings you should adhere to the following guidelines:

def divide(x, y):
    """
    Divide two numbers and return the result.

    Args:
        x (int or float): numerator
        y (int or float): denominator
    Returns:
        float: quotient of x / y
    Raises:
        ZeroDivisionError: if y is zero
    """
    return x / y

Built-in function docstrings

print(len.__doc__)
print(print.__doc__)

Use help() to view detailed documentation:

help(len)
help(print)

Module docstrings

Placed at the top of a Python file, before imports:

"""Utility functions for working with text files."""
import os

print(os.__doc__)

Student activity - Random string writer

Objective: Write a program that generates random lowercase strings and saves them to a file.

def writer():
    ?
    return "String written to file."

def random_string():
    ?
    return str_result

if __name__ == "__main__":
    for x in range(10):
        random_str = random_string()
        print(writer(random_str))

Requirements

Expected console output

String written to file.
String written to file.
... (repeated 10 times)

Expected file (example)

aznropvedj
kruaftwobv
mdtchweavx
gmpyoiknwc
kdpyojeczs
zhosrygxpv
yhovdubzrj
svkhzopjxm
riwokdnzsg
qrdyzebpgj
  

Note: Actual output will differ, as the strings are randomly generated.