Technical Activity Holiday for 12-15s

Python course: Home - Worksheets - Package - Developers - Licence - Credits

Python for the Inexperienced

Gareth McCaughan, 1999

A note about web browsers: This sheet uses a few newish features of HTML. If you're reading it online with an old browser, you may find that a few unimportant things come out wrongly: for instance, some quotation marks may disappear. I think nothing vital is lost even with the nastiest oldest browsers.

Contents

  1. Blurb
  2. Getting it running
  3. First steps
  4. Variables
  5. Loops and things
  6. The if statement
  7. More about loops
  8. More about lists
  9. More about strings
  10. Functions
  11. Odds and ends
  12. An example program


Blurb

Python is an elegant modern programming language, intended to make easy things easy without making hard things impossible. This brief introduction is intended to do the following:

  • Give you some idea of what the language looks like;
  • Teach you enough that you can easily find out more without further help;
  • Demonstrate how easy Python is to learn.
Unfortunately, it isn't nearly brief enough. You don't need to be an expert programmer to read this sheet. In fact, if you are then you probably want the Python for the Impatient sheet instead of this one. (You might want to read that when you've finished this one; it mentions a few things that aren't covered here.) I'll assume that the only programming language you know is BASIC, but I'll mention other languages too from time to time just to give a bit of perspective. You won't miss anything important by not knowing those languages.

You'll probably find that this stuff sticks in your memory best if you try all the examples. But if you don't have a copy of Python handy, don't worry.

Python is byte-compiled, object-oriented, lexically scoped and has exceptions. If you know what any of that means, you probably shouldn't be reading this introduction.

Getting it running

I need to find out about how this works on systems other than mine. I'm sorry there's no useful text here yet. Anyway, this is basically rather easy. If you have an installation of Python at all, you probably already know what to do.

First steps

So, you have a window in which Python is running. It should be displaying a prompt that looks like this:

        >>> 
      

Whenever Python displays that prompt, you can type in any expression and it will evaluate it for you:

        >>> 1+2*3
        7
      

Expressions are not limited to arithmetic. You can work with strings:

        >>> 'foo' + 2*'bar'
        foobarbar
      
or with lists:
        >>> [1,2,3] + 2*[4,5]
        [1,2,3,4,5,4,5]
      
or with all sorts of other things that we'll meet later.

One brief word of warning about arithmetic.

        >>> 7/3
        2
      
Notice that it doesn't say 2 1/3 or 2.33333333; it just throws away the fractional part of the answer: that's just what Python does when working with integers. If you force it to realise that it might not be working only with integers, all is well:
        >>> 7.0/3
        2.33333333333
      
This is one of the few Really Annoying Things in Python.

Variables

Like pretty much every other programming language, Python has variables. You use them in much the same way as in other languages:

        >>> my_salary = 12000
        >>> print 'Your salary is $', 2*my_salary
        Your salary is $ 24000
      
(It would be nicer not to have the space after the dollar sign. More on output later.)

A variable can hold any kind of value.

        >>> name = 'Frederick'
        >>> print name + ' has two cats.'
        Frederick has two cats.
      

Loops and things

The for loop

Here's something a bit different.

        >>> for n in 2,3,5,7,11:
        ... 
      
Python is suddenly presenting you with a different prompt. The ... means: You've started to say something but you might not have finished. Do go on. In this case, the for introduces a loop: whatever follows will be done five times, once with n=2, once with n=3, ..., once with n=11.

But you need to tell it what exactly you want to do five times. For instance:

        >>> for n in 2,3,5,7,11:
        ...   print n, 'squared is', n*n
        ... 
        2 squared is 4
        3 squared is 9
        5 squared is 25
        7 squared is 49
        11 squared is 121
      
The extra spaces in the second line are important; they are how Python knows exactly what material is within the loop. BASIC manages this by ending a FOR loop with NEXT; C manages it by surrounding the contents with { ... }. With both these languages (and all others) it's usual to indicate the structure of your program with indentation; with Python it's necessary. The meaning of the program depends on how it is indented!

(On the third line, just press enter. The machine will understand that this means you've finished entering your command.)

Ranges

As you can see, Python's loops are a bit different from BASIC's and C's. (And from those in most other languages, too. Lisp has something similar.) Instead of giving a range of values (as in BASIC), or a recipe for getting from each value to the next one (as in C), you give a list of values. Obviously this is more flexible; but what if you want to get the same effect as BASIC's FOR loops?

        >>> range(1,5)
        [1, 2, 3, 4]
      
Aha!
        >>> for n in range(1,5):
        ...   print n, 'squared is', n*n
        ... 
        1 squared is 1
        2 squared is 4
        3 squared is 9
        4 squared is 16
      

You may be wondering why range(1,5) doesn't go all the way up to 5. There isn't really a simple answer, other than that lots of programmers are used to working that way. It does mean, for instance, that range(1,5) + range(5,8) = range(1,8).

If you want the effect of BASIC's STEP keyword (to go up in different units), you can have that:

        >>> range(1,20,3)
        [1, 4, 7, 10, 13, 16, 19]
      
(If you'd said range(1,19,3) then 19 wouldn't have been included.)

The while loop

Most languages have a way to say: Do this over and over until some condition is met. Python is no exception. Here's how it works.

        >>> n=3
        >>> while n<1000: 
        ...   print n,
        ...   n = n*2
        ... 
        3 6 12 24 48 96 192 384 768
      

This is our first encounter with Boolean expressions: things like n<3 that can be either true or false. Python actually represents Boolean values with integers:

        >>> 1000<3
        0
        >>> 1000>3
        1
      
Indeed, every value Python can work with is considered either true or false. The number 0 is false; so are the empty string '', the empty list [] and a few other special values. (Numbers other than 0 and non-empty strings and lists are all considered true.)

The if statement

Python has an if statement much like any other language's.

        >>> if 100<3:
        ...   print 'I am the walrus'
        ... else:
        ...   print 'They are the eggmen'
        ... 
        They are the eggmen
      

Like almost every other language (but unlike some versions of BASIC), Python allows you to do this:

        >>> n=3
        >>> if n<0:
        ...   print 'n is negative'
        ... elif n>1000:
        ...   print 'n is huge'
        ... elif n%2 == 0:
        ...   print 'n is even'
        ... elif n%3 == 0:
        ...   print 'n is a multiple of 3'
        ... else:
        ...   print 'n is boring'
        ... 
        n is a multiple of 3
      
(You use ==, not =, to test whether two things are equal or not. And the % sign means modulo, or remainder on division by. Most versions of BASIC have this, under the name MOD. So 10%3==1 is true.)

More about loops

Sometimes you may want to get out of a loop before it has finished, or skip to the end of one iteration. Python has statements called break and continue to do these things. They work in for loops and in while loops.

        >>> for n in range(1,6):
        ...   print 'Trying', n
        ...   if n<3:
        ...     continue
        ...   if n==2 or n==4:
        ...     print n, 'is magic'
        ...     break
        ... 
        Trying 1
        Trying 2
        Trying 3
        Trying 4
        4 is magic
      

Sometimes you care whether a loop ended normally or with a break. If you attach some code to the end of the loop with else, Python will execute it if and only if the loop ended naturally.

        >>> n=11
        >>> for p in range(2,n):
        ...   if n % p == 0:
        ...     print n, 'is not prime'
        ...     break
        ... else:
        ...   print n, 'is prime'
        ... 
        11 is prime
      

More about lists

Lists in Python can do everything arrays can in BASIC, and more. Here are a few illustrations.

        >>> a=[1,2,3,4]
        >>> a
        [1, 2, 3, 4]
        >>> a[1]
        2
        >>> a[2]=99
        >>> a
        [1, 2, 99, 4]
        >>> a[1:3]
        [2, 99]
        >>> a[1:3] = [9,8,7]
        >>> a
        [1, 9, 8, 7, 4]
        >>> len(a)
      

Maybe it's time for a few explanations. The elements of a list a are a[0], a[1], and so on up to a[len(a)-1]. You can refer to a slice of the list a with the notation a[m:n], which means the list consisting of elements m (inclusive) to n (exclusive). Notice that this funny inclusive/exclusive thing is just the same as for the range function.

A couple of other handy things... You can count elements of a list from the right-hand end ...

        >>> a=[1,2,3,4]
        >>> a[-1]
        4
        >>> a[-3:-1]
        [2, 3]
      
... and when doing slices you can miss out either of the two numbers; Python will use the ends of the list by default.
        >>> a=[1,2,3,4]
        >>> a[:2]
        [1, 2]
        >>> a[2:]
        [3, 4]
        >>> a[:]
        [1, 2, 3, 4]
      
(That last one looks a bit silly, but it can be useful if you want to make a copy of a list that you can change without changing the original.)

More about strings

Strings behave very much like lists.

        >>> name='walrus'
        >>> len(name)
        6
        >>> name[2:]
        'lrus'
        >>> name[2]
        'l'
        >>> name[-3:]
        'rus'
      

However, you can't modify a string:

        >>> name='eggman'
        >>> name[5]='e'
        Traceback (innermost last):
          File "", line 1, in ?
        AttributeError: __setitem__
      
(Ouch! Never mind exactly what that means...)

But of course you can build up a new string instead.

        >>> name='eggman'
        >>> name[:4]+'e'+name[5:]
        'eggmen'
      

Functions

A function is a piece of program with a name. BASIC has functions (and also things called procedures, which are just another kind of function really), but you may not have used them much.

Functions are a very important way to organise a program; if possible, you should usually split up what your program does into sensible and meaningful chunks, and put those into functions. This is good for two reasons:

  • It makes the program easier to understand, because it gives some indication of what each portion of it is for.
  • You will often find that one function can be used in several places; this saves you having to write out whatever it does several times.

Here's a rather pointless function.

        >>> def print_underlined(text):
        ...   length = len(text)
        ...   print text
        ...   print '-' * length
        ... 
        >>> print_underlined('Ouch!!')
        Ouch!!
        ------
      

The variable text exists only while the function is in operation; if there was another variable of that name before it's temporarily forgotten about. The variable length also exists only while the function is in operation. These variables are called local variables. Which brings me to another advantage of using functions:

  • Most of your variables can be local.
It may not be obvious that this is an advantage, but it really is: it means that most of the time, when you see a variable, the place where it's defined is nearby. So you can understand each bit of the program without having to keep the details of the whole program in mind.

Returning a value

Unlike the function print_underlined above, a lot of functions return a value. What that means is ... well, the easiest thing is to give an example.

        >>> def thrice(x):
        ...   return x*3
        ... 
        >>> thrice(100)
        300
        >>> thrice(100)+5
        305
      
In this example, the function thrice eats up a number (actually, it needn't be a number. Try asking for thrice('xyz')!) and returns thrice that number. The value of a function can be used anywhere where any other value can be used, as you can see in the last two lines of the example.

Function arguments

The two functions we've seen so far each take a single argument; that is, a single value inside their parentheses. In print_underlined, the argument was called text and was expected to be a string (incidentally, it might amuse you to consider what would happen if you said print_underlined([1,2,3])...); in thrice, the argument was called x and was expected to be a number.

You can write functions that take no arguments, or functions that take several. This is pretty easy:

        >>> def print_greeting():
        ...   print 'A big hello from Python!'
        ...   print '2+2 is', 2+2
        ...   print 'Are you impressed?'
        ... 
        >>> def sum_of_four(a,b,c,d):
        ...   return a+b+c+d
        ... 
      
You use these by doing, say, print_greeting() or print sum_of_four(100,-3,my_salary,10*100).

But there's more! Function arguments can have default values:

        >>> def f(x, y=7):
        ...   return x+y
        ... 
        >>> f(1,2)
        3
        >>> f(1)
        8
      

Even weirder, when you're using a function you can refer to its arguments by name to save yourself the trouble of remembering what order they come in:

        >>> def silly(a, b, c, d=6):
        ...   print 'a =',a, 'b =',b,'c =',c,'d =',d
        ... 
        >>> silly(1,2,3,4)
        a = 1 b = 2 c = 3 d = 4
        >>> silly(1,2,3)
        a = 1 b = 2 c = 3 d = 6
        >>> silly(c=9,b=4,d=8,a=2)
        a = 2 b = 4 c = 9 d = 8
      

Odds and ends

You now know plenty enough to get started writing Python programs, but there's plenty more to learn if you want to. This section is just a collection of excessively brief mentions of interesting things about Python. You can ignore it if you like.

  • Comments are just as easy in Python as in BASIC. The character # (unless it's in a string) begins a comment, which extends to the end of the line.
    
                for i in 2,3,5,7,9:
                  # This line is a comment and has no effect on anything.
                  print i*i
              
  • Exceptions are Python's way of handling errors. In BASIC, if something goes wrong then the program ends. Some varieties of BASIC have (rather nasty) ways of arranging for something more constructive to happen. Python does it much more elegantly. Here's a little example.
    
                try:
                  z = x/y
                except ZeroDivisionError:
                  z = 100000000
              
  • Classes are a way of defining new kinds of objects. If you use classes then you get to say that your programs are object-oriented, and everyone will be very impressed. I won't give an example of how you use classes, because it would be a little too long.

An example program

Finally, here is a complete short program written in Python, illustrating most of the things I described above and more. It plays a game a little like Twenty Questions, in which you think of something and the computer tries to work out what it is with yes/no questions. When it fails (as it usually will) you give it a question that distinguishes between the best guess it had and the thing you were actually thinking of. For reasons of tradition, this program actually assumes it's always animals you're thinking of.

A sample run

Here's a sample run of the program, to give you a feeling for what it's like.

        >>> play_animals('lion')

        Think of an animal...

        Is it a lion? no
        Rats. What was your animal? a mouse
        Tell me a question that will distinguish a lion from a mouse. 
        --> is it a carnivore
        What's the answer for a mouse? no

        So far I've played 1 games and won 0.
        Would you like another game? yes

        Think of an animal...

        Is it a carnivore? yes
        Is it a lion? no
        Rats. What was your animal? rat
        Tell me a question that will distinguish a lion from a rat. 
        --> Is it a rodent?
        What's the answer for a rat? y

        So far I've played 2 games and won 0.
        Would you like another game? yes

        Think of an animal...

        Is it a carnivore? yes
        Is it a rodent? yes
        Is it a rat? yes
        I win!

        So far I've played 3 games and won 1.
        Would you like another game? no

        Thank you for playing.

        >>>
      

The whole program

Here is the whole program, interspersed with what I hope are helpful words of explanation. Don't worry if a lot of it doesn't make sense; the idea is just to give you an idea of what a real Python program looks like. (For this reason, I haven't been too careful to define every word I use, and I've skirted over many details.)


        import string

This means: The program might want to do some interesting things with strings, so load in the module that contains some string operations. You'll recognise those in what follows because they have names like string.lower() beginning with string. .


        class Animal_BadSplit(Exception): pass
        class Animal_BadBoolean(Exception): pass

These lines define new kinds of exception, which we use when something bad happens that we might want the program to be able to cope with. Ignore them for the moment.


        def prompting_input(str):
          if str[-1:] != ' ': str=str+' '
          if len(str) > 40:
            print str
            return raw_input('--> ')
          else:
            return raw_input(str)

This function is used to get input from the user. Its argument str is the prompt to use. The function adds a space onto the end if there isn't one there already. If the prompt is too long, the function prints it on a line by itself and then prompts with --> so that there's enough room on the line for the user to type something longish.

The raw_input function it uses is provided by Python itself.


        def is_yes(x):
          xl = string.lower(x)
          if xl in ('y','yes','true'):
            return 1
          if xl in ('n','no','false'):
            return 0
          raise Animal_BadBoolean

This looks at a string (which will of course come from the user) and tries to work out whether it means yes or no. It returns either 1 or 0 (these values are conventionally used by Python to mean true and false).

If the string doesn't seem to say yes or no, is_yes doesn't return a value at all. Instead, it raises an exception (of a type we defined earlier). You'll see what gets done with this in just a moment.


        def get_yesno(question):
          prompted_again=0
          while 1:
            answer = prompting_input(question)
            try:
              return is_yes(answer)
            except Animal_BadBoolean:
              if not prompted_again:
                question = "Please answer yes or no. "+question
                prompted_again=1

This is basically just a combination of the last two functions, except that it has to deal with the possibility that is_yes raised an exception. That's what the try...except is for. If is_yes complains, we modify the question to start with Please answer yes or no. , unless we've already done that, and then we try again.


        def articled(str):
          if    str[0:2]=='a '   \
             or str[0:3]=='an '  \
             or str[0:4]=='the ' \
             or str[0] in string.uppercase:
            return str
          if str[0] in 'aeiou': return 'an '+str
          else: return 'a '+str

This turns yeti into a yeti, aardvark into an aardvark, and leaves John Prescott and a lion alone.


        class Node:

Almost all of what follows defines a new class called Node. The idea is that a Node describes a possible state of the program's knowledge about the animal you're thinking of. There are two kinds of node: animal nodes (meaning that there is only one animal the program knows about that's consistent with the answers you've given, so it's about to ask you whether that's the animal you're thinking of), and question nodes (meaning that there's more than one possibility, and indicating the question the program needs to ask next).


          def make_animal(self, name):
            self.animal = name
            self.question = None
            self.yes      = None
            self.no       = None
            return self

          def make_question(self, q, yes, no):
            self.animal   = None
            self.question = q
            self.yes      = yes
            self.no       = no
            return self

It may not be obvious, but these definitions are indented further than the line that says class Node:. That means that these are part of the class definition. Functions defined inside a class are called methods. The idea is that a method defined in the Node class describes something you can do to a Node. To apply make_animal to a node x, you write something like x.make_animal('tiger'); this will do the above stuff with self=x and name='tiger'.

Anyway, these two functions are for making a Node into either an animal node or a question node. An animal node has an animal name for its animal attribute and the special value None (defined by Python itself) for its others. A question node is more interesting. Its question attribute is the question itself; the yes and no attributes are other nodes. If you answer the question with yes, the next node the program looks at will be the one stored in the question node's yes attribute.

Thus, each time you play the game the program moves through its question nodes, going from each to either its yes child or its no child. When it reaches an animal node, it makes its guess and (one way or another) the game is over.


          def get_question(self):
            if self.question:
              q = self.question
              if q[-1:] != '?':
                q = q+'?'
            else:
              q = 'Is it '+articled(self.animal)+'?'
            return q

For every node (both animal nodes and question nodes), there is a question to be asked. The get_question method, when applied to a node, returns the question needed. If the node is a question node (the program checks this by seeing whether its question attribute is set) then that attribute itself will always contain the question; if not, we need to manufacture a question out of the animal name.


          def split(self, question, new_is_yes, new_name):
            if self.animal is None:
              raise Animal_BadSplit(self)
            child1 = Node()
            child2 = Node()
            child1.make_animal(new_name)
            child2.make_animal(self.animal)
            if new_is_yes:
              self.make_question(question, child1, child2)
            else:
              self.make_question(question, child2, child1)

This method is the heart of the program. When the program has asked you Is it an aardvark? and you have answered no, the animal node representing aardvarks gets replaced by a question node whose two children are an animal node for aardvarks and an animal node for whatever sort of animal you were really thinking of. So, when the program would have asked Is it an aardvark?, it will now ask a question that distinguishes between aardvarks and (say) goldfish.

So, what we do is to make two new nodes (here called child1 and child2, which we make into animal nodes using the make_animal method; and to modify the existing node using the make_question method. The new_is_yes argument to split is supposed to be true if the new animal being added is to be the result of answering yes to the new question, and false if not.


          def child(self, bool):
            if bool: return self.yes
            else:    return self.no

          def choose_child(self):
            question = self.get_question()
            bool = get_yesno(question)
            return self.child(bool)

The child method is straightforward enough; it selects one or other child of a node depending on whether you pass it a true or a false value.

The choose_child method is a little more involved. It decides what question to ask by applying the get_question method to the node it's being applied to; it asks the question using the get_yesno function; and it selects the appropriate next node using the child method.


          def check_terminal(self):
            solved = get_yesno(self.get_question())
            if solved:
              print "I win!"
              return 1
            else:
              new_name = prompting_input("Rats. What was your animal? ")
              question = prompting_input("Tell me a question that will distinguish "
                                         +articled(self.animal)+" from "
                                         +articled(new_name)+". ")
              question = string.upper(question[0]) + question[1:]
              new_is_yes = get_yesno("What's the answer for "+articled(new_name)+"?")
              self.split(question, new_is_yes, new_name)
              return 0

When we reach an animal node, we stop applying choose_child and apply check_terminal instead. This asks the Is it ...? question; if the answer is yes then it prints I win! and returns something true (namely, 1); if not, then it asks the user for the information needed to apply split does that, and returns something false (namely, 0).


          def play_game(self):
            print "\nThink of an animal...\n"
            while self.question:
              self = self.choose_child()
            return self.check_terminal()

If you've followed everything so far (in which case, I congratulate you) you'll see that playing a game is now very easy. We just apply choose_child until we're no longer at a question node, and then apply check_terminal. We return whatever that returned; remember that this indicates whether the program won or lost.


          def play_series(self):
            played=0
            won=0
            while 1:
              played = played+1
              won    = won+self.play_game()
              print "\nSo far I've played %d games and won %d." % (played,won)
              if not get_yesno("Would you like another game? "):
                break
            print "\nThank you for playing.\n"

Playing a single game is very boring. The play_series method keeps playing until you've had enough. It should be pretty self-explanatory by now, except for the funny business in that first print statement, which I shan't explain.


        def play_animals(name):
          initial_node = Node()
          initial_node.make_animal(name)
          initial_node.play_series()

And, finally, the function (not a method: we're out of the class definition now, as you can tell from the indentation if you look carefully) that we saw at the very start of the sample run. It makes a new animal node, and applies play_series to it.

Page python/inexperienced.txt · Last modified: 2007/12/07 21:10 by mark · Built with dokuwiki ·