Input from the console

Published

2023-08-02

Motivation

It’s often the case that as we are writing code, we don’t have all the information we need for our program to produce the desired result. For example, imagine you were asked to write a calculator program. No doubt, such a program would be expected to add, subtract, multiply, and divide. But what should it add? What should it multiply? You, as the programmer, would not know in advance. Thus, you’d need a way to get information from the user into the program.

Of course, there are many ways to get input from a user. The most common, perhaps, is via a graphical user interface or GUI. Most, or likely all, of the software you use on your laptop, desktop, tablet, or phone makes use of a GUI.

In this chapter, we’ll see how to get input in the most simple way, without having to construct a GUI. Here we’ll introduce getting user input from the console. Later, in Chapter 13, we’ll learn how to read data from an external file.

Command line interface

We’ve seen how to use the Python shell, where we type expressions or other Python code and it’s executed interactively.

What we’ll learn now is how to write what are called CLI programs. That’s short for command line interface. This distinguishes them from GUI or graphical user interface programs.

When we interact with a CLI program, we run it from the command line (or within your IDE) and we enter data and view program output in text format. We often refer to this interaction as taking place within the console. The console is just a window where we receive text prompts, and reply by typing at the keyboard.

This has a similar feel to the Python shell: prompt then reply, prompt then reply.

The input() function

Python makes it relatively easy to get input from the console, using the built-in function input(). The input() function takes a single, optional parameter—a string—which, if supplied, is used as a prompt displayed to the user.

Here’s a quick example at the Python shell:

>>> input("What is your name? ")
What is your name? Sir Robin of Camelot
'Sir Robin of Camelot'
>>> input("What is your favorite color? ")
What is your favorite color? Blue
'Blue'
>>> input("What is the capital of Assyria? ")
What is the capital of Assyria? I don't know that!
"I don't know that!"

input() takes a string as an argument. This string is displayed as a prompt to the user, like “How old are you?” or “How many cookies would you like to bake?” or “How long are your skis (in cm)?” After displaying a prompt, input() waits for the user to enter something at the keyboard. When the user hits the return key, input() returns what the user typed as a string.

Again, here’s an example in the Python shell—notice we’re going to store the value returned by the input() function using a variable.

>>> users_name = input("What is your name? ")
What is your name? Sir Robin of Camelot
>>> users_name
'Sir Robin of Camelot'

Try this out on your own in the Python shell.

Here’s what just happened. On the first line (above) we called the input() function and supplied the string argument “What is your name? ”. Then, on the second line, input() does its work. It prints “What is your name?” and then waits for the user to type their response. In this case, the user has typed “Sir Robin of Camelot”. When the user hits the enter/return key, the input() function returns what the user typed (before hitting enter/return) as a string. In this example, the string returned by input() is assigned the name users_name. On the third line, we enter the expression users_name and Python obliges by printing the associated value: “Sir Robin of Camelot”.

Here’s a short program that prompts the user for their name and their quest, and just echoes back what the user has typed:

"""Prompts the user for their name and quest 
and prints the results. """

name = input('What is your name? ')
quest = input('What is your quest? ')

print(name)
print(quest)

Try it out. Copy this code, paste it into an editor window in your text editor or IDE, and save the file as name_and_quest.py. Then run the program. When run, the program first will prompt the user with ‘What is your name? ’ and then it will assign the value returned by input() to the variable name. Then it will prompt for the user’s quest and handle the result similarly, assigning the result to the variable quest. Once the program has gathered the information it needs, it prints the name and quest that the user provided.

A session for this might look like this:

What is your name? Galahad
What is your quest? To seek the Holy Grail!
Galahad
To seek the Holy Grail!

Notice that in order to use the strings returned by input() we assigned them to variables. Again, remember that the input() function returns a string.

That’s pretty convenient, when what we want are strings, but sometimes we want numeric data, so we’ll also learn how to convert strings to numeric data (where possible) with the functions int() and float().

Converting strings to numeric types

The problem

Here’s an example which illustrates a problem we encounter when trying to get numeric input from the user—the input() function always returns a string and we can’t do math with strings.

"""
Prompts the user for weight in kilograms 
and converts to (US customary) pounds.
"""

POUNDS_PER_KILOGRAM = 2.204623


def kg_to_pounds(kg_):
    return kg_ * POUNDS_PER_KILOGRAM
    

kg = input("Enter the weight in kilograms (kg): ")
lbs = kg_to_pounds(kg)
print(lbs)

If we save this code to file and try running it, it will fail when trying to convert kilograms to pounds. We’ll get the message:

TypeError: can't multiply sequence by non-int of type 'float'

What happened? When the program gets input from the user:

kg = input("Enter the weight in kilograms (kg): ")

the value returned from the input() function is a string. The value returned from the input() function is always a string. Say the user enters “82” at the prompt. Then what gets saved with the name kg is the string '82' not the number 82 and we can’t multiply a string by a floating point number—that makes no sense!

Happily, there’s an easy fix. Python provides built-in functions that can be used to produce objects of numeric types from a string (if possible). These are the integer constructor, int(), and the float constructor, float(). These functions can take a string which looks like it ought to be convertible to a number, performs the conversion, and returns an object of the corresponding numeric type.

Let’s try these out in the Python shell:

>>> int('82')
82
>>> float('82')
82.0

In the first instance, we pass the string '82' as an argument to the int() constructor to get an int. In the second instance, we pass the string '82' as an argument to the float() constructor to get a float.

What happens if have a string like '82.5'? This is a valid input to the float() constructor, but does not work with the int() constructor.

>>> float('82.5')  # this works OK
82.5
>>> int('82.5')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '82.5'

The error message is telling us that the string '82.5' cannot be converted to an int.

Now, returning to the problem at hand—converting user input to a floating point number—here’s how we fix the code we started with.

"""
Prompts the user for weight in kilograms 
and converts to (US customary) pounds.
"""

POUNDS_PER_KILOGRAM = 2.204623


def kg_to_pounds(kg_):
    return kg_ * POUNDS_PER_KILOGRAM
    

kg = float(input("Enter the weight in kilograms (kg): "))
lbs = kg_to_pounds(kg)
print(lbs)

Notice that we wrapped the call to input() within a call to the float constructor. This expression is evaluated from the inside out (as you might suspect). First the call to input() displays the prompt provided, waits for input, then returns a string. The value returned (say, '82.5') is then passed to the float constructor as an argument. The float constructor does its work and the constructor returns a floating point number, 82.5. Now, when we pass this value to the function kg_to_pounds(), everything works just fine.

If you’ve seen mathematical functions before this is no different from something like

f(g(x))

where we would first calculate g(x) and then apply f to the result.

Another scenario with a nasty bug

Consider this program which has a nasty bug:

"""This program has a bug! 
It does not add as you might expect. """

a = input("Enter an integer: ")
b = input("Enter another integer: ")
print(a + b)

Can you see what the bug is?

Imagine what would happen if at the first prompt the user typed “42” and at the second prompt the user typed “10”. Of course, 42 plus 10 equals 52, but is that what this program would print?

No. Here’s a trial run of this program:

Enter an integer: 42
Enter another integer: 10
4210

“4210” is not the correct result! What happened?

Remember, input() always returns a string, so in the program above, a is a string and b is a string. Thus, when we perform the operation a + b it’s not addition, it’s string concatenation!

What do we do in cases like this? In order to perform arithmetic with user-supplied values from input(), we first need to convert input strings to numeric types (as above).

"""This program fixes the bug in the earlier program."""

a = input("Enter an integer: ")
b = input("Enter another integer: ")
a = int(a)
b = int(b)
print(a + b)

We can make this a little more concise:

"""Prompt the user for two integers and display the sum."""

a = int(input("Enter an integer: "))
b = int(input("Enter another integer: "))
print(a + b)

Conversion may fail

While the code samples above work fine if the user follows instructions and enters numeric strings that can be converted to integers, users don’t always read instructions and they aren’t always well-behaved. For example, if a misbehaved user were to enter values that cannot be converted to integers, we might see a session like this:

Enter an integer: cheese
Enter another integer: bananas
Traceback (most recent call last):
  File "/myfiles/addition_fixed.py", line 5, in <module>
    a = int(a)
ValueError: invalid literal for int() with base 10: 'cheese'

Process finished with exit code 1

This occurs because 'cheese' cannot be converted to an int. In this case, Python reports a ValueError and indicates the invalid literal 'cheese'. We’ll see how to handle problems like this later on in Chapter 15.

input() does not validate input

It’s important to note that input() does not validate the user’s input.

Validation is a process whereby we check to ensure that input from a user or some other source meets certain criteria. That’s a big topic we’ll touch on later, but for now, just keep in mind that the user can type just about anything at a prompt and input() will return whatever the user typed—without checking anything.

So a different session with the same program (above) might be

What is your name? -1
-1

Be warned.

Don’t use names that collide with names of built-in Python functions!

As noted, input, int, and float are names of built-in Python functions. It’s very important that you do not use such names as names for your own functions or variables. In doing so, for example, you’d be reassigning the name input, and thus the input() function would no longer be accessible. For example, this

input = input('What is your name? ')
print(input)  # so far, so good -- prints what the user typed
input = input('What is your quest? ')
print(input)

fails miserably, with

Traceback (most recent call last):
  File ".../3.10/lib/python3.10/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<input>", line 1, in <module>
TypeError: 'str' object is not callable

What happened? We assigned the result to an object named input, so after the first line (above) is executed, input no longer refers to the function, but instead is now a string (hence the error message “‘str’ object is not callable”).

So be careful to choose good names and avoid collisions with built-ins.

Additional resources

The documentation for any programming language can be a bit technical. But it can’t hurt to take a look at the documentation for input(), int(), and float(). If it makes your head spin, just navigate away and move on. But maybe the documentation can deepen your understanding of these functions. See relevant sections of:

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).