Chapter 1. Introduction
Developing decent software is difficult
— monstrously difficult, in fact. People are always looking
for miracle cures, silver bullets that will help them creating
great software in no time with no conscious effort. In fact,
almost everyone will agree to the existence of a ‘software
crisis'. Projects do deliver too little
functionality, too late and often of a too low quality. Frederick
Brooks was the first to note this, in his famous book
The Mythical Man-Month. More's
the pity that there aren't any miraculous solutions for the many
problems that plague software development.
There is simply no single innovation that
will make you ten times more productive, no single innovation that
will ensure that whatever you do, you will produce bug-free
software and no single innovation that will make your applications
run will all the vim and vigor your users desire and
deserve.
However, it is quite possible, by simply
using the best possible tools and practices, to be far more
productive than would be possible by following the usual practices
and by using inferior tools.
It's amazing how many software development
environments have been designed with something else than developer
productivity as the main goal. There's Visual Basic, which, while
infinitely more productive than previous attempts at creating a
rapid development environment for Windows, still is mainly
concerned with preventing people from creating applications that
can compete with Microsofts' own applications. Java, while quite
usable, tries far too hard to protect me from myself and my
colleagues — like early versions of Pascal. C++ is
enormously large and complicated, because of its compatibility
goals with C — almost too big to learn to handle. In
contrast, Python was designed to be small, practical and to be as
open as possible to the developer.
In Python, all other considerations, are
secondary to considerations of development speed, code
maintainability and code reusability.
Python offers everything you need to put the
best practices into practice, like object oriented design, unit
testing and maintaining documentation in the code, but it doesn't
keep you from messing with the more messy parts of the operating
system — you can always use an extension module written in C
or C++ — or with the internals of Python itself. It is ideal
for rapid prototyping, but also for the development of large
applications by large teams of programmers.
Python code is meant to be readable.
Indenting correctly and neatly is not merely a good habit: it is
essential to delimit blocks of code. Likewise, there is little use
for comic-book swearing characters like ‘!@#$#%$' that other
languages use to indicate the type of a variable, or even for
variable declarations and all those other things that keep you
from writing the logic of your application. The most famous
description of Python is that it's ‘executable
pseudo-code'!
However, what Python has been lacking until
recently was a good development environment. Of course, since all
Python code is simple text, and since you don't need
pre-processors or compilers, you can get by with nothing more than
a text editor, like XEmacs
Nedit, or
MultiEdit. Indeed, I've used
Nedit exclusively for years — but
some project management facilities, a tighter integration with a
GUI builder and a good debugger can make life infinitely more
pleasant, and thus productive.
BlackAdder is
such an environment. Others are Wing
IDE, PythonWorks,
PythonWin,
Komodo and, perhaps,
IDLE. Of these, only
BlackAdder runs on both Windows and
Linux, includes a full-featured GUI designer and provides a
dependable debugger. Applications developed with Python and
BlackAdder can run on any Unix platform with X11 and on any
32-bits Windows platform (and in the near future on Apple's OS X,
too).
Python
Python is a modern programming language, with strong
object-oriented features, a small set of basic functions and
large set of libraries. The most important features of Python
are:
Compiled to byte-code, interpreted by a virtual
machine.
High-level data structures: lists, tuples and
dictionaries
Dynamic: you can even add new base-classes to an
existing object, run-time.
Portable: the same Python bytecode
will run — depending on which version of Python you
use and which C or C++ extensions are used — on Unix,
Windows, MacOS, Amiga, Palm OS and many others.
Extensible with modules written in
C or C++: there is no performance
penalty for calling native code, as there is when calling
native code from Java.
An object-oriented programming
model, but also supports functional programming (a bit) and
old-fashioned structured programming.
Enormous set of extension
libraries: for database access, high-performance
number-crunching, for sound-file analysis, for GUI
programming and countless other tasks.
Built-in regular expression engine
that works on both regular and Unicode strings.
Use of indentation instead of braces
begin/end pairs to
delimit blocks of code. This practically forces readable
code.
Your Python code resides in files, ending
with .py suffix. These files can be grouped
in modules, in the form of directories with an indexfile called
__init__.py, and you can import elements
from modules and files in other files. There is one file you use
to start your application. It will usually simply import the
necessary modules and start the application explicitly in a
main (args) function.
Maybe the introduction is bit early to
start with actual code examples, but let's have an example of a
Python bootstrap script anyway:
Python is, like Java, a language that is
compiled to bytecode. Python uses a virtual machine to run the
bytecode. This virtual machine is written in C and interprets
each byte-code instruction, translates it to real machine code
and then runs it. The Python virtual machine differs from the
Java virtual machine in that the byte-code instructions are a
bit more high-level, and that there are no JIT-compilers that
pre-compile chunks of byte-code to native machine code.
The translation from Python code to
byte-code only happens once: Python saves a compiled version of
your code in another file with the extension
.pyc, or an optimized compiled version of
your code that removes assert statements and line-number
tracking in a file with the extension
.pyo.
However, that is only done with Python
files that are imported from other files: the bootstrap script
will be compiled to bytecode every time you run it, but python
will create a myapp.pyc from a file
myapp.py (which is not shown here).
Interpreted languages, even byte-code
interpreted languages, have a reputation for sluggishness. On
the other hand, modern computers have a well-deserved reputation
for excessive processing power. The combination means that an
application written in a interpreted language can be fast enough
for almost any needs.
Certainly, anyone who has ever tried to
use a full-scale Java GUI application will know the exact
meaning of the expression ‘slow as frozen treacle'. There
are several reasons for the abominable slowness of Java
applications, the most important of which is the fact that all
Java Swing gui elements are also written in Java. Every pixel is
put on screen by Java. Python, on the other hand, makes clever
use of available GUI libraries that are coded in C or C++ and
thus run as native machine code.
The ease with which Python can make use
of native libraries is one of its strong points. Thanks to this
extensibility, you can write the logic of your application in
Python, and later rewrite the bottlenecks in C or C++. But even
without writing extension libraries, I have never encountered
any problem with the performance of a Python application.