InformationSoftwareDevelopmentTutorials Valid XHTML 1.0!SF logo

Python

Tutorials: Tutorials - Python - Basic Gtk+-2.0 application - DnD Loading - DnD Saving - Applet - Menus and options

This is a quick primer, mainly for ex-BBC BASIC programmers moving to python, although others may find it useful. Python is a clean, simple and elegant language which provides fairly direct equivalents to most BASIC statements, but for more advanced users also goes far beyond that.

Python makes an excellent language for writing ROX applications, and most of the ROX applications are written in it. However, for this primer we only consider general programming constructs without any GUI stuff. See the other tutorials for that. You'll also want to read the official python tutorial after this.

Getting started

Here's the familiar hello world program in BASIC and in Python:
PRINT "Hello World"
becomes
print "Hello World"
a = 4.5
b% = 3
c$ = "Hello World"
becomes
a = 4.5
b = 3
c = "Hello World"
d = None
number = input("Enter a number:")
Note: use raw_input() to get the exact string the user entered. The input() function tries to evaluate whatever you enter as an expression (eg, entering "1+1" will return 2).

Interactive mode

Like BASIC, python can be run interactively (type 'python' at the command prompt). Unlike BASIC, you don't need to write PRINT to evaluate things; in interactive mode, the result of every expression is printed automatically. >>> indicates the python prompt.
>>> a = 4
>>> a
4
>>> a + 1
5

WHILE...ENDWHILE

You can also enter multi-line statements, such as loops, at the prompt. The '...' prompt indicates that it's waiting for more input. Enter a blank line to complete the statement.
>>> x = 1
>>> while x < 10:
...     print x
...     x = x + 1
...
1
2
3
[etc]
Python has a 'break' statement that can be used to exit from a loop at any point:
10 Finished% = FALSE
20 WHILE NOT Finished%
30   REM Stuff...
40   IF FNerror THEN Finished% = TRUE:ENDWHILE:GOTO 70
50   REM More stuff...
60 ENDWHILE
70 PRINT "Done"
becomes
finished = False
while not finished:
        # Stuff...
        if error(): break
        # More stuff...
print "Done"

REPEAT...UNTIL

Python doesn't have REPEAT loops. These can normally be done directly as while loops, but if not, use break for the end condition. 'while True' is an infinite loop, as in BASIC.
REPEAT
  REM Stuff
UNTIL FNfinished
becomes
while True:
        # Stuff
        if finished(): break

IF...THEN...ELSE...ENDIF

If statements are very similar. The use of indentation means that there is no difference between single line and multiline statements. Note the `:'; this starts all nested blocks. The 'else' must go at the start of a new line (this prevents any confusion as to which IF the ELSE goes with, as is possible in BASIC).
if x > 0 and x < 10: print "OK"
else: print "Out of range!"
Like BASIC, python considers 0 to be false, and any other integer to be true. Unlike BASIC, python also allows non-integers:
>>> if "hello": print "yes"
...
yes
>>> if None: print "yes"
...

DEF FN

>>> def double(x): return 2 * x
...
>>> double(4)
8

DEF PROC

>>> def hello():
...     print "Hello World"
...
>>> hello()
Hello World
>>> a = hello()
Hello World
>>> print a
None

DIM ()

Python uses lists rather than arrays. They are rather more flexible (they can change size, for example).
>>> a = ["red", "green", "blue"]
>>> a
["red", "green", "blue"]
>>> a[0]
"red"
>>> a[1]
"green"
>>> a[2]
"blue"
>>> a[1] = "yellow"
>>> a[1]
"yellow"
>>> a[1] = 4
>>> a
["red", 4, "blue"]
>>> a[-1]
"blue"
>>> a[-2]
4
>>> a[1:3]
[4, "blue"]
>>> a[1:]
[4, "blue"]
>>> a[:1]
["red"]
>>> a[:-1]
["red", 4]

LEFT$, RIGHT$, MID$

Python has none of these. Instead, you can treat a string as a list of characters and use the indexing and slicing notation as for lists:
>>> b = "Hello World"
>>> b[0]
'H'
>>> b[1]
'e'
>>> b[-1]
'd'
>>> b[-2]
'l'
>>> b[1:]
'ello World'
>>> b[:-1]
'Hello Worl'
>>> b[2:4]
'll'

FOR...NEXT

Python's for loops are completly different to BASIC's. Instead of providing start, end and step values, you provide a list to loop over.
>>> for x in ["red", "green", "blue"]:
...     print "The next colour is", x
...
The next colour is red
The next colour is green
The next colour is blue
You can get the BASIC behaviour by using the range() function to create a list of numbers to loop over, but you'll find you almost never need to use this.
a$ = "Hello,Bye,Fred"
count% = 0
FOR c% = 1 TO LEN(a$)
  IF MID$(a$, c%, 1) = "," THEN count% += 1
NEXT c%
PRINT "String contains "; count%; " commas"
becomes
a = "Hello,Bye,Fred"
count = 0
for c in a:
  if c == ",": count += 1
print "String contains", count, "commas"
In fact, python provides a better way to count, as we shall see later.

ON ERROR LOCAL...RESTORE ERROR

Python error handling is much simpler, and doesn't require you to create a new function for each error trapping point.
 10 INPUT "Enter a number:", number%
 20 PROCrecip(number%)
 30 PRINT "Done!"
 40 END
 50 
 60 DEF PROCrecip(number%)
 70  ON ERROR LOCAL RESTORE ERROR: PRINT "Can't do that, sorry!": ENDPROC
 80  answer = 1 / number%
 90  PRINT "Result is", answer
100 ENDPROC
becomes:
number = input("Enter a number:")
try:
        answer = 1 / number
        print "Result is", answer
except:
        print "Can't do that, sorry!"
print "Done"
try:
        answer = 1 / number
except DivisionByZero:
        print "Can't devide by zero!"
except:
        print "Something wierd happened!"
If you don't provide a default handler ('except:') then the error is passed up to the enclosing 'try' block (possibly in a calling function) until it is either handled or there are no more try blocks. In that case, python prints out the error, giving not only the line number of the problem, but showing the call in each function leading to it.

Objects

Time to come clean... python is an object oriented language. This is a good thing, but requires a little adjustment to appreciate fully. Now, consider variables in BASIC. We think of a variable as a box with a label (the variable's name) and a value inside it.

In an OO (Object Oriented) language, the values exist outside of any boxes on their own. Variables merely 'point to' values. The difference is, two variables can point to the same value. Consider:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> c = b
The final result can be visualised like this:
a ----> [1,2,3]
b ----> [1,2,3] <---- c
That is, we have created two lists. 'a' points to the first, while 'b' and 'c' point to the second. The '==' test in python checks if two arrays contain equal values, while the 'is' test checks if 'two' values are actually one:
>>> a == b
True
>>> b == c
True
>>> a is b
False
>>> b is c
True
The difference is important when you change something:
>>> b[1] = 42
>>> a
[1,2,3]
>>> b
[1,42,3]
>>> c
[1,42,3]
On the other hand, if you assign something to 'b' (rather than modifying the thing 'b' points to), you make 'b' point at that instead:
>>> b = [4,5,6]
a ----> [1,2,3]
c ----> [1,42,3]
b ----> [4,5,6]
You might be a bit worried about this:
>>> a = 1
>>> b = a
>>> a += 1
>>> b
[ what goes here? ]
Don't worry. After assigning to 'b', 'a' and 'b' do indeed point at the same object (the number 1):
a ----> 1 <---- b
However, incrementing 'a' has the effect of creating a new number, and making 'a' point at that:
a ----> 2
b ----> 1
You cannot change the number which 'a' points to in-place (numbers are thus said to be 'immutable'). Strings are also immutable.

This means you can pass lists (arrays) to functions very quickly (because you're just making another pointer to the same array). If you want to copy a list, use the slicing notation to copy the whole thing:

>>> a = [1,2,3]
>>> b = a[:]
a ----> [1,2,3]
b ----> [1,2,3]
MAKE SURE YOU UNDERSTOOD THE ABOVE!

Garbage collection

OK, so we can create lots of new objects. How do we get rid of them again? The answer is simple: when it's no longer possible to refer to an object, python will free it for you:
>>> a = [1, 2, 3]
>>> a = None

Objects and methods

Because BASIC has only a few types, it tends to represent everything else with numbers. File handles are an example; window handles another. Python tends to create new types for everything. We have already seen a few types.

You can use a type like a function, to create a new object of that type. Eg:

>>> a = int("4")
>>> a
4
>>> b = float(4)
>>> b
4.0
>>> c = str(4)
>>> c
"4"
>>> d = list()
>>> d
[]
BASIC has a global selection of functions, and typically prefixes the names with types to avoid clashes. Consider:
account% = FNaccount_new()
PROCaccount_credit(account%, 100)
PRINT "Now has", FNaccount_check(account%)

door% = FNdoor_new()

PROCdoor_close(door%)
PROCaccount_close(account%)
Because python keeps track of types (and allows new ones to be created), it can automatically work out which of several functions to use, by keeping the functions 'inside the type'. Such functions are called 'methods':
account = Account()
account.credit(100)
print "Now has", account.check()

door = Door()

door.close()
account.close()
Here 'Door' and 'Account' are types (like 'int' or 'str'), while 'account' and 'door' are values of that type (like 4 or "Hello"). Notice how we use the type to create new objects ('instances') of that type.

Python knows that 'door' is a Door, so 'door.close()' calls the close function for doors, whereas 'account.close()' calls the close function for accounts. Most objects in python have many methods. Here are a few for strings:

>>> a = "Hello"
>>> a.upper()
"HELLO"
>>> a.lower()
"hello"
>>> "   spaces    ".strip()
"spaces"
>>> a = "Hello,Bye,Fred"
>>> print "String contains", a.count(","), "commas"
String contains 2 commas

While we're on the subject of strings, I should point out that you can use either single or double quotes, as desired:

>>> a = "Hello"
>>> a = 'Hello'
>>> a = '"Hello", she said.'
>>> a = '''In python, " and ' can be used to quote strings'''
Tripple quotes of either type can also be used, and these can span multiple lines. Strings can be any length (unlike in BASIC); you can read an entire file into a string if you want.

CASE ... OF

There is no CASE statement. You can use IF for a direct BASIC translation:
if x == 1:
        print "One"
elif x == 2:
        print "Two"
elif x == 3:
        print "Three"
else:
        print "Many"
However, as with FOR loops, you'll generally find that python makes such things unnecessary. Consider:
FOR creature_number% = 0 TO number_of_creatures% - 1
  CASE type_of%[creature_number%] OF
    WHEN 1: PROCmove_elf(creature_number%)
    WHEN 2: PROCmove_goblin(creature_number%)
    WHEN 3: PROCmove_dragon(creature_number%)
    ...
  ENDCASE
NEXT creature_number%
would likely be written in python as:
  for creature in creatures: creature.move()

ERROR

ERROR 0, "User error!"
becomes
raise Exception("User error!")
Exception is a type, so this creates a new Exception object and raises it as an error. It can be caught in a try block, as shown above. When you know how to create your own types, you can use that to create different types of error (any object can be raised as an error, even a string, but there are conventions...).

OPENIN, OPENOUT

> stream% = OPENIN("MyFile")
> PRINT stream%
254
becomes
>>> stream = file("MyFile")
>>> stream
<open file 'MyFile', mode 'r' at 0x8151290>
Note that 'stream' is not a string; that's just python's way of representing a 'file' object when you try to print it.

You can use the file type's methods to read from it:

>>> stream.readline()
'The first line\n'
>>> stream.readline()
'The second line\n'
>>> stream.readline()
'The end\n'
>>> stream.readline()
''
Each line read includes the newline character, so you can tell the difference between a blank line ('\n') and the end of the file ('').

More commonly, you'll use a file object as the sequence in a list. In this case, the loop iterates over the lines:

my_data = file('MyFile')
for line in my_data: print "Next line is", line
my_data.close()
Or, indeed:
for line in file('MyFile'): print "Next line is", line
For writing, pass 'w' to the constructor (the type used to create a new object):
stream% = OPENOUT("Output")
PRINT#stream%, "Hello World"
CLOSE#stream%
becomes
stream = file('Output', 'w')
print >>stream, "Hello World"
stream.close()
Note that print's syntax is slightly unusual for python, as it's a statement rather than a function. I've shown this system as it's the most BASIC-like. You can also use the write method of the stream object if you prefer:
stream.write("Hello World")

LIBRARY

>>> import math
>>> math.cos(0)
1.0
For example, most math functions exist in both normal and 'complex' forms:
>>> import cmath, math
>>> math.cos(0)
1.0
>>> cmath.cos(0)
(1-0j)
You can also pull in some names directly:
>>> from math import cos, sin
>>> cos(0)
1.0
>>> sin(0)
0.0
You can use import to split your own programs into several files. Name the files with a '.py' extension, and use import without the extension to load the file.

HELP

Use the help function to find out about anything in python. You can get help on functions, types and modules!
>>> import math
>>> help(math)
>>> help(math.cos)
>>> help(str)
Notice how we are passing apparently abstract ideas as function arguments! In fact, all these things are real python values, and can be assigned just like anything else:
>>> import math
>>> print math.cos(0)
1.0
>>> print math.cos
<built-in function cos>
>>> print math
<module 'math' from '/usr/lib/python2.2/lib-dynload/math.so'>
>>> a = math.cos
>>> a(0)
1.0

AND, OR, EOR, ^

Most python operators are the same as in BASIC. The bit-wise operators are different, however. EOR is written ^ in python, AND as & and OR as | (and ^ becomes **):
> PRINT 6 AND 3
2
> PRINT 6 OR 3
7
> PRINT 6 EOR 3
5
> PRINT 6 ^ 3
216
becomes
>>> 6 & 3
2
>>> 6 | 3
7
>>> 6 ^ 3
5
>>> 6 ** 3
216
BASIC also uses the bitwise operators AND and OR for boolean operations. Use the normal python 'and' and 'or' operators for this. These are 'short-circuit' operators; they only evaluate as far as they need to to get the result:
>>> 0 and 1/0
0
There is no error, because python only evaluates as far as the 0 before realising the result is going to be false.

LOCAL

Python doesn't have LOCAL; any variable assigned to in a function is automatically considered to be a local variable. Instead, the keyword 'global' must be used to indicate that a variable is NOT local:
>>> def inc_a():
...     global a
...     a += 1
...
>>> a = 1
>>> inc_a()
>>> print a
2
Also, the scoping rules are different. This isn't much of a problem, because python does what you'd expect, and BASIC doesn't. BASIC fakes local variables by storing the current global value on the stack and then restoring it when the function exits. Python does it properly. Consider:
 10 a% = 1
 20 PROCfoo
 30 END
 40
 50 DEF PROCfoo
 60 LOCAL a%
 70 a% = 2
 80 PROCbar
 90 ENDPROC
100
110 DEF PROCbar
120 PRINT a%
130 ENDPROC
This BASIC program prints 2, perhaps rather surprisingly.
def foo():
        a = 2   # Local variable
        bar()
        
def bar(): print a

a = 1
foo()
The python version prints 1, because the 'a' assigned in foo() is only accessible from within foo().

To be picky, when you use a variable without assigning to it, python uses the variable assigned to in the closest enclosing lexical scope. Which only matters if you're doing un-BASIC things, like defining functions inside other functions. And it still does what you'd expect:

def foo():
        a = 2   # Local variable
        def bar():
                print a
        bar()
a = 1
foo()
This prints 2, as you probably guessed.

Future reading

That's enough for now. Now play for a bit, and then read the offical python tutorial!

A few other interesting bits to look out for in python:

ROX project admin and website maintainer : Thomas Leonard [ GPG key ]
Please send questions about the ROX applications to the mailing lists, not directly to me.
Emails sent directly to me will likely be either ignored or forwarded to the list.