Conversing with the user

What will we cover?

So far our programs have only dealt with static data. Data that, if need be, we can examine before the program runs and thus write the program to suit. Most programs aren't like that. Most programs expect to be driven by a user, at least to the extent of being told what file to open, edit etc. Others prompt the user for data at critical points. This aspect of programming is what is referred to as the User Interface and in commercial programs designing and building the user interface is a job for specialists trained in human machine interaction and ergonomics. The average programmer does not have that luxury so must make do with some common sense, and careful thought about how users will use the program.

The most basic feature of a User Interface is displaying output and we have already covered the most primitive way of doing that via the Python print function (and JavaScript's write() function as well as the VBScript MsgBox dialog). The next step in User Interface design is to take input directly from the user. The simplest way to do that is for the program to ask for the input at run time, the next simplest way is for the user to pass the data in when he or she starts the program, finally we have graphical user interfaces (GUIs) with text entry boxes etc. In this topic we look mainly at the first two methods. We introduce GUI programming much later in the tutor because it is significantly more complex, however there is a module which allows us to do very basic GUI style dialog boxes for data entry in Python and we will briefly consider that.

Let's see how we can get data from a user in a normal Python interactive session running in IDLE or an OS terminal. Afterwords we'll try doing the same in a program.

Python user input

We can get input from a user in Python like this:

>>>> print( input("Type something: ") )

As you see input() simply displays the given prompt - "Type something" in this case - and captures whatever the user types in response. print() then displays that response. We could instead assign it to a variable:

>>> resp = input("What's your name? ")

And now we can print out whatever value was captured:

>>> print( "Hi " + resp + ", nice to meet you" )

Notice that this time I have chosen not to use the string formatting operator to display the value stored in the variable resp and have instead just inserted the value between two strings joining all three strings together using the string addition operator. The value of resp is the one captured from the user by input().

Notice too in both examples the use of spaces inside the strings, both in the prompt given to input() but also in the output string. In particular notice the third part of the output string started with a comma followed by a space. It is a common mistake when producing output like that to get the spacing wrong so check carefully when testing your programs.

This is great for reading strings. But what about other data types? The answer is that Python comes with a full set of data conversion functions that can convert a string to another data type. Obviously the data in the string has to be compatible with the type, otherwise you will get an error!

As an example lets take our multiplication table example and modify it to read the multiplier value from the user:

>>> multiplier = input("Which multiplier do you want? Pick a number ")
>>> multiplier = int(multiplier)
>>> for j in range(1,13):
...   print( "%d x %d = %d" % (j, multiplier, j * multiplier) )

Here we read the value from the user then convert it to an integer using the int() conversion function. (You can use float() to convert to a floating point value too, should you need to). Here we did the conversion on a separate line to make it clearer what we were doing, but in practice this is so common that we usually just wrap the input() call inside the conversion, like this:

>>> multiplier = int( input("Which multiplier do you want? Pick a number ") )
>>> for j in range(1,13):
...   print( "%d x %d = %d" % (j, multiplier, j * multiplier) )

You see? We just wrapped the input() call inside the call to int().

So what about using this in a real program? You recall the address book examples using a dictionary that we created in the raw materials topic? Let's revisit that address book now that we can write loops and read input data.

# create an empty address book dictionary
addressBook = {}

# read entries till an empty string
print()  # print a blank line 
name = input("Type the Name(leave blank to finish): ") 
while name != "":
   entry = input("Type the Street, Town, Phone.(Leave blank to finish): ")
   addressBook[name] = entry
   name = input("Type the Name(leave blank to finish): ")

# now ask for one to display
name = input("Which name to display?(leave blank to finish): ")
while name != "":
   print( name, addressBook[name] )
   name = input("Which name to display?(leave blank to finish): ")

That's our biggest program so far, involving sequences and two loops, and although the user interface design is a bit clunky, it does the job. We will see how to improve it in later topics. Some things to note in this program are the use of the boolean test in the while loops to determine when the user wants us to stop. Also note that whereas in the Raw Materials example we used a list to store the data as separate fields we have just stored it as a single string here. That's because we haven't yet covered how to break down a string into separate fields. We'll cover that in a later topic too.

The address book program will be cropping up from time to time through the rest of the tutorial as we gradually turn it into something useful.

VBScript Input

In VBScript the InputBox statement reads input from the user thus:

<script type="text/vbscript">
Dim Input
Input = InputBox("Enter your name") 
MsgBox ("You entered: " & Input)
</script>

The InputBox function simply presents a dialog with a prompt and an entry field. The contents of the entry field are returned by the function. There are various values that you can pass to the function such as a title string for the dialog box in addition to the prompt. If the user presses Cancel the function returns an empty string regardless of what is actually in the entry field.

Here is the VBScript version of our Address book example.

<script type="text/vbscript">
Dim dict,name,entry  ' Create some variables.
Set dict = CreateObject("Scripting.Dictionary")
name = InputBox("Enter a name", "Address Book Entry")
Do While name <> ""
   entry = InputBox("Enter Details - Street, Town, Phone number",
                    "Address Book Entry")
   dict.Add name, entry ' Add key and details.
   name = InputBox("Enter a name","Address Book Entry")
Loop

' Now read back the values
name = InputBox("Enter a name","Address Book Lookup")
Do While name <> ""
   MsgBox(name & " - " & dict.Item(name))
   name = InputBox("Enter a name","Address Book Lookup")
Loop
</script>

The basic structure is absolutely identical to the Python program although a few lines longer because of VBScript's need to pre-declare the variables with Dim and because of the need for a Loop statement to end each loop.

Reading input in JavaScript

JavaScript presents us with a challenge because it is a language primarily used within a web browser. We have a choice of using a simple input box like VBScript using the prompt() function or instead we can read from an HTML form element (or, in Internet Explorer, use Microsoft's Active Scripting technology to generate an InputBox dialog like the one used by VBScript). For variety I'll show you how to use the HTML form technique. If you are unfamiliar with HTML forms it might be worth finding an HTML reference or tutorial to describe them, alternatively just copy what I do here and hopefully it will be self explanatory. (We explore HTML in a little more detail in the web applications topics at the end of the tutorial.) For now I will be keeping it very simple, I promise.

<form id='entry' name='entry'>
<p>Type a value then click outside the field with your mouse</p>
<input type='text' name='data' 
          onChange='alert("We got a value of " + document.forms["entry"].data.value);'>
</form>

The HTML just consists of a form which contains a single line paragraph (<p>), providing a message to the user, and a text input field. The input field has a line of code associated with it which is executed whenever the input value changes. The code simply pops up an alert message box (very similar to VBScript's MsgBox) containing the value from the text field.

The form has id and name attributes of 'entry'. Within the document context the forms (we only have 1) are stored in an array indexed by name (recall JavaScript arrays can be used like dictionaries too?). The input field also has a name, 'data' within the entry form context. Thus within the JavaScript program we can refer to the value of the field as:

document.forms["entry"].data.value

I'm not going to show the address book example in JavaScript because the HTML aspects become more complex and we need to introduce the use of functions and I want to wait till we have covered those in their own topic.

Next we take a short detour to discuss a fundamental concept of command-line computing; the concept of data streams.

A word about stdin and stdout

NOTE: stdin is a bit of computer jargon for the standard input device (usually the keyboard). stdout refers to the standard output device (usually the screen). You will quite often see references to the terms stdin and stdout in discussions about programming. (There is a third, less commonly used term, stderr, which is where all console error messages are sent. Normally stderr appears in the same place as stdout.) These terms are often called data streams since data appears as a stream of bytes flowing to the devices. stdin and stdout are made to look like files (we'll get to those shortly) for consistency with file handling code.

In Python they all live in the sys module and are called sys.stdin and sys.stdout. The input() function uses stdin automatically and print() uses stdout. We can also read from stdin and write to stdout directly and this can offer some advantages in terms of fine control of the input and output. Here is an example of reading from stdin:

import sys
print( "Type a value: ", end='', flush=True)  # prevents newline and forces write
value = sys.stdin.readline()  # use stdin explicitly
print( value )

It is almost identical to:

print( input("Type a value: ") )

Note that we had to use flush=True as an option to print(). Without that, print does not actually display its output until after the next print() has completed! (It is effectively waiting for a newline.) flush forces the file-cache to write its contents to stdout.

The advantage of the explicit version is that you can do fancy things like make stdin point to a real file so the program reads its input from the file rather than the terminal - this can be useful for long testing sessions whereby instead of sitting typing each input as requested we simply let the program read its input from a file. (This has the added advantage of ensuring that we can run the test repeatedly, sure that the input will be exactly the same each time, and so, hopefully, will the output. This technique of repeating previous tests to ensure that nothing got broken is called regression testing by programmers.)

Finally here is an example of direct output to sys.stdout that can likewise be redirected to a file. print is nearly equivalent to:

sys.stdout.write("Hello world\n") # \n= newline

Of course we can usually achieve the same effects using format strings if we know what the data looks like but if we don't know what the data will look like till runtime then its often easier to just send it to stdout rather than try to build a complex format string at runtime.

Redirecting stdin & stdout

So how do we redirect stdin and stdout to files? We can do it directly within our program using the normal Python file handling techniques which we will cover shortly, but the easiest way is to do it via the operating system.

This is how the operating system commands work when we use redirection at the command prompt:

C:> dir
C:> dir > dir.txt

The first command prints a directory listing to the screen (the default stdout). The second prints it to a file. By using the '>' sign we tell the program to redirect stdout to the file dir.txt. We would do the same with a Python program like this:

$ python myprogram.py > result.txt

Which would run myprogram.py but instead of displaying the output on screen it would write it to the file result.txt. We could see the output later using a text editor like notepad.

(Note that the $ prompt shown above is the standard for Linux or MacOS users - just in case they were feeling neglected!)

We can also redirect the output of print using the optional file="result.txt" argument. This has the advantage of being controllable on a statement by statement basis but the disadvantage that the file name has to be hard coded into the program. It is more suited to printing a specific subset of your output rather than as a general means of saving output to a file. Even in this case, direct file output is preferable, so the file= option is not often used.

To get stdin to point at a file we simply use a < sign rather than a > sign. Here is a complete example:

First create a file called echoinput.py containing the following code:

import sys
inp = input()
while inp != '':
   print( inp )
   inp = input()

You can now try running that from a command prompt:

$ python echoinput.py

The result should be a program that echos back anything you type until you enter a blank line.

Now create a simple text file called input.txt containing some lines of text. Run the last program again, redirecting input from input.txt:

$ python echoinput.py < input.txt

Python echos back what was in the file.

By using this technique with multiple different input files we can quickly and easily test our programs for a variety of scenarios (for example bad data values or types) and do so in a repeatable and reliable manner. We can also use this technique to handle large volumes of data from a file while still having the option to input the data manually for small volumes using the same program. Redirecting stdin and stdout is a very useful trick for the programmer, experiment and see what other uses you can find for it.

There is a known bug in Windows XP that breaks input redirection. (If anyone knows whether this has been fixed in later Windows versions please let me know via the email link at the bottom of the page.) If you start your program by just typing in the script name, rather than explicitly typing in python before it, Windows will not display the results on the console! There is a registry hack to fix this on Microsoft's web site, although even the hack isn't quite correct! You need to look under HKEY_CURRENT USER instead of HKEY_LOCAL_MACHINE as recommended on the web page. My recommendation is to always explicitly invoke python when dealing with redirected input or output! (Thanks go to Tim Graber for spotting this and to Tim Peters for telling me about the registry hack to fix it.)

Command Line Parameters

One other type of input is from the command line. For example when you run your text editor from an operating system command line, like:

  $ edit Foo.txt
  

What happens is that the operating system calls the program called edit and passes it the name of the file to edit, Foo.txt in this case. So how does the editor read the filename?

In most languages the system provides an array or list of strings containing the command line words. Thus, the first element will contain the command itself, the second element will be the first argument, etc. There may also be some kind of magic variable (often called something like argc, for "argument count") that holds the number of elements in the list.

In Python that list is held by the sys module and called argv (for 'argument values'). The very first item in the list (argv[0]) is the name of the script file being executed. Python doesn't need an argc type value since the usual len() method can be used to find the length of the list, and in most cases we don't even need that since we just iterate over the list using Python's for loop, like this:

import sys
for item in sys.argv:
    print( item )
    
print( "The first argument was:", sys.argv[1] )

Note that this only works if you put it in a file (say args.py) and execute it from the operating system prompt like this:

C:\PYTHON\PROJECTS> python args.py 1 23 fred
args.py
1
23
fred
The first argument was: 1
C:\PYTHON\PROJECTS>

Note that if you have an argument with spaces in it you will need to surround it with quotes, like so:

C:\PYTHON\PROJECTS> python args.py "Alan Gauld" fred
args.py
Alan Gauld
fred
The first argument was: Alan Gauld
C:\PYTHON\PROJECTS>

VBScript and JavaScript

Being web page based the concept of command line arguments doesn't really arise. If we were using them within Microsoft's Windows Script Host environment the situation would be different, and WSH provides a mechanism to extract such arguments from a WshArguments object populated by WSH at run time.

That's really as far as we'll go with user input in this course. It's very primitive but you can write useful programs with it. In the early days of Unix or PCs it was the only kind of interaction you got. Of course GUI programs read input too, but the techniques are entirely different and we will look at how that's done much later in the tutorial.

Points to remember

Previous  Next