Conversing with the user

What will we cover?
  • How to prompt the user to enter data and how to read that data once it is entered.
  • We will show how to read both numerical and string based data.
  • The concepts of stdin and stdout
  • We look at command line interfaces and how to read data input as command line arguments.
  • 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 command (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 at the first two methods, we introduce GUI programming much later in the tutor because it is significantly more complex.

    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.

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

    As you see raw_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 = raw_input("What's your name? ")
    

    And now we can print out whatever value was captured:

    >>> print "Hi, %s, nice to meet you" % resp 
    

    Notice that we use the string formatting operator to display the value stored in the variable resp and that value is the one captured from the user by raw_input.

    raw_input() has a cousin called input(). The difference is that raw_input() collects the characters the user types and presents them as a string, whereas input() collects them and tries to evaluate them as some kind of data. For example if the user types '1','2','3' then input will read those 3 characters and convert them into the number 123.

    Let's use input to decide which multiplication table to print:

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

    Unfortunately there's a big snag to using input(). That's because input() doesn't just evaluate numbers but rather treats any input as Python code and tries to execute it. Thus a knowledgeable but malicious user could type in a Python command that deleted a file on your PC! For this reason it's better to stick to raw_input() and convert the string into the data type you need using Python's built in conversion functions. This is actually pretty easy:

    >>>multiplier = int(raw_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 raw_input() call in a call to int(). It has the same effect as using input but is much safer. There are other conversion functions too so that you can convert to floats etc as well.

    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 
    name = raw_input("Type the Name - leave blank to finish")
    while name != "":
       entry = raw_input("Type the Street, Town, Phone. Leave blank to finish")
       addressBook[name] = entry
       name = raw_input("Type the Name - leave blank to finish")
    
    # now ask for one to display
    name = raw_input("Which name to display?(blank to finish)")
    while name != "":
       print name, addressBook[name]
       name = raw_input("Which name to display?(blank to finish)")
    

    That's our biggest program so far, and although the user interface design is a bit clunky it does the job. We will see how to improve it in a later topic. 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. In fact 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")
    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")
    Wend
    
    ' Now read back the values
    name = InputBox("Enter a name","Address Book Lookup")
    While name <> ""
       MsgBox(name & " - " & dict.Item(name))
       name = InputBox("Enter a name","Address Book Lookup")
    Wend
    </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 Wend 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. I will be keeping it very simple, I promise.

    The basic structure of our HTML example will be to put the JavaScript code in a function, although we haven't covered these yet. For now just try to ignore the function definition bits.

    <script type="text/javascript">
    function myProgram(){
       alert("We got a value of " + document.entry.data.value);
    }
    </script>
    
    <form name='entry'>
    <P>Type value then click outside the field with your mouse</P>
    <Input Type='text' Name='data' onChange='myProgram()'>
    </form>
    

    The program just consists of a single line that displays an alert box (very similar to VBScript's MsgBox) containing the value from the text field. The form displays a prompt message (within the <P></P> pair) and an input field. The form has a name, entry within the document context, and the Input field 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.entry.data.value
    

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

    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 term 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. raw_input() 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: ",  # comma prevents newline
    value = sys.stdin.readline()  # use stdin explicitly
    print value
    

    It is almost identical to:

    print raw_input("Type a value: ")
    

    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
    

    The main practical use for this is to get around the fact that print always puts a space between the output values, whereas with stdout we can avoid that. Compare the two output lines in the example below:

    import sys
    for item in ['one','is',1]: 
        print item,  # comma suppresses newline
    print 
    for item in ['one','is',str(1)]: # must explicitly convert to strings
        sys.stdout.write(item)  # no spaces!
    

    Of course we can achieve the same effect 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 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 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.


    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 = sys.stdin.readline()
    while inp.strip() != '':
       print inp
       inp = sys.stdin.readline()
    

    Note: The strip() simply chops off the newline character that is retained when reading from stdin, raw_input() does that for you as a convenience.

    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. But you might recall that we said that print and raw_input actually use stdin and stdout internally? That means we can replace the stdin stuff in echoinput.py with raw_input() like this:

    inp = raw_input()
    while inp != '':
       print inp
       inp = raw_input()
    

    Which is much easier in most cases.


    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 that breaks input redirection. 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'). 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>
    

    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's the only kind of interaction you got. Of course GUI programs read input too and we will look at how that's done much later in the tutorial.

    Points to remember
    • Use input for reading numbers, raw_input for reading characters/strings.
    • Both input and raw_input can display a string to prompt the user.
    • Command line parameters can be obtained from the argv list imported from the sys module in Python, where the first item is the name of the program.

    Previous  Next  Contents


    If you have any questions or feedback on this page send me mail at: alan.gauld@yahoo.co.uk