Dec 01 Python
Volume Number: 17 (2001)
Issue Number: 12
Column Tag: Python on the Mac
by Rob Bedford
Using Python on the Macintosh
Introduction to Python and MacPython
Introduction
This article is intended as an introduction to the Python language on the Mac. While this will require the introduction of the MacPython environment, it is not intended as a review of the MacPython environment. Python is an easy to learn language that is an excellent tool for making prototypes and quick GUI front ends. The Mac implementation also has hooks for Mac specific functionality such as Applescript and Quicktime. Hopefully this article will lead toward the reader further exploring Python.
Overview
Python is open source and the license is GPL compatible (as is MacPython). MacPython is the Mac implementation of the Python language. The package includes an interpreter capable of executing text files, an IDE, a GUI toolkit, and droplets to make applets or applications. The current version (2.1) is capable of running on System 9 or X (native) however the GUI toolkit does not run native on X at this time.
While Python files can be created with any text editor, the included IDE provides the ability to execute from the editor and access to a debugger in addition to file creation. The error reporting from within the IDE also tends to be more verbose and useful than those reported by the interpreter. While not necessary on the Mac, files should end in .py for compatibility with other operating systems.
The GUI toolkit is called Tkinter and is a Python implementation of Tk. Tk is the graphical toolkit created for building graphical user interfaces with TCL. While originally for TCL, Tk has been ported to Perl and Python also. Although there are other GUI toolkits available, Tkinter is the Python standard and has excellent support, portability and functionality. Among the widgets provided by Tkinter are Entry Field, Menu, Scrollbar, Button, Checkbox, Radiobutton, Scale (slider), Listbox, Text, Canvas and a variety of Canvas drawing widgets. The toolkit also provides three geometry managers grid, pack and place, which can be used individually or in combination. The grid manager aligns all objects within a grid. The pack manager is similar to packing in Java with the objects arranging themselves based upon window content and shape. The place manager places a widget at a precise coordinate.
WxPython is an alternative GUI toolkit that was not easily available at the time this article was written, however indications are that it will be available soon. While this toolkit is not as accepted for use with Python, it has some advantages that Tkinter does not such as printing support.
Python can be run as an interactive script or interpreted. To run interactively, open the Python interpreter and type the code into the provided window. Pressing Enter or Return causes the code to execute. To run Python code in interpreted mode, drag and drop the text file unto the PythonInterpreter application. However if desired an applet can be generated by either choosing Save As Applet while in the IDE or dropping the file on the BuildApplet droplet. Note that the created applets require that Python be installed to run. If a standalone application is desired there is a BuildApplication droplet provided for the task. When using the BuildApplication droplet if a syntax error is reported and the same code executes fine from the IDE and interpreter, be sure that the last line is blank (no tabs). This is probably caused by the script looking for code due to the indentation.
Python can be extended using C. This provides a seamless interface to native C code for faster execution.
Language
Python is an interpreted language that self compiles to byte code when possible. Python has good performance for an interpreted language but the speed increases after one run since all subsequent runs are from compiled byte code.
Python is fully object oriented (even integers are objects) however it can also be used as a sequential language. The syntax is C-like except that there are no end of line markers or braces used. The block structure is implemented based entirely upon indentation. Thus Python code is formatted into a readable structure by necessity. Python comments are indicated by # with everything after the # treated as a comment. Multiple lines of code cannot be commented in blocks however Python does provide a doc string that provides multi-line comments. There are tools that extract doc strings to create documentation from Python source files.
Python variables are typeless objects, however while data is stored there is a type associated with it. Thus a string can be stored in a variable then be overwritten with an integer.
In addition to standard types such as integer, string and real, Python defines dictionaries, lists and tuples. Although these types at first seem simple these additional types are very powerful. One example of the power would be using lists as dynamic structures. Also the structure can be extended and since the data is further down the list it will not effect most code that already exists.
Lists can contain anything. The elements need not be of the same type and can even themselves be lists. An index is used to access or change data. Additionally, you can slice sections out of them or concatenate them together. Tests for membership and length are also available.
Strings are very similar to lists with the elements containing characters. However strings are immutable and thus cannot be changed in place. For instance it is possible to add a group of characters to a string variable and then reassign a new group of characters. However single characters within the string variable cannot be altered (immutable).
Tuples are similar to lists but tuples are immutable. While this seems to be an unnecessary duplication of lists it allows const-like operation.
Dictionaries are collections of data that are accessed by key. This provides better performance on large collections of data than lists.
When using Python in an object oriented fashion self provides a reference to the referring object. When defining a function in Python self must always be the first parameter in the argument list. When calling a function the self parameter is passed by default. The Super keyword references the objects parent class. Also when using Python as an object oriented language functions whose names begin and end in double underscores have special meaning. __init__ is called upon object initialization. __add__ and __mul__ are used to overload + and – respectively. Others are defined and are left to the reader to find.
Python also provides functionality that is associated with scripting languages such as the ability to execute external applications and regular expressions.
Starting Python
Begin by obtaining and installing Python. The official Python Language website is http://www.python.org and the official MacPython website is http://www.cwi.nl/~jack/macpython.html. First go to the Python site and download the documentation for Python. The documentation is not included in the MacPython distribution but is well done and worth the download time (the tutorial is highly recommended). Then go to the MacPython site and download the full installer.
The documentation expands to nine pdf files:
Api.pdf | Python/C API Reference Manual |
Dist.pdf | Distributing Python Modules |
Doc.pdf | Documenting Python |
Ext.pdf | Extending and Embedding the Python |
| Interpreter |
Inst.pdf | Installing Python Modules |
Lib.pdf | Python Library Reference |
Mac.pdf | Macintosh Library Modules |
Ref.pdf | Python Reference Manuals |
Tut.pdf | Python Tutorial |
The Python Library Reference and Python Reference Manuals will be used frequently and are worth converting trees to documents. The Python Tutorial is excellent and worth going through once. The other documents are useful but can be deferred until a higher level of proficiency is achieved.
Using Python
To illustrate the use of Python four examples will be presented, a simple Hello World, a GUI Hello World, a droplet or application to set the file creator code of text files, and finally a demonstration of various Tkinter widgets.
Hello World
Here is the traditional Hello World program. Open the Python IDE and select New from the File menu. In the new text file enter:
Print ‘Hello World’
Then press the Run All button. Your first Python program has just run.
Graphical Hello World
But Macs are graphical so next a graphical Hello World is next. The first line imports the Tkinter library for use. This can also be performed using from Tkinter import * which negates the need to use the Tkinter prefix. However the longer form was used to illustrate where Tkinter widgets are being used. Then Tk is started and stored in the variable base. After this we add the Button by passing it a container, in this case base, and the text to display. After setup is complete we enter the mainloop and are done.
import Tkinter
base = Tkinter.Tk()
Tkinter.Button(base, text = ‘Hello World’).pack()
base.mainloop()
Creator Code Editor
The following code is for a program to change the creator code of the file. The default operation is to read from a text file named type_preferences (in the same folder as the code) the creator code and type code (‘TEXT’) and set files that are dropped on it to that creator code. Files that are not of type ‘TEXT’ are ignored. Also the creator code can be set to the desired application by dropping it on the applet.
The code starts by importing the desired symbols. Although the imports are usually placed at the top this is not required. Go to the bottom and find if __name__ == ‘__main__’: this rather odd looking construct is very useful. If this module is imported into another program this code causes the main function to be ignored, however if execution begins in this module the check is true and main is executed. This allows each module to be tested in a standalone mode and contain test code that does not need to be deleted when the module is integrated. The main for this program is simple. Main checks the length of sys.argv and either creates a CFiletyper object or displays instructions to the user. To make this program more useful a GUI could be added in place of the display of instructions that allows the user to open files or set options via the GUI. So what is sys.argv? It is a list that contains the name of the applet including its path when the applet is double clicked. If items are dropped on the applet the name (including path) of each file is appended to the list containing the executing files name.
Upon creation of the CFiletyper object its __init__ routine is called. Now go back to the top of the code and examine the class declaration. Take notice of the colon as these are the one exception to delimiters and are easy to forget. The __init__ function is the standard constructor for Python. The first thing the routine checks is for argv lists of size two. If the size is two a FileSpec is created to store the file’s creator and type codes. Notice that creator and type codes are assigned in a single statement. If the type is ‘APPL’ in the file the user has dropped, a file called type_preferences is either opened or created. The new creator an type codes are then written to the file and the file closed. C programmers will find this code very familiar, because Python provides a wrapper for the C file routines. For Python experts all the resources needed to make extensions are available at the Python websites. After the data is written to the file the applet exits back to the finder.
If the type was not ‘APPL’ or the count was higher than two, then two routines are called. The first is getTypes that tries to open a file named ‘type_preferences’ that contains a type code and creator code. If this fails, assume the file is missing or corrupted and set the type code to ‘TEXT’ and the creator to Simple Text (‘ttxt’) then return. After the file is opened the text is stored in the list called data with each line becoming an item. The file is then closed. Then the data list is parsed, the first operation gets the first line and assigns the first four characters to self.Creator. The reason for taking only the first four characters is to delete the newline character. The same operation is then performed on the next item. The second function processFiles takes argv and slices off the program name creating a new list called fileList. Then get the fileinfo for each file using xstat. The last item in the list returned from xstat is the file’s type code. The type is checked to ensure it is a ‘TEXT’ file then set to the creator code to new creator code. The next two steps are not really necessary but provide the user some feedback by telling which files have been changed.
import sys
import os
import mac
import macfs
class CFiletyper:
def __init__(self):
#if one item was dropped see if it was an application
if len(sys.argv) == 2:
fileSpec = macfs.FSSpec(sys.argv[1])
self.Creator, self.Type = fileSpec.GetCreatorType()
if self.Type == ‘APPL’:
prefFile = open(‘type_preferences’,’w’)
prefFile.write(self.Creator)
prefFile.write(‘\n’)
prefFile.write(‘TEXT’)
prefFile.close
else:
self.getTypes()
self.processFiles()
#otherwise process files
else:
self.getTypes()
self.processFiles()
def getTypes(self):
try:
prefFile = open(‘type_preferences’, ‘r’)
except:
self.Type = ‘TEXT’
self.Creator = ‘ttxt’
return
data = prefFile.readlines()
prefFile.close()
self.Creator = data[0][:3]
self.Type = data[1][:3]
def processFiles(self):
fileList = sys.argv[1:]
for file in fileList:
fileinfo = mac.xstat(file)
if fileinfo[-1] == ‘TEXT’:
fileSpec = macfs.FSSpec(file)
fileSpec.SetCreatorType(self.Creator,
self.Type)
print os.path.split(file)[1]
print ‘Changing the creator code to Python IDE’
if __name__ == ‘__main__’:
if len(sys.argv) > 1:
CFiletyper()
else:
print ‘Drag and drop files onto the applet ‘ +
‘to set creator’
print ‘Drag and drop application onto the ‘ +
‘applet to set creator’
Tkinter Demo
The Tkinter demo is a simple program that has a button, checkbutton, radiobutton and scale widget. The __main__ function starts by initializing Tk and creating a Frame to contain the widgets. This frame is then passed to the __init__ function of the Test class. Finally the Frame is packed with a two-pixel buffer in the x and y direction then the main event loop is entered. Note that although the baseWin can be packed before creating the Test object the best results are always obtained when packing from inside to outside.
The Test class stores the frame passed for later use. Then creates a button widget and assigns the clicked function to it. The lambda declaration allows s to be resolved when the button is clicked and has the benefit of stopping the execution of clicked at button creation. Lambda is a Python keyword that allows for a function to be declared in line. Thus the assignment to command is in reality to function pointer that calls self.clicked. The checkbutton is then created and packed followed by a call to MakeEntry. MakeEntry then creates a frame to contain the Entry field and the accompanying label. Finally a radiobutton and scale are created and packed.
from Tkinter import *
class Test:
def __init__(self, super):
self.super = super
Button(super, command =
lambda s = self : s.clicked(),
text = ‘Hello World’).pack()
Checkbutton(super, text =
‘A Check Button’).pack()
self.MakeEntry(super)
Radiobutton(super, text = ‘button 1’).pack()
Scale(super, orient = ‘horizontal’).pack()
def clicked(self):
self.super.bell()
def MakeEntry(self, super):
container = Frame(super)
Entry(container).pack(side = ‘right’)
Label(container, text = ‘Enter something:’
).pack(side = ‘left’)
container.pack()
if __name__ == ‘__main__’:
base = Tk()
baseWin = Frame(base)
Test(baseWin)
baseWin.pack(padx = 2, pady = 2)
base.mainloop()
Python Extensions
There is not enough space in this article to cover all of the Python extensions available. However Pmw (Python Mega Widgets) will be covered to illustrate the installation of an extension and because of the usefulness of Pmw for a beginner.
Pmw is a set of widgets that extend Tkinter. Pmw widgets are created in Python primarily for Windows. They provide a good example on how Tkinter can be extended and are very useful despite some flaws. While they work on the Mac the appearance is sometimes less than desirable. The notebook widget in particular has a terrible appearance that could not be used in a deliverable project.
To install Pmw go to the Vaults of Parnassus (see Resources) and download the current version. Once the files have been extracted, place the entire directory in the Python:Extensions folder. Launch the EditPythonPrefs utility and scroll to the bottom. Add $(PYTHON):Extensions:Pmw to the list and close the utility. Go to Pmw_0_8_3:Demos and drag and drop All.py to the interpreter, this should launch a demonstration of all the Pmw widgets. The same result could have been obtained with the utility created in the last section and double clicking to execute the code.
The Future
While the current implementation is good the future is even brighter. Because of the UNIX heritage of X and Python, support should only get better.
The exception to this may Tkinter support, if Apple were to provide a way to run X windows apps natively then Tkinter support would be optimal. However if Tkinter has to depend on a Tk port to Carbon or Aqua then the implementation is subject to more violatility.
Now for the good news, Python already can run native on X. And the event model and other UNIX aspects of OS X more closely follow the Python design paradigm than does windows.
Resources
In addition to the Python Language and MacPython site, another site worth visiting is the Vaults of Parnassus at http://www.vex.net/parnassus. While this site is not Mac specific it contains a wide variety of examples and other resources that are invaluable.
- BBEdit users can obtain a Python plug-in at http://homepage.mac.com/christopherstern. Note that this does not work with BBEdit Lite.
- While the documentation is excellent the following books will also be useful. While the Python documentation is excellent the Tkinter documentation is very poor and the Grayson book highly recommended.
- Learning Python (Help for Programmers), by Mark Lutz & David Ascher, March 1999, ISBN 1-56592-464-9
- Python and Tkinter Programming, by John E Grayson, 2000, ISBN 1-884777-81-3
- The Quick Python Book by Daryl Harms and Kenneth McDonald, 1999 ISBN 1-884777-74-0
- While the Learning Python book can be avoided if money is tight, the Tkinter book is a necessity. A fair portion of the book is dedicated to Pmw but the back has the best documentation available for Tkinter.
- The comp.lang.python newsgroup is also an excellent source of help. For Mac specific questions the PythonMac SIG is probably a better source though. For information on the PythonMac SIG go to the MacPython page.
Conclusion
Learning Python is both easy and worthwhile. Python is a mature language and useful tool for programmers and is suitable for projects of all sizes. The interpreted nature of Python allows for quick code/test cycles. The byte code compilation of Python yields better speed than traditional scripting languages. The community is very helpful and the tools actively supported. Python’s UNIX heritage will only make the mac future brighter. But most importantly Python is a pleasure to use.
Rob Bedford has worked on a variety of platforms implementing systems from embedded automotive to missile defense. When not coding Bob is riding his motorcycle while trying to find new waterfalls to make QTVR panoramas of.