Chapter 1. Introduction

Table of Contents
Python
GUI programming with Python
About the BlackAdder IDE

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:

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:

Example 1-1. Bootstrapping a Python application

#!/usr/bin/env python                                      (1)
#
# bootstrap.py
#

import sys                                                 (2)
from myapp import SomeClass                                (3)

def main(args):                                            (4)
    class=SomeClass(args)
    class.exec_loop()

if __name__=="__main__":                                   (5)
    main(sys.argv)
        
(1)
The so-called ‘hash-bang' trick is useful on Unix systems only. If the first line of any text file starts with #!, then the system will try to execute the application that follows the #! with the rest of the file as input. In this case, the env utility starts python, which runs the rest of the script.
(2)
The standard Python module sys handles tasks like passing on command-line arguments and lots of other things. Here we import the module, so we can pass the command-line arguments to the application.
(3)
All application code is in separate modules; the first of these we import here.
(4)
This is the definition of the main function. By encapsulating this code in a function, it won't get run if this file were imported from another file.
(5)
In this line, we check if this is a top-level script, instead of a file imported from another file. This is done by looking at the variable __name__. If this is the toplevel file, then the main(args) is run.

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.