Python has gained a lot of attention lately because it is a powerful mixture of different programming paradigms and styles. For example, it is one of the very few interpreted object-oriented programming languages (Perl being another example, but only relatively late in its existence). Python fans say it is especially easy to learn. Python was written and designed almost entirely by Guido van Rossum, who chose the name because he wrote the interpreter while watching reruns of the British TV show Monty Python’s Flying Circus. The language is introduced in Learning Python and covered in detail in Programming Python (both published by O’Reilly).
As nice and useful as Perl is, it has one disadvantage—or at least many people think so—namely, that you can write the same code in many different ways. This has given Perl the reputation that it’s easy to write code in Perl, but hard to read it. (The point is that another programmer might do things differently from you, and you might therefore not be used to reading that style.) This means that Perl might not be the right choice for developing code that later must be maintained for years to come.
If you normally develop software in C, C++, or Java, and from time to time you want to do some scripting, you might find that Perl’s syntax is too different from what you are normally used to—for example, you need to type a dollar in front of a variable:
foreach $user ...
Before we look into a bit more detail at what Python is, let us suggest that whether you choose to program in Perl or Python is largely a matter of “religion,” just as it is a matter of “religion” whether you use Emacs or vi, or whether you use KDE or GNOME. Perl and Python both fill the gap between real languages such as C, C++, and Java, and scripting languages such as the language built into bash, tcsh or zsh.
In contrast to Perl, Python was designed from the beginning to be a real programming language, with many of the constructs inspired from C. This does undoubtedly mean that Python programs are easier to read than Perl ones, even though they might come out slightly longer.
Python is an object-oriented language, but you do not need to program in an object-oriented fashion if you do not want to. This makes it possible for you to start your scripting without worrying about object orientation; as you go along and your script gets longer and more complicated, you can easily convert it to use objects.
Python scripts are interpreted, which means that you do not need to wait for a long compilation process to take place. Python programs are internally byte-compiled on the fly, which ensures that they still run at an acceptable speed. In normal daily use, you don’t really notice all this, except for the fact that when you write a .py file, Python will create a .pyc file.
Python has lists, tuples, strings, and associative arrays (or, in Python lingo, dictionaries) built into the syntax of the language, which makes working with these types very easy.
Python comes with an extensive library, similar in power to what we saw previously for Perl. See http://www.python.org/doc/current/lib/lib.html for a complete library reference.
Most programming languages are best explained using examples, so let’s look at a Python version of the last log statistics script we previously developed using Perl. Your first impression of the script might very well be that it is way longer than the Perl script. Remember that we are forcing Python to “compete” here in the area where Perl is most powerful. To compensate, we find that this script is more straightforward to read.
Also notice the indentation. Whereas indentation is optional in most other languages and just makes the code more readable, it is required in Python and is one of its characterizing features.
1 #!/usr/bin/python 2 3 import sys, re, string 4 5 minutes = { } 6 count = { } 7 line = sys.stdin.readline() 8 while line: 9 match = re.match( "^(S*)s*.*(([0-9]+):([0-9]+))s*$", line ) 10 if match: 11 user = match.group(1) 12 time = string.atoi(match.group(2))*60 + string.atoi(match.group(3)) 13 if not count.has_key( user ): 14 minutes[ user ] = 0 15 count[ user ] = 0 16 minutes[ user ] += time 17 count[user] += 1 18 line = sys.stdin.readline() 19 20 for user in count.keys(): 21 hour = `minutes[user]/60` 22 min = minutes[user] % 60 23 if min < 10: 24 minute = "0" + `min` 25 else: 26 minute = `min` 27 print "User " + user + ", total login time " + 28 hour + ":" + minute + 29 ", total logins " + `count[user]`
The script should be self-explanatory, with a few exceptions.
On line 3 we import the libraries we want to use. Having imported
string
, for instance, we may use
it as in line 12, where we use the method atoi
from the library string
.
On lines 5 and 6 we initialize two dictionaries. In contrast
to Perl, we need to initialize them before we can assign values to
them. Line 7 reads a line from standard input. When no more lines
can be read, the readline
method
returns None
, which is the
equivalent to a null pointer.
Line 9 matches the line read from stdin
against a regular expression, and
returns a match object as a result of matching. This object contains
a method for accessing the subparts of the match. Line 21 converts
the result of the division minutes[user]/60
to a string. This is done
using two backquotes.
In this section we look into developing a slightly more complicated application, which uses classes. The application is a reverse Polish notation calculator, and can be seen in Figure 21-1. For developing the graphical user interface, we use the Qt library, which is a C++ library wrapped for many different languages, such as Perl, Python, and Java.
The program consists of two classes: Display
, which is the area displaying the
numbers, and Calculator
, which is
a class for the calculator:
1 #!/usr/bin/python 2 import sys, string 3 from qt import * 4 5 class Display(QTextEdit): 6 def _ _init_ _( self, parent ): 7 QTextEdit._ _init_ _( self, parent ) 8 self.setAlignment( Qt.AlignRight ) 9 self.setReadOnly( 1 ) 10 11 def pop( self ): 12 lines = self.paragraphs() 13 if lines = = 0: 14 return 0 15 16 res = QString.stripWhiteSpace(self.text( lines-1 )) 17 self.removeParagraph(lines-1) 18 19 if ( res.isEmpty() ): 20 return 0 21 22 return res.toFloat()[0] 23 24 def push( self, txt ): 25 self.append( `txt` ) 26 27 class Calculator(QDialog): 28 # Constructor 29 def _ _init_ _(self, parent): 30 QDialog._ _init_ _(self, parent) 31 vlay = QVBoxLayout( self, 6 ) 32 self.insertMode = 0 33 34 # Create display 35 self.edit = Display( self ) 36 vlay.addWidget( self.edit ) 37 38 # Create button array 39 index = 0 40 for txt in [ "1", "2", "3", "+", "4", "5", "6", "-", "7", "8", "9", 41 "*", "C", "0", "Enter", "/" ]: 42 if (index%4) = = 0: 43 hlay = QHBoxLayout( vlay ) 44 index = index+1 45 46 but = QPushButton( txt, self ) 47 but.setAutoDefault(0) 48 QObject.connect( but, SIGNAL( "clicked()" ), self.buttonClicked ) 49 hlay.addWidget( but ) 50 51 # Function reacting on button clicks 52 def buttonClicked(self): 53 txt = self.sender().text() # Text on button pressed. 54 if txt = = "Enter": 55 self.insertMode = 0 56 57 elif txt in [ "+", "-", "*", "/" ]: 58 val1 = self.edit.pop() 59 val2 = self.edit.pop() 60 self.edit.push( self.evaluate( val2, val1, txt ) ) 61 self.insertMode = 0 62 63 elif txt = = "C": 64 self.edit.pop() 65 self.insertMode = 0 66 67 else: # A number pressed. 68 if self.insertMode: 69 val = self.edit.pop() 70 else: 71 self.insertMode = 1 72 val = 0 73 val = val*10+ txt.toFloat()[0] 74 self.edit.push(val) 75 76 def evaluate( self, arg1, arg2, op ): 77 if ( op = = "+" ): 78 return arg1 + arg2 79 elif ( op = = "-" ): 80 return arg1 - arg2 81 elif ( op = = "*" ): 82 return arg1 * arg2 83 elif (op = = "/" ): 84 return arg1 / arg2 85 86 # Main 87 app=QApplication(sys.argv) 88 cal = Calculator(None) 89 cal.show() 90 app.exec_loop()
The code may at first look like a lot of work; on the other hand, with only 90 lines of code we have developed a working application with a graphical user interface. Most of the work is really handled by Qt, and since this is not a book on programming with Qt, we will not delve into these issues too much. Let’s have a look at the code snippet by snippet.
Let’s start where execution of our application starts — namely, at lines 86 through 90. Of course execution starts on line 1, but the first 85 lines merely defined the classes, which doesn’t result in any code being executed.
Line 87 creates an instance of the class QApplication
, in contrast to other
languages such as Java or C++, you do not use the keyword new
to create an instance — you simply
name the class. The class QApplication
comes from
qt.py, which we include in a special way on
line 3: we say that all symbols from that module should be included
into our namespace, so we do not need to write qt.QApplication
. Doing it this way is
seldom a good idea, but it is OK in our situation, as all classes
from Qt already are namespaced by an initial
letter, namely Q
.
The QApplication
instance
we create on line 87 is the magical object that makes Qt process
events and so forth. We start this event processing by calling the
method enter_loop()
on line 90.
Details on this are beyond the scope of this book and are not needed
for understanding the example.
On line 88 we create an instance of the class Calculator
, and on line 89 we call the
method show()
, which takes care
of mapping the dialog on the screen.
Now let’s have a look at the class Display
on lines 5 to 25. This class
inherits the class QTextEdit
,
which is a widget for editing multiple lines of text. Inheriting is
done on line 5, where we specify the superclass in parentheses.
Multiple inheritance is also possible, in which case you would
simply write each superclass as a comma-separated list within the
parentheses.
Line 6 is the constructor of the class. The constructor is implicitly called whenever an instance of the class is created. The first argument is a reference to the instance itself. This reference is needed whenever a method of the instance is to be called.[*]
Line 7 is a call to the constructor of the superclass. We need to call the constructor of the superclass to be able to hand on the parent reference to the superclass. The parent reference is, among other things, needed to get the layout working in our GUI.
On lines 8 and 9 you see methods called on the object itself. These methods are defined in the superclass, but could of course have been from the class itself.[*]
On lines 11 to 22 we have a definition of the method pop()
. Again notice how we get a
reference to the object itself as the first argument of the
function. When calling this method, you do not hand it a reference
as the first argument, Python will take care of doing so itself. On
line 58 you can see such a call.
The implementation of the pop()
and push()
methods involves mostly Qt issues
that we do not care about in this context. So let’s just shortly
outline what they do. The push()
method appends a number to the end
of the text edit, whereas pop()
does the opposite — namely taking the last line of the text edit,
converting it into a number, and returning it.
Now let’s turn our focus to the class Calculator
, which is our GUI class that
you see on screen. To be a Qt dialog, it must inherit QDialog
, as we see it do on line
27.
Once again, the code is mostly about Qt, and as such not too
interesting in this context. There is one Python construct we still
haven’t seen, though: instance variables . On lines 32, 55, 61, 65, and 71 we assign to the
variable self.insertMode
, and on
line 68 we read this variable. Due to the self.
part of the variable name, it is a
variable that is local to the object, which is called an
instance variable. Had we had several
instances of the Calculator
class, then each of these objects would have had its own copy of the
insertMode
variable. In contrast
to languages such as C++ and Java, you do not need to declare an
instance variable. The first time you assign to it, it will jump
into existence, just like local variables do.
You can read all about Python at http://www.python.org or in Learning Python and Programming Python. If you are interested in learning more about Qt, then Programming with Qt (O’Reilly) might be interesting to you. There is also at least one book dedicated to developing Qt programs in Python: Gui Programming With Python: Using the Qt Toolkit (Opendocs).
[*] In languages such as C++ and Java, you do not need to
explicitly specify the object when calling methods on it from
within member functions. This is needed in Python, however,
where we couldn’t have replaced line 8 with setAlignment( Qt.AlignRight )
.
[*] All methods in Python are virtual, as is the case in Java, and unlike how it is in C++.