Standard input and exceptions

Documentation about exceptions

  1. Exceptions in the Python Tutorial
  2. Exceptions in the Python Language Reference
  3. Exception statements in the Python Language Reference:
    1. try
    2. except
    3. else
    4. finally
  4. List of built-in exceptions (EOFError, KeyboardInterrupt, ZeroDivisionError, TypeError, ValueError, etc.)
  5. EAFP vs. LBYL in the Python Glossary

The script

stdin.py

The input and output

What is your first name? John
What is your last name? Smith
Hello, John Smith.

The input built-in function

The input function writes its argument to the standard input. For legibility, you probably want this argument to end with a space. It then waits for the user to type something and press return. The line that the user typed (minus the “trailing newline” or invisible return character) is the value produced by this function. We store the value into a variable for future use.

In Python 2, this function was named raw_input with an underscore.

Things to try

  1. Verify that input captures the entire line of input (minus the return character), not just the first word.
    What is your first name? Johann Sebastian
    What is your last name? Bach
    Hello, Johann Sebastian Bach.
    
  2. Instead of typing a name, the user can signal the end of input by typing control-d on macOS and Linux, or control-d enter on Microsoft Windows. That’s how the user announces their intention to type no more input into the program.
    What is your first name? control-d
    Traceback (most recent call last):
      File "/Users/myname/python/stdin.py", line 11, in <module>
        first = input("What is your first name? ")
    EOFError: EOF when reading a line
    >>>
    

    The user can also type control-c at any time to kill the program on macOS and Linux.

    What is your first name? Jocontrol-c
    Traceback (most recent call last):
      File "/Users/myname/python/stdin.py", line 11, in <module>
        first = input("What is your first name? ")
    KeyboardInterrupt
    >>>
    

    These kinds of error are called (euphemistically) exceptions. We say that the statement

    first = input("What is your first name? ")
    
    has raised an exception when something goes wrong.

    To prevent the Python program from being terminated by this exception, surround each vulnerable input statement with try and except. The try and except act like the containment dome on a nuclear reactor: they contain the explosion and prevent it from terminating the entire program. If the surrounded statement or statements raise an exception (i.e., if there was an explosion), the statements indented beneath the except will be executed. Otherwise, these statements will be skipped. Do all your indentation in this course with groups of exactly four spaces. Do not use tabs. See Intermezzo: Coding Style.

    The try/except style is called EAFP, a phrase invented by Grace Hopper. (The alternative if/else style is called LBYL.)

    """
    stdin.py
    
    Prompt the user for their name.
    Read the name from the standard input, and send a geeting to the standard
    output.
    """
    
    import sys
    
    try:
        first = input("What is your first name? ")
        last = input("What is your last name? ")
    except BaseException as error: #Create a variable named error containing an error message.
        print(error)
        sys.exit(1) #1 means unsuccessful termination
    
    print(f"Hello, {first} {last}.")
    sys.exit(0)     #0 means successful termination
    

    When I raised the EOFError exception (i.e., when I typed control-d), an error message was placed in the error variable. Unfortunately, when I raised the KeyboardInterrupt exception (i.e., when I typed control-c), no error message was placed in the error variable. In both cases, the program terminated tamely, without spilling blood on the screen.

    What is your first name? control-d
    EOF when reading a line
    >>>
    
    What is your first name? Jocontrol-c
    
    >>>
    
  3. Instead of printing a pre-programmed error message, you can invent a different error message of your own choosing for each type of exception. For example, EOFError and KeyboardInterrupt are two types of BaseException. (In the jargon of Object Oriented Programming, we say that class EOFError and class KeyboardInterrupt are subclasses of class BaseException.)
    """
    stdin.py
    
    Prompt the user for their name.
    Read the name from the standard input, and send a geeting to the standard
    output.
    """
    
    import sys
    
    try:
        first = input("What is your first name? ")
        last = input("What is your last name? ")
    except EOFError:
        print("Since you decline to answer, the program had decided to halt.")
        sys.exit(1)
    except KeyboardInterrupt:
        print("You have just killed the program.")
        sys.exit(1)
    
    print(f"Hello, {first} {last}.")
    sys.exit(0)
    
  4. Now that we know that input will capture the entire line (exercise 1), let’s type in a complete sentence.
    pip3 list
    
    pip3 install googletrans
    Successfully installed googletrans-2.4.0
    
    pip3 list
    Package        Version
    googletrans    2.4.0
    
    pip3 show googletrans
    Name: googletrans
    Version: 2.4.0
    Summary: Free Google Translate API for Python. Translates totally free of charge.
    Home-page: https://github.com/ssut/py-googletrans
    Author: SuHun Han
    Author-email: ssut@ssut.me
    License: MIT
    Location: /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages
    Requires: requests
    Required-by:
    
    pip3 show --verbose --files googletrans
    
    translate --help
    translate --src en --dest es "Hello, how are you?"
    

    AWS Linux:

    ls -ld /usr/local/lib/python3.7/site-packages/
    drwxr-xr-x 2 root root 6 Feb  9 17:36 /usr/local/lib/python3.7/site-packages/
    
    sudo pip3 install googletrans
    
    """
    Translate a sentence from English to Spanish.
    """
    
    import sys
    import requests
    import googletrans
    
    print("What sentence do you want to translate from English to Spanish?")
    
    try:
        s = input("Go ahead: ")
    except BaseException as error:
        print(error)
        sys.exit(1)
    
    translator = googletrans.Translator()
    
    try:
        translation = translator.translate(s, src = "en", dest = "es")   #Español
    except requests.exceptions.ConnectionError:
        print("Your Internet connection is down.")
        sys.exit(1)
    except TypeError:
        print("You have to type some words.  You can't just type nothing.")
        sys.exit(1)
    except BaseException as error:   #none of the above exceptions
        print(error)
        sys.exit(1)
    
    print(translation.text)
    #print(googletrans.LANGUAGES) #possible source and destination languages
    sys.exit(0)
    
    What sentence do you want to translate from English to Spanish?
    Go ahead: Tonight I can write the saddest lines.
    Esta noche puedo escribir las líneas más tristes.
    

    Three nicer ways to print the dictionary googletrans.LANGUAGES.

    for key in googletrans.LANGUAGES:
        value = googletrans.LANGUAGES[key]
        print(key, value)
    
    #To loop through the return value of items, must have 2 variables after for.
    
    for key, value in googletrans.LANGUAGES.items():
        print(key, value)   #key is abbreviation, value is full name
    
    #Slap on line numbers.
    #To loop through the return value of enumerate, must have 2 variables after for.
    #In this case, the second of these two variables happens to be a tuple.
    
    for i, (key, value) in enumerate(googletrans.LANGUAGES.items(), start = 1):
        print(i, key, value)
    
  5. The value returned by input is a string (i.e., series) of characters, not a number. The following + operator therefore concatenates two strings.
    import sys
    
    i = input("Please type a number: ")
    j = input("Please type another number: ")
    sum = i + j
    print(f"The sum of {i} and {j} is {sum}.")
    
    sys.exit(0)
    
    Please type a number: 10
    Please type another number: 20
    The sum of 10 and 20 is 1020.
    

    The solution is to convert each incoming string to an integer or to a floating point number before using it as an addend.

    import sys
    
    s = input("Please type a number: ")
    i = int(s)
    
    s = input("Please type another number: ")
    j = int(s)
    
    sum = i + j
    print(f"The sum of {i} and {j} is {sum}.")
    
    sys.exit(0)
    
    Please type a number: 10
    Please type another number: 20
    The sum of 10 and 20 is 30.
    

    You could telescope the above code using a nested function call. We saw a nested call here.

    i = int(input("Please type a number: "))
    j = int(input("Please type another number: "))
    sum = i + j
    print(f"The sum of {i} and {j} is {sum}.")
    
    Please type a number: 10
    Please type another number: 20
    The sum of 10 and 20 is 30.
    

    If the user might type a number with a decimal point and fraction, convert the incoming strings to the data type float:

    s = input("Please type a number: ")
    x = float(s)
    
    s = input("Please type another number: ")
    y = float(s)
    
    sum = x + y
    print(f"The sum of {x} and {y} is {sum}.")
    
    Please type a number: 10.5
    Please type another number: 20
    The sum of 10.5 and 20.0 is 30.5.
    
  6. If some joker types hello into the above script, the statement that calls float will explode and terminate the script.
    Please type a number: 10
    Please type another number: hello
    Traceback (most recent call last):
      File "/Users/myname/python/stdin.py", line 14, in <module>
        j = float(j)
    ValueError: could not convert string to float: 'hello'
    
    import sys
    
    s = input("Please type a number: ")
    
    try:
        x = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        x = 0.0
        print(f"I'll assume you wanted to type {x}.")
    
    s = input("Please type another number: ")
    
    try:
        y = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        y = 0.0
        print(f"I'll assume you wanted to type {y}.")
    
    sum = x + y
    print(f"The sum of {f} and {y} is {sum}.")
    
    sys.exit(0)
    
    Please type a number: 10
    Please type another number: hello
    Sorry, hello is not a number.
    I'll assume you wanted to type 0.
    The sum of 10.0 and 0.0 is 10.0.
    
  7. Instead of composing your own error message in the above program, you can change
    except ValueError:
        print(f"Sorry, {s} is not a number.")
    
    to the following. If the float function raises an exception of type ValueType, the exception will be stored in a variable that I decided to name error.
    except ValueError as error:
        print(f"ValueError: {error}")
    
    ValueError: could not convert string to float: 'hello'
    
  8. The user can signal the end of input with control-d on macOS or Linux, control-z enter on Microsoft Windows. That’s how the user announces their intention to type no more input into the program.
    Please type a number: control-d
    Traceback (most recent call last):
      File "/Users/myname/python/stdin.py", line 11, in <module>
        s = input("Please type a number: ")
    EOFError: EOF when reading a line
    

    The user can also type control-c to kill the program on macOS and Linux.

    Please type a number: 12control-c
    Traceback (most recent call last):
      File "/Users/myname/python/stdin.py", line 11, in <module>
        s = input("Please type a number: ")
    KeyboardInterrupt
    

    If the user types the above keystrokes we’ll terminate the script for them, silently and without all the error messages, but with an exit status of 1 to indicate that we have not accomplished the primary mission.

    import sys
    
    try:
        s = input("Please type a number: ")
    except EOFError:          #unable to input any characters
        sys.exit(1)
    except KeyboardInterrupt: #user kills the program
        sys.exit(1)
    
    try:
        f = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        f = 0.0
        print(f"I'll assume you wanted to type {f}.")
    
    try:
        s = input("Please type another number: ")
    except EOFError:          #unable to input any characters
        sys.exit(1)
    except KeyboardInterrupt: #user kills the program
        sys.exit(1)
    
    try:
        g = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        g = 0.0
        print(f"I'll assume you wanted to type {g}.")
    
    sum = f + g
    print(f"The sum of {f} and {g} is {sum}.")
    
    sys.exit(0)
    
    Please type a number: control-d
    (Script terminates silently, without error message, and produces exit status 1.)
    
    Please type a number: 10
    Please type another number: hello
    Sorry, hello is not a number.
    I'll assume you wanted to type 0.
    The sum of 10.0 and 0.0 is 0.0.
    
  9. An example we saw earlier.
    import sys
    
    try:
        s = input("How much capital do you have? ")
    except EOFError:
        sys.exit(1)
    except KeyboardInterrupt:
        sys.exit(1)
    
    try:
        capital = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        capital = 0.0
        print(f"I'll assume your capital is {capital}.")
    
    try:
        s = input("What percent interest are you getting? ")
    except EOFError:
        sys.exit(1)
    except KeyboardInterrupt:
        sys.exit(1)
    
    try:
        rate = float(s)
    except ValueError:
        print(f"Sorry, {s} is not a number.")
        rate = 0.0
        print(f"I'll assume your rate is {rate}.")
    
    try:
        s = input("Compounded annually for how many years? ")
    except EOFError:
        sys.exit(1)
    
    try:
        years = float(s)
    except ValueError:
        print(f"Sorry, {years} is not a number.")
        years = 0.0
        print(f"I'll assume your number of years is {years}.")
    
    fraction = 1 + rate / 100
    final = capital * fraction ** years
    
    print(f"After {years} years, you will end up with ${round(final, 2)}")
    
    sys.exit(0)
    
    How much capital do you have? 100000.00
    What percent interest are you getting? 4
    Compounded annually for how many years? 20
    After 20.0 years, you will end up with $219112.31
    
  10. Write a Python program named inout.py that does input and output. Make it much more interesting than the following.
    How old are you? 61
    That's about 9 dog years!
    
    How many pounds does the turkey weigh? 16
    How many minutes per pound? 20
    That's 320 minutes, or 5 hours and 20 minutes.
    

    To create the script, pull down the IDLE menu
    File → New File
    Type your Python program into the new Untitled window.
    To save and run the script, pull down
    Run → Run Module
    When you save the program, name it inout.py.
    Then follow these instructions to create a GitHub repository and copy your program into the repository.

A script that invites you to tell it a knock-knock joke

knockknock.py

Tell me a knock-knock joke. Knock knock.
Who's there? Rufus
Rufus who? Rufus the most important part of your house.
Ha ha ha ha ha ha!