Programming and Teaching with Python

There are some things you need to know about Python before introducing it as a teaching language. I will assume you know Java in this.

First, the code is quite pretty - there will be no Ugly section here, Just the Good and the Bad. But its blessings are mixed as are its flaws.

The Good (and Sometimes Bad)

Python is a very dynamic language. It has a lisp-like core as well as an object-oriented core. It is pretty easy to use. Most everything you want to use is free (FOSS).

There is little syntax. Indentation is the critical things. Important declarative lines end with colons( if a < b : ), with the block indented (for spaces, no tabs, by convention)

For the most part Python is very uniform. What you learn caries over to new things pretty faithfully. Once you understand how dynamic it is, and the consequences of that, there are few gotchas.

Python has multiple inheritance. Simple uses (mixins) are good. Complex uses are bad.

Unlike Java, constructors are inherited. However, super calls (done by class name, not with a "super" keyword" are NOT done automatically. If you create a subclass of UrRobot for example, you don't need to write a constructor unless you need to actually do something in it. However, if you do write a ctor, make it start with an explicit call, like (yes, self is included as an arg here):

UrRobot.__init__(self, street, avenue, direction, beepers)

but replace UrRobot with the actual superclass (and its args) even if it doesn't have an explicit ctor, but inherits one. If you don't do this, nothing gets initialzied.

Things are very explicit in Python. If you have a method, mumble, of a class that you want to invoke from another, the reference is self.mumble(...). The same is true for fields. This is good. But if you forget self on the left side of an assignment you will just create a new local variable. Bummer.

Mixin multiple inheritance is very nice and very natural. It is one of the really great features of such dynamic languages. Very expressive.

Functions (and methods) are first class objects. They can be passed as arguments, etc. There is a lambda function for creating anonymous functions on the fly.

Python has built in lists, tuples (both examples of sequences) and dictionaries (maps). They are easy to use and both use the same syntax for access. For example, mumble[3] micht be the fourth elment of a list, or the value in dictionary mumble that has key 3. This makes for very smooth use.

Catenate lists or union dictionaries with +.

Tuples are immutable sequences. Lists are like lisp lists and append, pop make a stack like thing. There are no arrays. use lists or dictionaries instead (or tuples if they should be immutable).

Operators can be overloaded. I don't know much about this.

Files of text are easy to use. There is infrastructure similar to Java's Scanner/Tokenizer stuff, but very simple.

You can add things to an object directly, similar to JavaScript. Don't know if this is good or bad. It doesn't seem to be as uniform as everything else in the language.

Exceptions will be familiar to Java programmers (try...except, rather than try...catch)

The Bad (and Sometimes Good)

There are no declarations. Nothing is done until it is executed. Very little is even checked until it is executed. Test - Test - Test. Then do some testing.

There is no name overloading in Python. One constructor per class, one method with a given name.

Python has no real notion of a constant.

It has no real notion of private-hidden features. Everything like that is done by convention only. This affects how you teach it and also requires discipline in its use. A class attribute name beginning with a single underscore (_foo) is pseudo-private. A name beginning with two underscores (__bar) will be handled in a special way and harder to use outside the class since its name will be given a special, mangled, form outside the class. But it still isn't private, except by convention. Proceed with caution.

If you call a python function (or equivalently, send a message) and forget the parentheses, it won't be an error, but nothing will happen. The function name without parentheses is just an expression that evaluates to the function. With the parentheses it is an invocation without arguments. It is easy to get caught with this one (blush).

The compiler does very little checking of correctness of your program. It will find most syntax errors and lexical errors where it expects keywords, but not much else. You need to actually execute every line of your program even to find something as simple as a mis-spelled variable name. This will be a big pain moving from a statically typed language like Java. This is a direct consequence of its dynamic nature.

In Python you don't declare fields. You just assign something to (say) self.field to get a field named (ta da) field. The problem with this is that if you later (anywhere in the class) misspell the field name you may wind up with another field. So if you also, by mistake assign to self.feild you have a new field that will, perhaps, mess you up. This is another reason to make sure that your unit tests test EVERY line of your code.

In unit tests, don't use Python's built in assert statement. While it is convenient, the messages won't be as informative. Instead use the methods defined in the unit test structure unittest.TestCase and robottestcase.RobotTestCase, Monty Karel comes with this test framework that allows assertions about robots.

Note, by the way, that simply verifying that your code is correct by visual inspection (desk-checking) is not sufficient in a program that may change. It may work NOW, but after a change may BREAK. If your tests cover every line adequately, then you will learn of the problem the next time you run ALL the tests. Otherwise you will be misled, unless you want to visually re-verify ALL the code. UGH. Tests are not there to assure you get the code right the first time, though they do help with that. They are there to assure that changes don't break something that was once working.

In the Karel code, directions are functions with a robot argument. We provide North, South,... functions. However it is possible to pass ANY such function in the constructor (CTOR). I don't know if this is a bug or a feature. It may be a feature, actually, except that if you do this, then turnLeft has no effect. The direction functions are responsible for knowing how to move a robot (in their direction)

In python unit tests. A test MUST begin with test... Otherwise it won't be executed at all. This is consistent with earlier versions of JUnit, actually.

Since the language is so dynamic and the interpreter can't give you much information about correctness of your program until you execute each line, I've found the tool called pychecker to be very helpful. It gives you a report about your py files (it runs from a command line/window). In particular it can help you find misspellings of things, as well as dead code. In one function I forgot the word return in front of a return value and it caught it as "statement seems to have no purpose". The one thing it has some trouble with is recursive imports. More trouble than the interpreter, actually. So if you have too complex an exchange of information between two or more files, it may fail. But then you should think about simplifying the structure anyway.

Just the Facts

Python files are called modules and end in .py. They can contain several classes and ordinary functions. They can be imported or executed (if they have a "main" function). When they are imported any top level (unindented) statements are executed. Module names are all lower case by convention.

Python packages are similar to Java packages (folders of modules). They need a file named __init__ in them to permit imports. The file may be (and usually is) empty.

You will need a system PYTHONPATH variable set unless you use some IDE like Eclipse that manages its own path structure.

Jython is a version of Python that is written in Java and has access to all of the Java libraries (AWT, Swing...). If you work on a machine that supports both, then Jython is an easy way to get access to a standard GUI library. Python has bindings to several other libraries (tk, gtk, etc), but they may not give you the same portability that Jython does.

You will be happier if you adopt the conventions from the beginning. Happier still if you use an ide that supports the standard convention. I use Eclipse, PyDev, Jython, and pyunit inside Eclipse and pychecker and pydoc as standalone aids. I'm trying to get set up with pygtk but having a hard time (on the mac -- easier on the pc).

Python is one of the core languages on the OLPC.


Last Edited: January 2, 2008