[Tutor] Linear programming - is it bad?

Brian van den Broek bvande at po-box.mcgill.ca
Tue Aug 10 05:48:57 CEST 2004

Eric Belanger said unto the world upon 2004-08-09 19:30:
> Hi!
> This is my first post here (ive been reading this list for a few weeks, 
> interesting content!).
> So my question: is it bad to write a python program/script in a linear 
> way? By linear, I mean: the code is executed line by line, without any 
> (programmer defined) classes or functions, a bit like [Q]BASIC without 
> GOTO's, or , while we're at it, HTML. I could also compare it to Doom 3: 
> going from A to B, then C, without any choices or options, until Z.
> I assume that by writing  huge projects/programs, im assured programmers 
> *needs* to use functions and classes. But since Im beginning, I dont see 
> the point.


> Thanks!
> Eric Belanger - bilange A gamebox _ net

Hi Eric,

I didn't take a look at the code you linked to (in the snipp'ed part), and 
I'm a relative programming newbie, so read what I say with your skeptic's 
goggles on ;-) (Also, having come to the end of writing this email, it 
seems I am in verbose-mode today. Oops.)

That said, so far in my own programming efforts, I've noticed two benefits 
of functions that I wouldn't want to live without:

1) Program logic that you use time and time again can be wrapped into a 
function, and them imported from a module into new code that you create.

As a simple example, in several of my first programs, I found myself 
opening a file, calling readlines on it, and then closing the file. Typing 
that each time seems silly (and typo-prone). So, without claim that its 
the prettiest such function in the world, I put the following into a 
module I called fileutils.py:

def reader(full_file_path):
     '''reader(full_file_path) -> file_contents (as a list)

     Given a full file path (or a file name in the current working
     directory), reader() uses the readlines() method of file objects
     to read the lines into a list, closes the file, and then returns
     the list.'''

     the_file_to_read = open(full_file_path, 'r')
     file_contents = the_file_to_read.readlines()
     return file_contents

Now, instead of retyping of copying and pasting, I can say

from fileutils import reader as reader

and then invoke the function as though I'd defined it in whatever program 
or interactive session I am in. Hassle-free, less to type, and the 
debugging was done once and for all.

(This function could certainly be improved (for instance, it could take an 
optional mode argument to allow for binary files, and I guess the call-tip 
part of the docstring really shouldn't imply a complete file path is 
needed), but since it is pretty much what I was typing each time, it saves 
me time and effort as is.)

2) Danny's point about functions being for helping humans read is very 
important. Write a 10-line function, debug it, and understand what it 
does. Then, when your code uses it, if you are trying to work out why 
exactly your program is doing some unexpected thing, instead of 
conceptually stepping through all 10 lines, you can read the one line with 
the function call as an extended Python command that does exactly what you 
created it to do. In effect, it packs trusted code logic into a single 
line. It's *much* easier to conceptualize your code that way.

Of course both points (1) and (2) depend upon a thorough test and debug of 
your function. And, it will surely happen that at some point, while 
enjoying benefit (2), you will be unable to see why your program is doing 
some unexpected thing. Eventually (and probably at 3am while feeling on 
the verge of going completely bonkers), you will be driven to examine some 
function very carefully only to discover that you were a bit too quick to 
decide that the function def did indeed do exactly what you wanted. That 
can make debugging more difficult, but get a trust-worthy, reusable 
function and you never have to debug that bit again. (A few such 3am 
experiences will certainly teach you to push the boundaries of a function 
in every which way while testing it *before* you decide to start importing 
it into other programs.)

Note too that you can get some, but not all, of the benefit of (1) by 
writing code in a linear manner. If you do it fresh each time, every time 
is a new chance to make an error. You might think to get around that by 
copying and pasting from the original source. Doing that, you can be 
reasonably sure there are no bugs in the lines you paste.

What you cannot be so sure of is that there are no bugs caused by the 
interaction of the pasted code and the code it is pasted into. (You must 
be much more skeptical that the code does exactly what it is supposed to 
do in the new context than you need be of well-tested functions that you 
import.) Take, for example, my reader example from above. If I did it in a 
linear manner, I'd run the risk that I might put those lines right into 
the middle of a program where file_contents (say) already had a meaning. 
The names in the pasted code and the pasted-to code might clash, creating 
possibly nasty bugs.

Functions avoid that; even if I copy and paste by reader's def block into 
a new program context, the name file_contents isn't top-level. Instead, 
it's a name in the function's namespace; if I have a file_contents 
variable in my top-level code the two can live in peace and harmony, never 
stepping upon each other's toes since each has its own namespace. (Trying 
to get the same thing by pasting and then manually checking for 
name-clashes has two problems: (a) what a hassle!, and (b) you'd still be 
vulnerable to introducing new clashes as you extend the code.)

Anyway, that's about 3 times what I set out to type . . . .


Brian vdB

More information about the Tutor mailing list