/* jquery */ /* jquery accordion style*/ /* jquery init */

28 April 2013

Learn Python - GUI File Search App

Now we've seen how a typical GUI program is structured, let's try a more advanced example.

It will be based on the File Walk App we created earlier, which searched the file system, using the os.walk function to obtain a list of files and sub-directories.

Open another new file in Geany, save it as 'tk-search.py' and type in the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# A GUI search program using tkinter
# Created by David Briddock

from tkinter import *
import os

# initialise main window
def init(win):
  win.title("File Search")

  labelPath.grid(row=0, column=0, sticky="W")
  entryPath.grid(row=1, column=0)
  labelEnding.grid(row=2, column=0, sticky="W")
  entryEnding.grid(row=3, column=0)
  btnSearch.grid(row=4, column=0)
  fileList.grid(row=0, column=1, rowspan=5)
  yscroll.grid(row=0, column=2, rowspan=5, sticky="NS")

  fileList.configure(yscrollcommand = yscroll.set)
  yscroll.configure(command = fileList.yview)
  entryPath.insert(INSERT, "/home")
  entryEnding.insert(INSERT, ".py")

# find button callback
def search():
  # get start directory and file ending
  startDir = entryPath.get()
  fileEnding = entryEnding.get()

  # clear the listbox
  fileList.delete(0, END)

  # find matching file and fill listbox
  for path, dirs, files in os.walk(startDir):
    for fileName in files:
      if (fileName.endswith(fileEnding)):
        fileList.insert(END, path+"/"+fileName)

# create top-level window object
win = Tk()

# create widgets
labelPath = Label(win, text="Starting Path")
entryPath = Entry(win, width=12)
labelEnding = Label(win, text="File Ending")
entryEnding = Entry(win, width=12)
fileList = Listbox(win, width=80)
yscroll = Scrollbar(win, orient=VERTICAL)
btnSearch = Button(win, text="Search", width=8, command=search)

# initialise and run main loop
init(win)
mainloop()

While there are quite a few lines of code here, I hope you can pick out the function definitions and typical GUI app structure.

We've still have our tkinter module import on line 4, while line 5 imports the os module. You'll also notice the init function and another event callback function, this time called search. More on these later.

More Widgets

On line 40 we create the top-level window object. This time we need quite a few widgets. These are created on lines 42 to 49.

The labels and entry boxes will provide our user input interface. The label text is set using the text configuration parameter. The two entry fields will hold the starting directory and file ending strings, and have a display width assignment of twelve characters.

On line 47 a listbox widget is created. This will hold a list of matched files. Specifying a width of 80 characters will cater for any long path names. A search might find many files. So, we need a vertically oriented scrollbar. We'll 'attach' this scrollbar to the listbox later.

And finally, on line 49, we create a button widget to kick off the search operation. The three parameters specify the button label text, the callback function name, and a width of eight characters.

Lines 52 and 53 call the init function and start the main window loop, just like we saw in the Basic GUI App post.

Using Grid Layout

Now back to the init function. With more widgets it's quite a bit longer than before, and there's also something new to learn. Our widgets need to be positioned in particular locations. Luckily, the Tkinter module has a built-in grid layout feature.

You can think of a grid layout as a collection of empty boxes or cells, organised into rows and columns - very like the cells in a spreadsheet. The cells are numbered from the top left corner starting from zero. A widget is placed in a particular grid cell with the widget's grid function.

We start on line 11 with the cell at column zero row zero, which will contain the starting directory label widget. On line 12 we populate the cell in column zero row one with the starting directory entry widget. Lines 13 and 14 repeat this process for the file ending's label and entry widgets for rows three and four. On line 15 we add the search button to row five in column zero.

By now I'm sure you noticed the sticky configuration parameter on the labels. The 'W' setting means 'West' and ensures the label text will line up on the left hand side of the column.

The second column, column one, only contains the listbox widget. However, the rowspan configuration parameter will stretch it to fill five rows - matching the number or rows we assigned in column zero.

The final column has the scrollbar. This is also stretched over five rows and has a 'NorthSouth' stickiness to ensure it fills the full column space. We 'attach' the scrollbar to the listbox using the statements on lines 19 and 20. This will ensure the listbox contents scroll when the scrollbar is moved.

The last two lines of the function, 21 and 22, set default text string values for the entry widgets.

The Search Callback

Now for the search function. Remember this is called when the search button is clicked, as per the callback setting on line 49. The first two lines, 27 and 28, extract the contents of the entry widgets and store them in two string variables, startDir and fileEnding.

Line 31 deletes all the items in the listbox, to remove any files from a previous search.

Our search is done in lines 34 to 37. Line 34 starts a loop and calls the os.walk function with our startDir string. This function returns a list of paths, files and sub-directories. Line 35 is another loop which extracts each file in the file list, and stores it in the fileName variable.

The conditional if statement on line 36 compares the end of the fileName string with our entered fileEnding. If the test is True then it adds a new string to the listbox, using the path and file name.

And that's it. Run the program using Geany's Build->Execute menu option, or F5 key.

Experiment by trying different file endings and starting directories.

Make It Your Own

As we've seen a GUI program requires quite a bit more code than a simple terminal-based one. However, the flexibility offered by a widget-based user interface is certainly worth the effort.

GUI programming is a big subject. In this short article we've barely scratched the surface. The possibilities for refinement are almost endless. For example, you could change a widget's size or colour, add new widgets, or create a completely different layout.

Python 2.7

Remember, for Python 2.7 you'll need to install Tkinter. If you see a message that says 'No module named Tkinter' then take a look at my previous Installing Tkinter post.

A post from my Learn Python on the Raspberry Pi tutorial.

25 April 2013

Hack Minecraft with Python on the Raspberry Pi

Mojang recently released their free Minecraft: Pi edition - complete with hackable Python API.

Would you like to learn how to hack Minecraft with Python on your Raspberry Pi?

This week's Micro Mart magazine (issue 1257) contains the first of my two part mini-series on Pi Minecraft hacking.

Part one guides you through Minecraft installation before demonstrating how to interact with a live running game with Python's interactive mode and simple statements.

Part two dives further into the API with a step-by-step tutorial on creating a Minecraft hack module.

Here are a few extracts from part one:

There are many reasons to try Minecraft hacking. It's a visually interactive way to experiment with the Python language and so an ideal coding project for the novice Python coder.

Mojang's supplied Python application programming interface (API) ensures you're able to make dramatic physical changes to the Minecraft world with through code-driven crafting. With this API even a small program can offer a surprising amount of game functionality.

And, of course, it's great fun.

The Python modules that implement this package consist of the main minecraft module (minecraft.py), plus the block management (block.py), event handling (event.py), utility (util.py), coordinate conversion (vec3.py) and client-server communication (connection.py).

Are you starting to see the potential of Mojang's Python API? Using these API function calls you can dramatically change your world.

So, let your imagination run free. Python code can rapidly generate new landscapes, construct homes, build defences, plant crops, and so much more.

Also see my Learn Python on the Raspberry Pi tutorial.

23 April 2013

Learn Python - Basic GUI App

Now it's time to write a GUI app.

Boot up your Raspberry Pi and open your Python editor. Next open a new file and save it as tk-basic.py in the Desktop's Python folder.

Now type in the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# A basic GUI program using tkinter
# Created by David Briddock

from tkinter import *
from tkinter import messagebox

# initialise main window
def init(win):
  win.title("My GUI")
  win.minsize(200, 50)
  btn.pack()

# find button callback
def hello():
  messagebox.showinfo("Hello", "Callback worked!")

# create top-level window object
win = Tk()

# create a widget
btn = Button(win, text="Hello", command=hello)

# initialise and start main loop
init(win)
mainloop()

Before we run this app let's examine the code in detail.

Basic Flow

After the program-level comments there's a tkinter module import statement on line 4. However, you'll notice it's a little different to the ones we've used before.

What this style of import does is alleviate the need to prefix all the tkinter modules constants and functions. We'll need quite a few tkinter constants and functions for any reasonably sized GUI program, so this import option will help de-clutter the code - and save quite a bit of repetitive typing.

On line 5 there's a more specific import statement for the tkMessageBox module.

In order follow the program execution flow we need to skip past the function definitions and look further down the listing.

Window And Widget Creation

At line 18 we create a top-level window object and assign it to the variable win.

On line 21 we have the one and only widget, a button. When we create a widget we need to say where it fits in the window hierarchy. This is done by specifying the parent window as the first parameter. Widget characteristics are set by defining one or more optional parameters. Here we have specified two.

The text parameter will set the button's text label. The command parameter defines the callback function name. When a mouse click event occurs for this button, the named function is called, in this case hello.

Initialise And Loop

It's lines 24 and 25 that hold the key to the program's operation. On line 24 we call the init function to perform any initialisation operations. We'll look at this in detail shortly.

On line 25 there's the main GUI loop. It's an endless loop which only terminates when the window is closed. Entering this loop will cause the main window to be displayed, along with any widgets we've defined. Once running it will capture and process all keyboard and mouse events. If these events are associated with any widgets, such as our button, the appropriate callback function will be called.

Initialisation Function

As we saw earlier, line 24 calls the init function. In this basic program init contains just three lines.

On line 9 we set the top-level window title, which will appear in the titlebar. On the next line we specify the minimum size for our window in pixels. In this case it's 200 pixels wide and 100 pixels high.

The final function statement, on line 11, calls the Tkinter pack function on behalf of our button. This adds the button to its parent window, namely the top-level window win.

The Callback Function

The callback function, hello, is defined on line 14. Remember, callback functions never have any parameters.

Once again this is a small function with just a single line of code, which calls the tkMessageBox module function showinfo. This function creates a new popup-style window, and you'll notice it has two parameters. The first parameter will define the string in the window's titlebar. While the second parameter is the message that will appear inside the popup window.

Run The App

Now we can execute the app, using the Geany Build->Execute menu option or the F5 key. After the window appears click on the button to see the message window popup.

Because the callback is only associated with the button, if you click somewhere else inside the top-level window nothing happens.

Python 2.7 code

Here's the Python 2.7 version of the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# A basic GUI program using Tkinter
# Created by David Briddock

from Tkinter import *
import tkMessageBox

# initialise main window
def init(win):
  win.title("My GUI")
  win.minsize(200, 50)
  btn.pack()

# find button callback
def hello():
  tkMessageBox.showinfo("Hello", "Callback worked!")

# create top-level window object
win = Tk()

# create a widget
btn = Button(win, text="Hello", command=hello)

# initialise and start main loop
init(win)
mainloop()

A post from my Learn Python on the Raspberry Pi tutorial.

22 April 2013

Learn Python - Installing Tkinter

Python 3.x

If you're using a recent version of Python 3, say version 3.5 or 3.6, then the tkinter module is preloaded. So you can move on to the next tutorial.

Python 2.7

However, if you're using Python 2.7 then you might need to install the Tkinter module.

To check if it's already installed open a new Python interactive session, then enter this statement (making sure there's an uppercase T in Tkinter):

>>> import Tkinter

Did you see an    ImportError: No module named Tkinter    error message?

If the answer is yes then follow the installation steps below (which are applicable to the Raspbian Jessie distro or the older Raspbian Wheezy image).

Ensure your Raspberry Pi is connected to the Internet, open an LXTerminal window and enter this command:

sudo apt-get install python-tk

If prompted enter the your login password, and reply y to any prompts.

Now we're ready to create GUI apps.

A post from my Learn Python on the Raspberry Pi tutorial.

20 April 2013

Learn Python - GUI Event Handling

Event handling is a critical aspect of GUI app development. Events can be generated in various ways, keyboard and mouse interaction being two obvious examples.

A GUI program must be able to determine which key was pressed. Not just the alphanumeric keys, but also shift keys, control keys, alt keys, function keys, cursor keys, the escape key and special keys like the Windows key.

As for the mouse, a program needs to determine the current coordinates of the mouse pointer, whether a mouse button has been clicked and if the scroll wheel has moved.

How do we do this? In a GUI program it's done with something called 'callbacks'. A callback is registered against a particular widget, and associated with a specific function. When an event occurs in the widget's window area, the function is called. This function can then analyse the event type and respond appropriately.

Once again all this functionality is contained within the tkinter module, so creating a GUI callback is a straightforward operation.

A post from my Learn Python on the Raspberry Pi tutorial.

18 April 2013

Learn Python - GUI Code Structure

GUI programs tend to have more code than simple terminal-based ones. This extra code might look a little daunting to the novice programmer. However, it's not as confusing as it might at first seem.

Every GUI application has a similar structure. Understand this structure and you'll be able to create any number of GUI apps, from the simple to the highly complex.

A typical GUI program has four main parts:

window and widget definition
 top-level window initialisation
 the main window loop
 event handlers

The first two parts define the look and feel of the GUI app. As the number of widgets grows and the design becomes more complex we'll have to increase the quantity of code in these parts.

The next two parts control the runtime operation of the app. After the loop renders the various windows and widgets onto the display it continually checks for new mouse and keyboard events. These events are subsequently processed by the previously defined event handlers.

To demonstrate each of these sections we'll create a simple tkinter app. But first, let's talk a little more about GUI events.

A post from my Learn Python on the Raspberry Pi tutorial.

16 April 2013

Learn Python - GUI Windows

From a user's perspective GUI applications tend to look very different from one another. For example, on the Raspberry Pi's desktop the Geany application doesn't seem to have much in common with the File Manager utility. However, this isn't the case.

GUI apps are assembled from a collection of windows. All these windows are arranged in a hierarchy. Most of us recognise the typical application window frame, with its bar containing the app name and an array of window management buttons to iconise, maximise and close the window.

Inside this main frame there's a top-level window containing an assortment of GUI elements, generally referred to as widgets. Buttons, labels, text boxes, images, scrollbars, selection boxes and sliders are all types of widget. However, did you realise that all these widgets are themselves little windows. In fact, each widget may itself contain other widgets.

Every widget has its own specific list of properties, such as location, size and colour. Very importantly, a widget is aware of certain kinds of events within its window area, such as a key press or a mouse click. I'll talk more about GUI events in a future post.

If all this sounds a little complex, don't worry, there's good news in the form of a Python 3 module called tkinter, (or Tkinter for Python 2.7). This module has a collection of GUI-specific functions to simplify GUI coding. So let's get started.

A post from my Learn Python on the Raspberry Pi tutorial.

14 April 2013

Portable Raspberry Pi

Are you looking to make your Raspberry Pi more portable? Or maybe you're working on a project (such as a weather station) which dictates the Pi will be located some distance from a convenient power source?

Luckily the Pi can run from a small power source, such as a battery pack. Battery life will depend on three factors. Firstly, whether you own a Model A or Model B, the Model A should last over twice as long. Secondly, the number of other devices you have attached. And thirdly, the processing requirements of your apps.

Adafruit has a professional looking solution. The kit includes a rechargeable battery and simply plugs into one of the USB ports.

For more of a DIY solution which uses standard AA batteries visit this raspberrypi-spy web page.

Of course, you could go even further and construct a solar powered solution, as described on this CNET web page.

Visit my Raspberry Pi page for news, reviews, advice and tutorials.

12 April 2013

Learn Python - Guessing Game

Let's take the programming knowledge we've gained and create a simple guessing game, where we have to guess a mystery number. Following our structured programming theme most of the code will be contained in a two functions.

Create a new file with Geany and save it as 'guess.py' in the Desktop's Python folder. Now type in the source code, as below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# A number guessing game
# Created by David Briddock

import random

# generate a random number
def generateNumber(player):
  print "\n" + player + " guess a number between 1 and 20"
  return random.randint(1, 20)

# try to guess the number
def guessNumber(number):
  guessCount = 0 # start at zero

  # allow up to five attempts
  while guessCount < 5:

    guessCount += 1 # add one
    guess = int(raw_input('Your guess? '))

    if guess == number:
      print "Success in {0} guesses!" . format(guessCount)
      return
    elif guess < number:
      print "Too low - try again..."
    elif guess > number:
      print "Too high - try again..."

  print "Sorry, the number was " + format(number)
  return

# discover who is playing
player = raw_input("Who is playing today? ")

# main guessing game loop
while True:
  number = generateNumber(player)
  guessNumber(number)

As always we start with our program-level comments. On line 4, we have an import statement to load the 'random' module. As you might expect from the name, this module can generate random numbers.

Our function definitions come next. It's good practice to put all the functions definitions towards the top of the code. However, this means the main program execution flow continues further down, So, we'll follow the flow and look at the body of these functions shortly.

The execution will continue on line 33, where we ask the user for the player's name using the 'raw_input' function. The value is stored in the 'player' variable. Now for the game loop.

The Game Loop

Line 36 starts an endless loop with a 'while True:' statement. This means we can play the game again and again without having to continually rerun the program (the Ctrl-C key sequence will exit the game).

Thanks to our functions there are just two indented lines in our game loop, and so is easy to read and understand.

On line 37 we call the 'generateNumber' function passing in the 'player' variable and store the return in 'number'. And finally, we call the 'guessNumber' function and pass in 'number' on line 38.

Random Number Generation

Now it's time to look at the first function we defined, 'generateNumber', defined on line 7.

Line 8 uses the passed 'player' parameter to print out a message asking the player to make a guess.

While line 9 calls the random module's function 'randint' with two parameters representing the lower and upper values of a range, namely 1 and 20. This generated number is returned to the function call statement.

The Guessing Loop

Time to look at our second function definition 'guessNumber'. This contains most of the program's logic. As you can see it has a single parameter, called 'number'.

After the function definition statement on line 12, we initialise a 'guessCount' variable to zero on line 13.

Line 16 starts another 'while' loop. We are going to give the player up to five guesses. So each time the loop repeats we test the guess count to see if it's less than five.

The first indented line in our loop, line 18, increments the value of the guess count by one.

Next we ask the player for a guess. This is done with the 'raw_input' function again, but this time it's wrapped inside another function called 'int'. Note the brackets around the whole 'raw_input' function call, where one fuction is nested inside another. The 'int' function ensures we'll have an integer stored in the 'guess' variable.

All we need to do now is test the player's guess against the 'number' parameter. Starting on line 21 we use the 'if' keyword for this. In fact, we'll need three of them. One to test if the guess is correct, and two more to test if the number is higher or lower. The last two tests will enable us to print a helpful message for the player.

You'll notice the last two tests actually use the 'elif' keyword. In Python this is shorthand for 'else if'. What's the advantage of using 'elif' instead of 'if'? Well, if the previous 'if' or 'elif' test is 'True', any remaining 'elif' statements are skipped during execution. This makes our program more efficient, and therefore a little faster to execute - something that can be very important when writing certain types of programs, such as a fast-action game.

Making Changes

That's it, our guessing game is finished. I hope you can see how breaking your program up into well-defined, re-usable functions improves its overall readability and make it easier to understand, debug and maintain.

For example, if you'd like to alter the range of random numbers generated, say from 1 to 30, it's the 'generateNumber' function that needs to be modified. However, if you wish to decrease the number of allowed guesses from five to four, it's the 'guessNumber' function that will have to be changed.

During debugging each function can be called and tested one at a time, simply by commenting out the other function calls. In this way the full app is run only after we are sure each function behaves as intended.

A post from my Learn Python on the Raspberry Pi tutorial.

10 April 2013

Learn Python - Creating Functions

Now we understand the benefits it's now time to create a function. We'll start with a simple one that calculates the area of a circle.

Open the Geany editor using the Desktop menu option 'Programming->Geany' and create a new file using the 'File->New' menu option. Now save it as 'func.py' in the 'Python' folder we created on the Desktop in a previous post.

Type in the source code below. Take care to correctly enter those quotes, colons and line indentations. And save your typing frequently.

1
2
3
4
5
6
7
8
9
10
11
12
# A simple function definition and call example
# Created by David Briddock

import math

# find the area of a circle for a specified radius
def circleArea(radius):
  return math.pi * (radius*radius)

radius = input("Circle radius? ")
area = circleArea(radius)
print ("Area is ") + format(area)

After the program-level comments and the 'math' module import statement we reach the function definition at line 6. Notice the comments. Comments are even more important for functions and should clearly describe the function's behaviour.

Now let's consider the code in lines 7 and 8.

Line 7 starts with the 'def' keyword. This tells Python we are defining a function. Next is the function name, which must be unique to our program. When reading the code we want to be able to determine what the function from its name, so make sure the you choose is appropriate and meaningful one. Here I've used the so-called camel case naming standard to to help with readability.

All functions will have a pair of brackets, or parenthesis, after the name. Optionally there may be one or more parameters declared inside these brackets. Here there is just one called 'radius', which will contain a numeric radius value. Finally, there's a colon ':' at the end of the definition. A colon signifies that all the indented code below will belong to this function, and will be executed when it is called.

In this case our function only has a single line of code. Line 8 calculates the area of a circle, using the 'math' module's constant 'math.pi'. Once calculated this value is then returned back to the statement that called the function.

Now for the main code. On line 10 the user is asked to input a 'radius' value.

Line 11 calls the 'circleArea' function with the user-supplied 'radius' value as the parameter. The returned value is assigned to a variable called 'area'.

And finally line 12 prints out a message and the value of 'area'.

Creating your own functions is a major step in becoming a more accomplished programmer. Study any well written program and you'll see functions everywhere.

A post from my Learn Python on the Raspberry Pi tutorial.

7 April 2013

Learn Python - Using Functions

As an analogy think of a Lego set. You have a wide selection of bricks in all kinds of sizes, shapes and colours. These bricks enable you to build models quite quickly, just by combining the right type of bricks in the right sequence. If you change you mind, or have a new idea, the type of bricks used or their assembly sequence can be quickly changed.

In Python, as with most languages, the developer can define a set of functions. Each function has a well defined purpose and role within the overall program. In effect a function acts as a code brick. Once defined and tested a program can be assembled by calling these functions in a particular sequence.

A function can be called many times within the same program. Reusing code in this way reduces the overall number of code lines in a program, which aids code readability and debugging. In addition, related functions can be collated and stored in a library module. This module can be imported in any number of different programs.

A good place to witness function reusability is in games. At face value every game may look very different. However, many of the tasks required are very similar. Loading an image, moving an image around the screen, playing a sound, testing for key or mouse button presses, and so on can all be done with generic functions.

The more programming experience you gain, the more you'll start to recognise the sections of your programs that could be converted into functions.

A post from my Learn Python on the Raspberry Pi tutorial.

Learn Python - Program Structure

So far all our programs have had a simple flow, from top to bottom. While this is fine for small examples, as soon as programs become longer and more complex, things tend to become more difficult.

One common problem is it becomes more difficult to recall what each section of code actually does. Even with plenty of comments you'll spend lots of time scrolling up and down the source to identify the pieces to change or extend. The end result is a long program listing that's difficult to read and prone to bugs.

Another issue is that you may see very similar pieces of code repeated. Obviously, this isn't an efficient way of programming. Even more importantly, the more code you write the more errors are likely to be introduced, and the more bugs you'll have to find and fix.

A far better approach is to break the solution down into a series of identifiable elements. Each element can be designed and coded in isolation.

A post from my Learn Python on the Raspberry Pi tutorial.

5 April 2013

Learn Python - File Walk App

In this program we'll use the powerful os module introduced in the first article. This time our focus will be on its walk function, which scans the file system then returns a list of files and their locations. We'll use this function to search for specific types of file based on their name.

Let's start by creating another new file with Geany and saving it into the Desktop's Python folder with the name 'walk.py'. Now enter the source code, saving frequently and taking care with quotes, colons and line indentations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# A file search program
# Created by David Briddock

import os

root = input("Start directory? ")
ending = input("File ending? ")

# starting from the specified root directory
# walk through all the files and sub-directories
for path, dirs, files in os.walk(root):

  # step through each file in the collection
  for fileName in files:

    # does the file name ending match?
    if fileName.endswith(ending):
      print(path + "/" + fileName)

Now, let's step through the code. The first two lines contain our program description comments. These are followed by the 'import os' statement on line 4.

Next we obtain some user supplied search data. On line 6 we use the input function to capture the starting directory for our search, and store it in root. Line 7 does a similar thing to capture a file ending string and store it in ending'.

The For Loop

Now we come to the meat of the program, contained in lines 11 to 18.

As you can see, we actually have two for loops, with the second one inside the first. With Python, as with most languages, we can have as many loops within loops as we like. Creating a hierarchy of loops is a frequently used programming technique.

Both for loops use the same format we saw earlier. However, the one on line 11 looks a little different as it has three variables before the in keyword. I'll not dwell on this for now, but just to note functions that return multiple variables is just one of Python's powerful features.

What does os.walk do? Well, as the comment suggests, it finds all the files and sub-directories in the supplied start directory. Then, for each subdirectory, it again finds all the files and sub-directories. This process is repeated until all the sub-directories have been searched.

Now for the three returned variables. The first, 'path', is just a simple string. However, the next two, 'dirs' and 'files', are list-type variables. A list-type variable holds a collection of items. We're only interested in 'files' which contains a list of file names.

As 'files' contains a list of files we can use the 'for' loop on line 14 to extract each file name from the list in turn, and assign it to a variable called 'fileName'.

Now we have a file name we can see if it ends with the string we entered earlier. This is done with the if statement on line 17 and a string method called endswith. (one of many Python string methods)

Let's imagine we entered '.py' as the file ending string. The test will see if 'fileName' ends with '.py'. If it does the test will be 'True', and the indented print statement on line 18 will be called. If no match is found, the test is 'False' and nothing is printed. So, only files which end in '.py' will be printed out.

Execute And Experiment

And that's the end of our 'walk' program. Use the Geany 'Build->Execute menu option, or press the F5 key, to run the program. Try entering '/home' as the starting directory and '.py' as the file ending. If you see an error message instead, go through the debugging process we described above until it runs successfully.

Feel free to experiment with different 'ending' strings. For example, using '.conf' should display some configuration files. And you can also try different start directories. A single period string '.' means the current directory. A value of '/etc' will find more Python files. While entering '/' will scan the complete file system - something that might take a little time to run, and could generate hundreds of file matches.

You can, of course, change the program too. One idea is to replace the 'endswith' function with 'startswith' to find all files starting with a specific string.

A post from my Learn Python on the Raspberry Pi tutorial.

3 April 2013

Learn Python - For Loops

Sometimes we need a loop that executes a fixed number times. It's something you'll find in many other programming languages. A Python 'for' loop is what we'll need. Let's look at a typical statement.

Suppose we wanted to print out each character of a string. The code would look like this:

message = "Hello"
for ch in message:
  print(ch)

First, we define a variable called message with a string value. Then we start the for loop. The in keyword instructs the loop to operate for a fixed number of times. In this case it's the number of characters in our message, namely five.

Each time the loop repeats it selects the next character from the string and assigns it to the variable ch. So, the first time char will be 'H', then next time it will be 'e', and so on.

Notice the colon : at the end of the line. Once again this marks the start of our indented loop code. There's only one line in this loop, a print statement. Run the code to see the loop print out all the characters in the message in sequence.

Now we've seen a simple for loop, let's create a guessing game app that uses one.

A post from my Learn Python on the Raspberry Pi tutorial.

2 April 2013

Learn Python - Running Timer

To run the program click on the Geany 'Build->Execute' menu option, or press the F5 key. Enter a value of say 10 seconds to start with. If you see an error message instead read it carefully, then check all your typing, especially any string quotes and brackets. Fix the typo and run again. Repeat this debugging process until it runs correctly.

Execute the program a few times with different numbers of seconds. If you enter a big number and get bored waiting you can always stop the program by selecting Geany's 'Build->Stop' menu option, pressing the F5 key again, or just closing the output window.

The Timer app can also be run from the command line in a terminal window. Open an new LXTerminal window and enter this command next to the '$' prompt:

$ python ~/Desktop/Python/timer.py

Time to have some fun and personalise your app. Try changing the character that appears when the loop in running. Or replace the final message.

A post from my Learn Python on the Raspberry Pi tutorial.

Learn Python - A Timer App

Now we know what a while loop is and how it works, let's create a useful little timer program.

A timer program can be used for all sorts of activities. Maybe you want to time the moves in a game of chess, or cook the perfect hard boiled egg at breakfast. Knowing how to create a timer is an important programming skill, especially in games where there are many time-sensitive aspects.

Let's get started. Open the Geany editor and creating a new file using Geany's File->New menu option.

Before starting to type save this file into the Python folder we created on the Desktop last time. Save it as timer.py.

Now we need to type in the code. Check your typing as you go, making sure you add the colon : character and indent the loop lines by the same number of spaces.

It's a good idea to save your typing frequently, say after every few lines, so you don't lose any changes. If you use the shortcut Ctrl-S (control key plus the s key) it only takes a second.

Here's the code listing (note the lines numbers are for reference only, and not part of the code):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# A timer countdown program
# Created by David Briddock - July 2012
# Updated for Python 3 September 2017

import time

# get the countdown time in seconds
seconds = int(input("Number of seconds: "))

count = 0

# loop that counts in seconds
while count > seconds:

  # show loop is running
  print(".")

  # wait for one second
  time.sleep(1)

  # increment the counter
  count = count + 1

print("Time is up!")

Now let's take a walk through each line of code.

The first few lines are comments which describe the program. Adding comments is an important part of programming. Programmers spend at least as much time reading code as writing it. Descriptive comments, clear layout and meaningful variable names all help to make the code more readable. Python comments start with a # character and are not executed as part of the program. Feel free to change the wording of any comment to suit yourself.

On line 5 we import a module called time.

On line 8 we use the seconds variable to capture a user-entered countdown time (note it's converted to an integer). You can choose a different value every time the program is run.

Next we setup a counter variable, on line 10, with an initial value of 0.

Now onto the loop code.

After a comment line we have a while statement on line 13, complete with conditional test and terminated by a colon : character. As the comment says, this will repeat the indented loop code as long as the count is less than the seconds value.

All we need now is some code inside the loop. The indented line 16 prints a character to the screen, so we have some visual indication that something is happening.

Python programs run extremely quickly. A loop like this will execute thousands of times a second. So line 16 would also run thousands of times a second. This isn't what we want to happen, so we add this sleep statement on line 19.

Now we just increment the counter by one on line 22.

And that's the end of our loop. The final print statement isn't indented, so it's only executed when the loop has finished.

Now we can run the timer app.

A post from my Learn Python on the Raspberry Pi tutorial.