Python Course
Session 1
Session 1 of the Python Course covers what's useful to know so you can quickly and easily set about writing Python programs. Detailed Python programming will be covered progressively in subsequent courses.
The course assumes a varied audience, from those that may have very little computing/programming experience, to those who have already been actively programming in Python. The aim is to get everyone up to the point where they feel confident in using Python and writing useful programs. But we can't cover everything in this short course: Python and all that has been written by skilled people the world over in support of it, is extensive.
Please feel free to seek assistance with understanding Python, particularly with the topics covered in the course sessions.
To start off, there is a quick introduction into the essence of computing/programming.
A digital computer consists of: memory, processor and i/o. The computer manipulates numbers, just numbers.
There are different kinds of memory accessible to the processor. A memory consists of an indexed set of locations. Each location holds numbers. E.g. location 9253 might contain numbers 43, 98 and 99.
The processor chip contains a mass of logic circuits for obeying instructions such as fetch from memory, add, multiply etc. The "engine" of the processor contains logic that repeatedly fetches a number from memory, interprets that number as an instruction, and executes that instruction.
The memory location index to fetch the instruction from is held in a special memory location called an Instruction Pointer (IP). The processor engine automatically increments IP after fetching the instruction. The engine operates repeatedly, so fetches and obeys instructions stored in sequential memory locations. The full set of stored instructions is called a program. The execution depends on the value of the instruction, e.g. 41 might mean store, 43 might cause addition, 55 might be "output". The memory may contain special locations, with particular hard-wired chip logic e.g. location 0 could hold the "instruction pointer" (with its hard-wired auto-increment after fetch), location 1 could be the "accumulator", where a value is operated on by the instructions.
Memory both holds the programs to run, and is used to store variable values used by the programs.
Consider the following program stored in memory locations 10 .. 13:
Location | Contents | Meaning |
0 | 10 | Instruction pointer |
1 | 0 | Accumulator |
... |
|
|
10 | (41, 1, 98) | Fetch contents of location 98 into location 1 |
11 | (43, 1, 99) | Add contents of location 99 to location 1 |
12 | (55, 1, 50) | Output contents of location 1 to output port 50 |
13 | (40, 0, 11) | Store 11 into location 0 |
... |
|
|
98 | 123 |
|
99 | 2 |
|
The processor runs the program:
The hard-wired “instruction fetch and execute” on location 0 uses the contents of that location as an index to fetch an instruction from (location 10); then it increments location 0, and executes the fetched instruction.
The processor repeats the instruction fetch and execute on location 0, this time fetching an instruction from location 11 – an addition.
So it fetches the contents of location 11, which is an addition. So after these two instruction fetch and executes, we now have:
Location | Contents | Meaning |
0 | 12 | Instruction pointer |
1 | 125 | Accumulator |
... |
|
|
10 | (41, 1, 98) | Fetch contents of location 98 into location 1 |
11 | (43, 1, 99) | Add contents of location 99 to location 1 |
12 | (55, 1, 50) | Output contents of location 1 to output port 50 |
13 | (40, 0, 11) | Store 11 into location 0 |
... |
|
|
98 | 123 |
|
99 | 2 |
|
The program continues. The instruction at location 13 resets the instruction pointer back to 11, causing the program to loop. So the program loops, outputting 123, 125, 127, ...
Larger programs would be incomprehensible with everything just numbers. Wouldn't it be so much easier if it could look like:
Location | Contents | Meaning |
IP | progstart | Instruction pointer |
ACC | 0 | Accumulator |
... |
|
|
progstart | (Fetch, ACC, startvalue) | Fetch contents of startvalue into accumulator |
loopstart | (Add, ACC, incrvalue) | Add contents of incrvalue to accumulator |
| (Output, ACC, 50) | Output contents of accumulator to output port 50 |
| (Jump, loopstart) | Store loopstart index into IP |
... |
|
|
startvalue | 123 |
|
incrvalue | 2 |
|
A programming language allows you to do that, and better. E.g. in Python:
# Print numbers starting at 123, incrementing by 2 each time.
startvalue = 123
incrvalue = 2
accumulator = startvalue
while True:
accumulator += incrvalue
print(accumulator)
# End of program
Or, sensibly limiting this loop to stop before 200, just:
for i in range(123, 200, 2): print(i)
The programming language interpreter (python) takes what you write, analyses it, and arranges that the processor performs the relevant low level instructions to obey the defined logic of your program.
Python was invented by Guido van Rossum, in the late eighties. The language is under continuous, controlled development with the aim of improving it whilst striving to maintain backwards compatibility. Latest versions as of 11 Jan 2016: Python 3.5.1 and Python 2.7.11.
Python is a programming language that provides useful features to enable us to efficiently write effective programs. For instance, allowing us to write basic mathematical expressions such as a
x = a + b / 43
Like most programming languages, programs are written in plain text.
A program, "python", is provided by the designers of the language to process the program file you have written in the Python language. The python program analyses your program on the basis of the Python language rules, reporting errors where you break those rules. As a language interpreter, it executes your program as it analyses.
It's difficult to write a program if you don't know where to start. So here's some useful information and guidance. Firstly, what issues do you face?
Choosing your language. There are many, many programming languages. Python is easy to use, modern, well supported and has a massive online presence. It is usable for many projects. It is of course well described in Wikipedia.
You can choose to use Python 3, or the older but still very much in favour Python 2. The RaspberryPi organisation prefers Python 3 (here, which is also a great mini-intro to Python), and that is what is assumed for this course. The differences are relatively small. See here for a well-considered discusssion on whether to us 2 or 3.
Learning the language. It's useful to look at short, well-written example programs and try and understand them. You have to write Python to learn it, so find some small manageable projects; or even just try modifying some of the examples.
Using the language. You need to know how to create Python program files and how to run them.
Debugging. Programs tend to have bugs. The Python interpreter will report basic syntax and execution errors, and hopefully the errors are clear enough to enable you to fix those problems. But if your program doessn't actually do what you want it to do, you'll need to debug it. How do you do that?
Documenting. If you don't document your program in some way then you're likely making a problem for the future, when it needs fixing or you'd like to extend it. Them maybe even you as the writer could be struggling to understand quite what it's doing from the code. Python has some built-in documentation aids.
Publishing. Hey, you've made it. You'd like to make public a program, or library module you've written. How?
Python has a massive online presence. Here's a set of useful links to carefully selected information sources.
PEP8 Style guide – A lot to take in but well worth skimming periodically as you learn and use Python. There's even an online code checker here.
docs.python.org – Official Python3 documentation. An invaluable learning and reference resource. It's a lot to take in!
news:comp.lang.python (Google groups) – Very active Python news group where you can discuss anything to do with Python.
Raspberry Pi learning tool – For beginners.
wiki.python.org – The Python Wiki. A broad range of Python resources.
The Python Standard Library (under doc.python.org).
PyPI - the Python Package Index. A large contributed-software repository.
Python3 Tutorial – Part of the official docn. Excellent.
TutorialsPoint (Python2) – A useful tutorial and information source despite just being for Python2. The Python Quick Guide is very good.
Non-Programmer's Tutorial for Python 3 (Wikibooks).
Python Programming (Wikibooks).
inventwithpython.com – Many good books on Python. A number are readable online and some are free to download.
Any text editor e.g. vi (but only use vi if you already know it!)
Any IDE – which also provides syntax highlighting.
There are numerous IDEs (Integrated Development Environments) that you can use to make it easier to write Python. They generally provide syntax highlighting and some degree of auto-completion and pop-up docn.
idle (/usr/bin/idle) – it's not liked by everyone but it's already installed, and generally ok.
idlex – an extension for idle.
Geany - (sudo apt-get -install geany) Geany is a general IDE for multiple languages. You'll need to add a Debug execute build command: python -m pdb "%f" so you can run with the debugger.
Pythonwin – For Windows, not Linux, unless you use the wine emulator.
Built into each IDE.
pdb – Ready-installed in raspbian, run: /usr/bin/pdb
Run your program under python with the -m trace option. i.e.:
python -m trace …
There are various options, e.g.: python -m trace --trace file.py > trace.out
Use the 2to3 program.
Reference: docs.python.org tutorial on modules.
A file containing Python code is called a module. The file name is the module name with the suffix .py appended. A module may be: a top-level program (one you invoke directly from the command line) (and that's called the main module); or a useful set of Python definitions to be imported into another module. Or both, i.e. a top-level program containing useful definitions that you may want to import into another program.
Python comes with a library of standard modules.
The built-in function dir() can be used to find out which names a module defines.
By convention, the top-level function of a program is called main:
def main ():
... # Elipses are allowed in python and they effectively do nothing here.
And you need to explicitly call main:
main ()
Standard code to call function main if you think you may ever import this module:
if __name__ == "__main__": main() # Only call main if module run from cmd line
Useful variables automatically defined for you in any module:
__name__ module name
List of command line arguments:
sys.argv
(Note that argv[0] is the script name or path.)
When you run a python script, python analyses and executes each statement as it is encountered Note that execution of a function definition merely causes python to remember that definition - the function isn't invoked at that time. (Note if the function definition includes default values for any parameters, those are evaluated and remembered at the point of execution of the function definition.)
The first string in a module, function, class or method is implicitly assigned to a local variable:
__doc__
Use help(module) to print the doc strings (or help(__name__) from within a module).
E.g.
import fibo # Makes all defns in module fib accessible as e.g fibo.fib1
More sophisticated versions of import:
from fibo import fib1, fib2 # Import just defns fib1 and fib2 from module fibo
from fibo import * # Import all defns from fibo (generally frowned upon)
Python checks if fibo is a built-in and uses that if it is; otherwise it checks the directory of the top level script (or current directory if no file was specified); else the directories listed in the shell PYTHONPATH environment variable.
The import statements are best placed first in a module. At least, the first Python statements.
Python first line, useful on linux:
#! /usr/bin/python
Allows you to run your program without doing python program (Check that /usr/bin/python is in fact a symbolic link to python3, using ls -ld /usr/bin/python)
Comments begin with # and need to be at the end of a line.
Indentation is required, and is by convention four spaces.
Boilerplate main module:
#! /usr/bin/python
"""<module doc string>
"""
import ...
global definitions
def main ()
...
if __name__ == "__main__": main()
Comments should supply useful information not immediately obvious from the code. Don't write comments like:
a = pi * r * r # Multiply pi by r squared and store in a.
(unless, you're writing an explanation to absolute beginners.)
But do write:
a = pi * r * r # Calc area.
But better of course would be to choose your variable names carefully:
area = pi * radius * radius
(which is best not commented)
But it's often a compromise. If you're writing lots of code manipulating area and radius then:
a = pi * r * r
without a comment is actually best.
It's good to provide a comment for each and every name you introduce. Go back over the code when it's nearing completion and do that, renaming if required to better reflect the true meaning. Often you unearth issues when you figure out accurate names.
Each module should have a header comment that ideally fully describes what the module is about.
Sometimes, you're not sure what you're going to write, where it's going. You just have an idea for a program and you're not sure where to start. So, what do you do? Sketch out what you are thinking about, write it down. Now, is there some part of what you want to do that you could make a start on? Throw some code together to implement some small part? Well, that's a start. Perhaps it's something that might have general usage, so you could write it as a separate module.
Say you want to write a chess program. It splits into different parts: the board (visual); the user interface; web features; moving the chess pieces; the core chess-playing algorithm; a database of standard chess moves (especially openings); move recording and replaying. These are in fact each pretty much independent and you could have a go at each one separately. Though, it would be nifty to get the visual board up and running first, and the chess pieces moving, so you can use that to see the results of your other efforts. And you may well want to research what other people have done in this area too. Much that you learn and achieve may be reuseable for other projects. Perhaps you write a general move (change) recorder and replayer that you can polish to be reusable across other games and similar.
Depends on the size of the program/module, intended audience, enthusiasm etc.
•If you're just quickly trying something out then style isn't overly important.
•If you're coding upwards of 50 lines then you're best laying it out nicely and using comments.
•If you're coding upwards of 500 lines then that's quite an investment of effort and it's best to get it nicely maintainable at least by you. If it's intended for a wider audience then put more effort into it. and if it's being published then get it reviewed.
There should be a similar approach to testing: from no testing to a full regression test suite.
And again, for documentation.
Publishing also requires ensuring you don't infringe on other people's rights.
For best understanding, bear in mind who else may be reading the code. Don't be too clever with complicated parts of the language and don't try and do too much in one statement. Lay the code out so it looks neat and tidy.
Structuring a large program well can be difficult: what to split into separate programs, separate modules, and separate functions/classes.
Often, you end up with a structure that doesn't feel like the best, and it would be a lot of effort to restructure. It's a common problem. Perhaps the only sure thing I can say is that if you've got a GUI aspect to your program then try and keep that separate: program the non-GUI part with functions/methods that can be called by the GUI part.
So, if we've got to this point in the course then there may just be time to have a look at some examples using the pygame library. On raspbian, you'll find them here:
/usr/lib/python3/dist-packages/pygame/examples
Note that the readme page states that the pygame examples programs are in the public domain, so it's ok to use them here.
A slightly modified version of moveit.py :-
#!/usr/bin/env python
"""
This is the full and final example from the Pygame Tutorial,
"How Do I Make It Move". It creates 10 objects and animates
them on the screen.
Note it's a bit scant on error checking, but it's easy to read. :]
Fortunately, this is python, and we needn't wrestle with a pile of
error codes.
Modified SDB Jan 2016 to move at a fixed rate.
"""
#import everything
import os, pygame
from pygame.locals import *
main_dir = os.path.split(os.path.abspath(__file__))[0]
#our game object class
class GameObject:
def __init__(self, image, height, speed):
self.speed = speed
self.image = image
self.pos = image.get_rect().move(0, height)
def move(self):
self.pos = self.pos.move(self.speed, 0)
if self.pos.right > 600:
self.pos.left = 0
#quick function to load an image
def load_image(name):
path = os.path.join(main_dir, 'data', name)
return pygame.image.load(path).convert()
#here's the full code
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
player = load_image('player1.gif')
background = load_image('liquid.bmp')
# scale the background image so that it fills the window and
# successfully overwrites the old sprite position.
background = pygame.transform.scale2x(background)
background = pygame.transform.scale2x(background)
screen.blit(background, (0, 0))
objects = []
for x in range(10):
o = GameObject(player, x*40, x)
objects.append(o)
clock = pygame.time.Clock()
while 1:
for event in pygame.event.get():
if event.type in (QUIT, KEYDOWN):
pygame.quit()
return
for o in objects:
screen.blit(background, o.pos, o.pos)
for o in objects:
o.move()
screen.blit(o.image, o.pos)
pygame.display.update()
clock.tick(40)
if __name__ == '__main__': main()