Bigdigitspy

The first program we will review is quite short, although it has some subtle aspects, including a list of lists. Here is what it does: Given a number on the command line, the program outputs the same number onto the console using "big" digits.

At sites where lots of users share a high-speed line printer, it used to be common practice for each user's print job to be preceded by a cover page that showed their username and some other identifying details printed using this kind of technique.

We will review the code in three parts: the import, the creation of the lists holding the data the program uses, and the processing itself. But first, let's look at a sample run:

bigdigits.py 41072819

We have not shown the console prompt (or the leading ./ for Unix users); we will take them for granted from now on.

import sys

Since we must read in an argument from the command line (the number to output), we need to access the sys.argv list, so we begin by importing the sys module.

We represent each number as a list of strings. For example, here is zero:

Zero

*** " * * " * *■■ * *■■ * *» * * " *** »

" * * ", " *** "1, # Zero ii n ii ii

ii >|( ■■ II >|< ■■ ■■ * ii II ^ II

r ii >|(>|<>|<>|<ii ii ^c * ii ii >|< 54c ii ■■ >|<)|<)|<)|i ii

One detail to note is that the Zero list of strings is spread over multiple lines. Python statements normally occupy a single line, but they can span multiple set type lines if they are a parenthesized expression, a list, set, or dictionary literal, a ^ 121 function call argument list, or a multiline statement where every end-of-line dict character except the last is escaped by preceding it with a backslash (\). In type all these cases any number of lines can be spanned and indentation does not ^ 126 matter for the second and subsequent lines.

Each list representing a number has seven strings, all of uniform width, although what this width is differs from number to number. The lists for the other numbers follow the same pattern as for zero, although they are laid out for compactness rather than for clarity:

One = [" * " "** " " * " " * " " * " " * " "***"] Two = [" *** " "* *" "* * " " * " " * " "* " "*****"] # ...

Nine = [" ****" "* *" "* *" " ****" " *" " *" " *"]

The last piece of data we need is a list of all the lists of digits:

Digits = [Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine]

We could have created the Digits lists directly, and avoided creating the extra variables. For example:

We preferred to use a separate variable for each number both for ease of understanding and because it looks neater using the variables.

We will quote the rest of the code in one go so that you can try to figure out how it works before reading the explanation that follows.

try:

while column < len(digits):

number = int(digits[column]) digit = Digits[number] line += digit[row] + " " column += 1 print(line) row += 1 except IndexError:

print("usage: bigdigits.py <number>") except ValueError as err: print(err, "in", digits)

The whole code is wrapped in an exception handler that can catch the two things that can go wrong. We begin by retrieving the program's command-line argument. The sys.argv list is 0-based like all Python lists; the item at index position 0 is the name the program was invoked as, so in a running program this list always starts out with at least one item. If no argument was given we will be trying to access the second item in a one-item list and this will cause an IndexError exception to be raised. If this occurs, the flow of control is immediately switched to the corresponding exception-handling block, and there we simply print the program's usage. Execution then continues after the end of the try block; but there is no more code, so the program simply terminates.

If no IndexError occurs, the digits string holds the command-line argument, which we hope is a sequence of digit characters. (Remember from Piece #2 that identifiers are case-sensitive, so digits and Digits are different.) Each big digit is represented by seven strings, and to output the number correctly we must output the top row of every digit, then the next row, and so on, until all seven rows have been output. We use a while loop to iterate over each row. We could range() just as easily have done this instead: for row in (0, 1, 2, 3, 4, 5, 6): and later ^ 141 on we will see a much better way using the built-in range() function.

We use the line string to hold the row strings from all the digits involved. Then we loop by column, that is, by each successive character in the command-line argument. We retrieve each character with digits[column] and convert the digit to an integer called number. If the conversion fails a ValueError exception is raised and the flow of control immediately switches to the corresponding exception handler. In this case we print an error message, and control resumes after the try block. As noted earlier, since there is no more code at this point, the program will simply terminate.

If the conversion succeeds, we use number as an index into the Digits list, from which we extract the digit list of strings. We then add the row-th string from this list to the line we are building up, and also append two spaces to give some horizontal separation between each digit.

Each time the inner while loop finishes, we print the line that has been built up. The key to understanding this program is where we append each digit's row string to the current row's line. Try running the program to get a feel for how it works. We will return to this program in the exercises to improve its output slightly.

+1 0

Post a comment