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.
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:")
>>> a = 4 >>> a 4 >>> a + 1 5
>>> x = 1 >>> while x < 10: ... print x ... x = x + 1 ... 1 2 3 [etc]
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 REM Stuff UNTIL FNfinishedbecomes
while True:
# Stuff
if finished(): break
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 double(x): return 2 * x ... >>> double(4) 8
>>> def hello(): ... print "Hello World" ... >>> hello() Hello World
>>> a = hello() Hello World >>> print a None
>>> 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]
>>> 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 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 blueYou 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"
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 ENDPROCbecomes:
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!"
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 = bThe final result can be visualised like this:
a ----> [1,2,3] b ----> [1,2,3] <---- cThat 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 TrueThe 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 <---- bHowever, incrementing 'a' has the effect of creating a new number, and making 'a' point at that:
a ----> 2 b ----> 1You 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!
>>> a = [1, 2, 3] >>> a = None
a ----> [1, 2, 3]
[1, 2, 3]
a ----> None
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.
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 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...).
> stream% = OPENIN("MyFile")
> PRINT stream%
254
becomes
>>> stream = file("MyFile")
>>> stream
<open file 'MyFile', mode 'r' at 0x8151290>
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
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")
>>> import math >>> math.cos(0) 1.0
>>> 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.0You 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.
>>> 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
> PRINT 6 AND 3 2 > PRINT 6 OR 3 7 > PRINT 6 EOR 3 5 > PRINT 6 ^ 3 216becomes
>>> 6 & 3 2 >>> 6 | 3 7 >>> 6 ^ 3 5 >>> 6 ** 3 216BASIC 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 0There is no error, because python only evaluates as far as the 0 before realising the result is going to be false.
>>> def inc_a(): ... global a ... a += 1 ... >>> a = 1 >>> inc_a() >>> print a 2Also, 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 ENDPROCThis 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.
A few other interesting bits to look out for in python:
>>> "Pi is %.3f (to three decimal places)" % math.pi 'Pi is 3.142 (to three decimal places)'
>>> class Point: ... def __init__(self, x, y): ... self.x = x ... self.y = y ... >>> p1 = Point(3, 4) >>> p2 = Point(7, 8) >>> p1.x 3 >>> p2.y 8
>>> def double(x): return 2 * x ... >>> map(double, [1,2,3]) [2,4,6]
