9. Several Practical Topics¶
The topics in this chapter do not belong to a single theme or concept, but are useful to know in programming practice.
9.1. Modules¶
importing modules
In this course we encounter multiple modules, like turtle, tkinter, random. After importing a module the interpreter recognizes more functions than before. So how does the import of a module work?
Upon a statement like this:
import module_name
the interpreter will go through all the code of the file module_name.py. All global statements will be executed once and all def statements can be used with the prefix ‘module_name.’
As your program gets longer, you may want to split it into several files for easier maintenance. You may also want to use a handy function that you’ve written in several programs without copying its definition into each program.
You can even bundle modules into so-called packages, but that is beyond the scope of this course.
renaming a module in your own code
Sometimes a module you want to import has an inconvenient name. As an example, look at this code:
import nao_nocv_remote_control_2_0_1
nao_nocv_remote_control_2_0_1.Init()
nao_nocv_remote_control_2_0_1.MoveForward()
The module name above is clearly uncomfortably long. If you are not the author of the module, it is impracticle to change the name of the module file. However, it is possible to rename such a module to fit your own needs, for instance give it your own shorter ‘nickname’, with the ‘as’ keyword. The following code fragment has the identical effect as the code above:
import nao_nocv_remote_control_2_0_1 as nao
nao.Init()
nao.MoveForward()
alternative way of importing: from
With the import statement all definitions of the module will be loaded into the computer’s memory. Some modules are very big and if you only need one or a few definitions. There is an alternative to indicate which definitions you want to import from a module.
from module_name import function_name
As an example consider the following code snippet:
from turtle import forward
forward(100)
In this fragment the ‘turtle.’ prefix is not necesary anymore. You can even import all object and definitions in this way:
from turtle import *
forward(100)
left(45)
penup()
Now all functions and numbers from the turtle module can be used without the ‘turtle.’ prefix.
Please be aware, that with ‘from module_name import *’ the origin of the functions is not visible anymore. For this reason many professional programmers still prefer ‘import module_name’ over ‘from module_name import *’, even when they need multiple functions from the module.
9.2. Random Numbers¶
There are many occasions in programming when you need so-called random numbers. These are numbers selected from a certain range (e.g. 1, 2, 3, 4, 5 and 6) as if they were drawn “in a lottery”. Examples are questions in questionaires that you want to mix in order or simulations of simulating stochastic processes to calculate probabilities.
All major programming languages have been built-in facuilities for random number generation. Python is no exception, the random features are in the built-in module ‘random’. We will consider only three practical applications here, though the random module offers many more possibilities. Please note that the examples listed below are all examples of uniform probability distributions.
Function randint(lower_number, upper_number) returns a random number n with lower_number \(\leqslant\) n \(\leqslant\) upper_number. For example, throwing a regular dice for a hundred times can be easily simulated in a program by:
import random
for n in range (1, 100):
throw = random.randint(1, 6)
print(n, throw)
Another examples is the calculation of the probability of throwing heads or tails in a coin flip:
1import random
2
3nr_coin_flips = 100
4nr_heads = 0
5nr_tails = 0
6for n in range (0, nr_coin_flips):
7 flip = random.randint(0, 1)
8 if flip == 0:
9 nr_heads += 1
10 else:
11 nr_tails += 1
12print("total nr of heads = ", nr_heads)
13print("total nr of tails = ", nr_tails)
14p_heads = nr_heads / nr_coin_flips
15print("P(heads) = ", p_heads)
with output of a sample run:
total nr of heads = 498
total nr of tails = 502
P(heads) = 0.498
An alternative for randint is randrange(lower, upper, step), which is a random selection of a number from range(lower, upper, step).
Less frequently used, but sometimes needed is drawing a random floating-point number. Function ‘random.random()’ returns a random float number from the interval [0, 1). It is easy to change the boundaries 0 and 1 with some basic calculus:
import random
#random float x in the interval lower <= x < upper
x = lower + (upper - lower) * random.random()
As a final practical example, the random selection from items in a list is done with random.choice(list_name):
import random
reward_list = ['frying pan', 'big turkey', 'knife set', 'dinner cheque']
random_reward = random.choice(reward_list)
print("You have won a", random_reward)
9.3. File Reading and Writing¶
File Objects
Built-in function open() returns a file object, and is most commonly used with two arguments: open(filename, mode).
f = open('workfile', 'w')
The first argument is a string containing the filename.
The second argument is another string containing a few characters describing the way in which the file will be used. The mode can be ‘r’ when the file will only be read, ‘w’ for only writing (an existing file with the same name will be erased), and ‘a’ opens the file for appending; any data written to the file is automatically added to the end. ‘r+’ opens the file for both reading and writing. The mode argument is optional; ‘r’ will be assumed if it is omitted.
Normally, files are opened in text mode, that means, you read and write strings from and to the file. If ‘b’ is appended to the mode (e.g. ‘rb’ or ‘wb’) the file is opened in binary mode: now the data is read and written in the form of bytes objects. This mode should be used for all files that don’t contain text.
In text mode, the default when reading is to convert platform-specific line endings (\n on Unix, \r\n on Windows) to just \n. When writing in text mode, the default is to convert occurrences of \n back to platform-specific line endings. This behind-the-scenes modification to file data is fine for text files, but will corrupt binary data like that in JPEG or EXE files. Pay attention to use binary mode when reading and writing such files.
We will only treat text files in this reader.
When you’re done with a file, call f.close() to close it and free up any system resources taken up by the open file. After calling f.close(), attempts to use the file object will automatically fail.
>>>
>>> f.close()
>>> f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file
It is good practice to use the with keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way. It is also much shorter than writing equivalent try-finally blocks:
>>>
>>> with open('workfile', 'r') as f:
... read_data = f.read()
>>> f.closed
True
Reading from Files
The rest of the examples in this section will assume that a file object called f has already been created.
To read a file’s contents, call f.read(size), which reads some quantity (size) of data and returns it as a string (in text mode). Size is an optional numeric argument. When size is omitted or negative, the entire contents of the file will be read and returned. Otherwise, at most ‘size’ bytes are read and returned. If the end of the file has been reached, f.read() will return an empty string (‘’):
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''
Method f.readline() reads a single line from the file. A newline character (\n) is left at the end of the string, and is only omitted on the last line of the file (unless the file happens to end in a newline). This makes the return value unambiguous. If f.readline() returns an empty string, the end of the file has been reached. If f.readline() returns ‘\n’, a blank line was read.
>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''
For reading all lines in a file, you can loop over the file object. This leads to simple code:
>>>
>>> for line in f:
... print(line)
...
This is the first line of the file.
Second line of the file
etc.
If you want to read all the lines of a file in a list you can also use ‘list(f)’ or ‘f.readlines()’.
Writing to Files
Method f.write(string) writes the contents of ‘string’ to the file, returning the number of characters that was written:
>>>
>>> nr = f.write('This is a test\n')
>>> nr
15
Other types of objects than strings need to be converted to a string (in text mode) before writing them. Here is an example:
>>>
>>> value = ('the answer', 42)
>>> s = str(value) # convert the tuple to string
>>> f.write(s)
18
Seeking in Files
Method f.tell() returns an integer giving the file object’s current position in the file represented as number of bytes from the beginning of the file when in binary mode and an opaque number when in text mode. To change the file object’s position, use f.seek(offset):
>>>
>>> f = open('workfile', 'r+')
>>> f.write('0123456789abcdef')
16
>>> f.seek(5) # Go to the 6th character in the file
5
>>> f.read(1)
'5'
In text files only seeks relative to the beginning of the file are allowed (the exception being seeking to the very file end with seek(0, 2)) and the only valid offset values are those returned from the f.tell(), or zero.
9.4. Timing¶
9.4.1. delaying¶
In many cases there is a need for some control over the moment that an action is performed. Think of the countless psychological experiments that involve manipulating the timing of actions. The simplest way of controling when statements in a program are executed is by waiting for input of the user. We have already seen how to do that with an input() statement.
Sometimes we want to delay actions without haveing to depend on user input. In such cases the so-called sleep() function comes in handy. Sleep is so simple we will just show it’s use in an example program:
# program power_nap
from time import sleep
from random import randrange
for n in range(5):
delay = randrange(1, 7, 2)
sleep(delay)
print('I power napped for', delay, 'seconds!')
Here is a sample run:
============== RESTART: power_nap.py ==============
I power napped for 1 seconds!
I power napped for 3 seconds!
I power napped for 5 seconds!
I power napped for 3 seconds!
I power napped for 1 seconds!
>>>
9.4.2. using timers¶
Often, the simple function of sleep() will fulfill the needs of the programmer. There is one severe disadvantage to sleep however: the program becomes unresponsive to all user events like keyboard input or mouse events. Fortunately, there is a slightly more advanced programming technique that allows the program to continue with other actions in the mean time: a so-called timer event. It allows the program to multi-task as demonstrated by this simple example:
from time import sleep
from threading import Timer
def handleTimer():
print("Your eggs are ready!")
print("simple 'egg-timer' for 'multitasking' your program")
egg_timer = Timer(5.0, handleTimer)
egg_timer.start()
for n in range(8):
sleep(1.0)
print(n, 'seconds have passed')
which produces the following output:
>>>
============== RESTART: timer.py ==============
simple 'egg-timer' for 'multitasking' your program
0 seconds have passed
1 seconds have passed
2 seconds have passed
3 seconds have passed
Your eggs are ready!
4 seconds have passed
5 seconds have passed
6 seconds have passed
7 seconds have passed
The output above shows that the timer runs in the background until the required amount of seconds have passed. Argument handleTimer is then called once.
After starting a timer can be stopped and thus prevented from firing the timing event by:
egg_timer.cancel()
A timer will not restart after firing. The programmer needs to specifically instruct re-starting a timer with the run() method. The example below is the classic way to produce a regular timer ‘tick’ in this way:
# ticking with a timer
from time import sleep
from threading import Timer
def handleTimer():
print("timerTick...")
timer.run()
print("repeated timer ticks in your program")
timer = Timer(3.0, handleTimer)
timer.start()
sleep(10)
timer.cancel()
With the corresponding repeated timerTicks in the output below. Be careful not to forget the timer.cancel() at the end or the timer will continue firing events:
repeated timer ticks in your program
timerTick...
timerTick...
timerTick...
>>>
9.4.3. measuring time¶
Knowing the amount of time that has elapsed between two actions or events is also often required. This can be achieved by simply calling the time() function repeatedly. This function returns the amount of seconds that have passed since jan 1, 1970.
>>>time.time()
1476283951.725473
The gmtime() method converts this impractical number into a more useful format:
>>> import time
>>> now_sec = time.time()
>>> gmt = time.gmtime(now_sec)
>>> print(gmt.tm_year, '-', gmt.tm_mon, '-', gmt.tm_mday, ',',
gmt.tm_hour, ':', gmt.tm_min, ':', gmt.tm_sec)
2016 - 10 - 12 , 14 : 57 : 6
You can find more on time functions in the python.org site (https://docs.python.org/3.6/library/time.html).
Since we are usually interested in time differences only we can get useful information about time intervals by simply subtracting two consecutive time() results. The following program illustrates how to measure a timespan of some user action:
from time import time
print("How fast can you type 'the quick brown fox jumps over the lazy dog'?")
input("Press <Enter> to start")
start = time()
input("Type here: ")
end = time()
interval = end - start
print("It took you", round(interval, 1), "seconds to type it.")
Here is a sample run testing the author’s typing speed:
>>>
============= RESTART: /Users/peterlambooij/Documents/timing.py =============
How fast can you type 'the quick brown fox jumps over the lazy dog'?
Press <Enter> to start
Type here: the quick brown fox jumps over the lazy dog
It took you 5.6 seconds to type it.
>>>
Although all timing examples were demonstrated here with text based programs, they can be easily incorporated into more advanced programs like GUIs.
© Copyright 2022, dr. P. Lambooij
last updated: Oct 07, 2022