<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Basic Terminal Apps
By this point, you have learned enough Python to start building interactive apps. If you are set on the larger projects such as building a video game, making a visualization, or making a web app, you can skip this section. But if you would like to start building some simpler apps that run directly in your terminal, check out this notebook.
Terminal apps are a great way to build the core functionality of a program you are interested in, which can then be extended into a more accessible format.
Previous
Step1:  Now we will modify the program so that the screen is cleared right after the message is displayed
Step2:  There is no output to show here, because as soon as the message is displayed the screen is cleared. Run the program on your computer to see this.
The first line imports the module "os". This is a set of functions that let you interact with your operating system's commands. The line os.system('clear') tells Python to talk to the operating system, and ask the system to run the clear command. You can see this same thing by typing clear in any open terminal window.
On a technical note, the screen is not actually erased when you enter the clear command. Instead, the terminal is scrolled down one vertical window length. If you scroll the terminal window up, you can see the old output. This is fine, and it can actually be good to be able to scroll back up and look at some output you might have missed.
On Windows
Step3:  Everything is fine so far. Let's look at what happens when we have a bunch of output below the title bar. Copy the following code onto your machine and run it.
Step4:  I won't include the output here. All you should see are a number of lines about doing fun and interesting things together, with the title bar far up your terminal window, well above the visible portion. 
The sleep() function
Sometimes it is helpful to be able to pause a program for a moment. This can slow things down, and it can let us show output in intervals. Run this code on your own machine, and see if you can understand how it works
Step5:  If you ran this code, you should have seen the message "I'm going to sleep now." Then you should have seen nothing happen for 3 seconds, and then you should have seen the message "I woke up."
The first line imports the sleep() function from the module time. You will be seeing more and more import statements. Basically, we are importing a function from Python's standard library of functions.
The sleep function can accept decimal inputs as well, so you can pause for as short or as long in your programs as you want.
A slowly disappearing title bar
This time we are going to print out the title bar, but then we are going to print enough output that we start to lose the title bar. Run this code on your own machine to see the full effect
Step6:  You should have seen the title bar appear, and then groups of names appear every second for a while. At some point, the title bar probably disappeared. Now we are going to modify the code so that the screen is cleared each time through the loop.
Step7:  This time you should see the same output, but you should see a steady title bar, and the new information takes the place of the old information instead of being listed below the old output. We have a "running" application!
Reducing repeated code
If you understood the section Introducing Functions, you may have noticed that we have some repeated code in the last program listing. Any time you see a significant amount of repetition, you can probably introduce a function.
The repeated code in this example involves displaying the title bar. Let's write a function to show the title bar.
Step8:  Again, you really need to copy this code onto your own machine and run it locally to see this in action. You should see the same behavior as before.
It's interesting to note that having good comments makes writing functions easier. The comment just before the code for displaying the title bar was "Display the title bar." This practically gives us a name for the function that will take over this job
Step9:  If this is more appealing visually to you, feel free to use these kind of "section header" comments in your longer programs.
top
Building Greeter
Let's continue building Greeter. There are a couple more things we will introduce, but you should be able to follow everything we do.
We will start with the previous part where we have a persistent title bar, but we will remove the sleep functions. We will begin by offering users the choice to see a list of names, or enter a new name.
Step10:  If you run this code, you will see that it doesn't quite work. There are no Python errors, but the logic is a little off. We can enter choices, but the call to display_title_bar() at the beginning of the loop clears the screen as soon as the output is printed.
We can fix this by moving the call to display_title_bar(), and putting it in two places. We call display_title_bar() once just before we enter the loop, when the program starts running. But we also call it right after the user makes a choice, and before we respond to that choice
Step11:  This works, so let's put the menu into a function
Step12:  Now, let's make it so that the program actually does something.
We will make an empty list to store names.
We will print names from this list in choice 1.
We will get a new name in choice 2.
We will store that new name in the list of names.
Step13:  If you run this program, you will see that it works mostly as its supposed to. But the code in lines 37-50, where we are responding to the user's choice, is starting to get crowded. Let's move the code for choice 1 and choice 2 into separate functions
Step14:  This code doesn't behave any differently, but the main program itself is much easier to read. Lines 48-57 are a clean series of if-elif-else statements, each of which has a clear action.
Putting each action into its own function also lets us focus on improving that action. If you look at the function get_new_name(), you might notice that we are storing the name without checking anything about it. Let's put in a simple check to make sure we don't already know about this person.
Step15:  This works well. Now the program only stores new names, and names that are already in the list are greeted as old friends.
It's interesting to note that you can run this program through python tutor, and step through each line of the code. It's pretty enlightening to see exactly how the Python interpreter steps through a program like this. You can see all of the jumps from the main program to each of the functions, and the change in flow when the user makes a particular choice. It's informative to see which lines are skipped when certain if tests pass or fail.
There is one last thing we'd like Greeter to do, to consider it a basic terminal app. Let's make it remember the list of names after the program closes. To do this, let's learn about pickling using a simpler example.
top
Basic Pickling
When we "pickle" something in the physical world, we soak it in salt and vinegar so it won't rot. "Pickling" an object in Python packages it up and stores it on disk in a way that we can get it back in its original form later. You don't want to use pickle for imporant data, but it's a good way to get started with storing data after your program closes.
Here is a simple program that asks the user for some input, and then stores the input in a list. The program dumps the list to a file using pickle, and the next time the program runs it loads that data back in. Run this program on your computer, and see if it works for you.
Step16:  This program uses three new things
Step17:  The new try-except block at the beginning of the file works like this
<ASSISTANT_TASK:>
Python Code:
# Show a simple message.
print("I like climbing mountains.")
Explanation: Basic Terminal Apps
By this point, you have learned enough Python to start building interactive apps. If you are set on the larger projects such as building a video game, making a visualization, or making a web app, you can skip this section. But if you would like to start building some simpler apps that run directly in your terminal, check out this notebook.
Terminal apps are a great way to build the core functionality of a program you are interested in, which can then be extended into a more accessible format.
Previous: While Loops and Input | 
Home |
Next: Dictionaries
Contents
What are terminal apps?
Why write terminal apps?
Greeter - A simple terminal app
Clearing the screen
Exercises
A Persistent Title Bar
The sleep() function
A slowly disappearing title bar
Reducing repeated code
Building Greeter
Basic Pickling
Exercises
Pickling in Greeter
Overall Exercises
Overall Challenges
top
What are terminal apps?
A terminal application is simply an application that runs inside the terminal. By now, you have seen that most of the output from your programs is printed to the terminal. By learning a few more techniques such as clearing the terminal screen and "pickling" data, you can create full-fledged standalone applications that run in the terminal.
A terminal app starts just like any other program, but it finishes when the user selects an action that causes the program to quit. In terminal applications, this often means something like entering 'q' or 'quit'.
If you are on a linux system, you can run some terminal apps right now. Many of these are not written in Python, but that doesn't matter. They are applications that run in the terminal, and you can write your own apps in Python. If you are on Linux, try the following:
Open a terminal and enter top.
You will see a bunch of processes that are running on your system, sorted by which ones are using the most resources.
You can press 'q' to quit this application.
Open a terminal and enter nano test_file.txt. 
This is a text editor that runs in the terminal. It is useful for quick edits.
If you are editing files on a remote server, you need a terminal-based editor. Nano is one of the simplest.
Press Ctrl-x to exit. If you have typed anything, you will be given the option to save your file.
Open a terminal and enter vi.
This is another text editor. It is much less intuitive than nano at first, but once you learn how to use it you can edit files extremely quickly.
Enter :q to exit.
There are quite a few other terminal apps. Let's figure out how to write some of our own.
Why write terminal apps?
Unless you see people working in technical fields on a regular basis, it's quite possible you have not seen many people using terminal applications. Even so, there are a number of reasons to consider writing a few terminal apps of your own.
They can be much more fun and satisfying to write than simpler programs.
Applications, by their nature, solve interesting problems. When you write an application, you are creating an environment in which people work and play. That's pretty satisfying.
Terminal apps let you play with complex code, without layers of abstraction between you and the user.
When you write more complex graphical applications, there are layers of abstraction between you and the user. To get input in a terminal, you issue the command input("Please tell me some information: "). When you want some information in a graphical program, you have to build text boxes and buttons for submitting information. That has gotten pretty simple these days, but it is still more complicated than what you will do when writing terminal applications. Terminal applications let you focus on getting the logic right, rather than building a graphical interface.
You will learn about user interaction issues.
Terminal apps do have users, even if that is just you, and maybe your friends or family. If you see people using your applications at an early stage, you will write better code. There is nothing like watching people use your programs to make you code more defensively. You know to enter a string in some places, but what keeps your users from entering numbers? Influencing your users to give you the right information the first time, and being prepared to deal with the wrong kind of data are good skills as a programmer. Having real users at an early stage in your programming career is a good thing.
top
Greeter - A simple terminal app
Let's define a simple terminal app that we can make in this notebook. Greeter will:
Always display a title bar at the top of the screen, showing the name of the app that is running.
Offer you three choices:
Enter a name.
If the program knows that name, it will print a message saying something like "Hello, old friend."
If the program does not know that name, it will print a message saying something like, "It's nice to meet you. I will remember you."
The next time the program hears this name, it will greet the person as an old friend.
See a list of everyone that is known.
Quit.
The program will remember people, even after it closes.
The program may list the number of known people in the title bar.
Now we will go over a few things we need to know in order to build this app, and then we will build it.
top
Clearing the screen
You may have noticed that your programs which produce a lot of output scroll down the terminal. This keeps your program from looking like a running application. It's fairly easy to clear the terminal screen any time you want to, though.
Let's make a really simple program to show this:
End of explanation
###highlight=[2,7,8]
import os
# Show a simple message.
print("I like climbing mountains.")
# Clear the screen.
os.system('clear')
Explanation: Now we will modify the program so that the screen is cleared right after the message is displayed:
End of explanation
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
# Display a title bar.
print("\t**********************************************")
print("\t***  Greeter - Hello old and new friends!  ***")
print("\t**********************************************")
Explanation: There is no output to show here, because as soon as the message is displayed the screen is cleared. Run the program on your computer to see this.
The first line imports the module "os". This is a set of functions that let you interact with your operating system's commands. The line os.system('clear') tells Python to talk to the operating system, and ask the system to run the clear command. You can see this same thing by typing clear in any open terminal window.
On a technical note, the screen is not actually erased when you enter the clear command. Instead, the terminal is scrolled down one vertical window length. If you scroll the terminal window up, you can see the old output. This is fine, and it can actually be good to be able to scroll back up and look at some output you might have missed.
On Windows: The command to clear the terminal screen is different on Windows. The command os.system('cls') should work.
<a id="Exercises-clearing"></a>
Exercises
Simple Clear
Print one line to the screen.
Run your program to make sure the line actually prints.
Add a call to your system's "clear" command.
Run your program and make sure the line disappears.
If it didn't work, make sure you have the line import os at the top of your file.
top
A Persistent Title Bar
Let's consider how to make a title bar that stays at the top of the screen. We can't make this yet, because as our program creates more and more output, any title bar we print will disappear up the top of the screen.
Now that we know how to clear the screen, we can rebuild the screen that our user sees any time we want. Let's start out by printing a title bar for Greeter. If you want to follow along, type out the following code and save it as greeter.py:
End of explanation
###highlight=[10,11,12]
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
# Display a title bar.
print("\t**********************************************")
print("\t***  Greeter - Hello old and new friends!  ***")
print("\t**********************************************")
# Display a bunch of output, representing a long-running program.
for x in range(0,51):
    print("\nWe have done %d fun and interesting things together!" % x)
Explanation: Everything is fine so far. Let's look at what happens when we have a bunch of output below the title bar. Copy the following code onto your machine and run it.
End of explanation
# Import the sleep function.
from time import sleep
print("I'm going to sleep now.")
# Sleep for 3 seconds.
sleep(3)
print("I woke up!")
Explanation: I won't include the output here. All you should see are a number of lines about doing fun and interesting things together, with the title bar far up your terminal window, well above the visible portion. 
The sleep() function
Sometimes it is helpful to be able to pause a program for a moment. This can slow things down, and it can let us show output in intervals. Run this code on your own machine, and see if you can understand how it works:
End of explanation
###highlight=[2,12,13,15,16,17,18,19,20,21,22]
from time import sleep
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
# Display a title bar.
print("\t**********************************************")
print("\t***  Greeter - Hello old and new friends!  ***")
print("\t**********************************************")
# Print a bunch of information, in short intervals
names = ['aaron', 'brenda', 'cyrene', 'david', 'eric']
# Print each name 5 times.
for name in names:
    # Pause for 1 second between batches, and then skip two lines.
    sleep(1)
    print("\n\n")
    
    for x in range(0,5):
        print(name.title())
Explanation: If you ran this code, you should have seen the message "I'm going to sleep now." Then you should have seen nothing happen for 3 seconds, and then you should have seen the message "I woke up."
The first line imports the sleep() function from the module time. You will be seeing more and more import statements. Basically, we are importing a function from Python's standard library of functions.
The sleep function can accept decimal inputs as well, so you can pause for as short or as long in your programs as you want.
A slowly disappearing title bar
This time we are going to print out the title bar, but then we are going to print enough output that we start to lose the title bar. Run this code on your own machine to see the full effect:
End of explanation
###highlight=[3,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
from time import sleep
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
# Display a title bar.
print("\t**********************************************")
print("\t***  Greeter - Hello old and new friends!  ***")
print("\t**********************************************")
# Print a bunch of information, in short intervals
names = ['aaron', 'brenda', 'cyrene', 'david', 'eric']
# Print each name 5 times.
for name in names:
    # Clear the screen before listing names.
    os.system('clear')
    
    # Display the title bar.
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    print("\n\n")
    for x in range(0,5):
        print(name.title())
    
    # Pause for 1 second between batches.
    sleep(1)
Explanation: You should have seen the title bar appear, and then groups of names appear every second for a while. At some point, the title bar probably disappeared. Now we are going to modify the code so that the screen is cleared each time through the loop.
End of explanation
###highlight=[8,9,10,11,12,13,14,22]
from time import sleep
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
# Print a bunch of information, in short intervals
names = ['aaron', 'brenda', 'cyrene', 'david', 'eric']
# Print each name 5 times.
for name in names:
    display_title_bar()
    print("\n\n")
    for x in range(0,5):
        print(name.title())
    
    # Pause for 1 second between batches.
    sleep(1)
Explanation: This time you should see the same output, but you should see a steady title bar, and the new information takes the place of the old information instead of being listed below the old output. We have a "running" application!
Reducing repeated code
If you understood the section Introducing Functions, you may have noticed that we have some repeated code in the last program listing. Any time you see a significant amount of repetition, you can probably introduce a function.
The repeated code in this example involves displaying the title bar. Let's write a function to show the title bar.
End of explanation
###highlight=[9,20]
from time import sleep
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
### MAIN PROGRAM ###    
# Print a bunch of information, in short intervals
names = ['aaron', 'brenda', 'cyrene', 'david', 'eric']
# Print each name 5 times.
for name in names:
    display_title_bar()
    print("\n\n")
    for x in range(0,5):
        print(name.title())
    
    # Pause for 1 second between batches.
    sleep(1)
Explanation: Again, you really need to copy this code onto your own machine and run it locally to see this in action. You should see the same behavior as before.
It's interesting to note that having good comments makes writing functions easier. The comment just before the code for displaying the title bar was "Display the title bar." This practically gives us a name for the function that will take over this job: display_title_bar. If we use short, descriptive function names that tell us exactly what the function does, it becomes much easier to follow what is happening in the program. We can see that we don't even need a comment when the function is called, because the function name itself is so informative. The name display_title_bar is much better than something like title, although you don't want to go overboard with a name such as clear_screen_and_display_title_bar.
This code gets a bit hard to read overall though, because we have several sections of code. You can use comments to visually break up your programs. Here's what that can look like in our current program:
End of explanation
###highlight=[2,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
choice = ''
while choice != 'q':    
    display_title_bar()
    
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    choice = input("What would you like to do? ")
    
    # Respond to the user's choice.
    if choice == '1':
        print("\nHere are the people I know.\n")
    elif choice == '2':
        print("\nI can't wait to meet this person!\n")
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: If this is more appealing visually to you, feel free to use these kind of "section header" comments in your longer programs.
top
Building Greeter
Let's continue building Greeter. There are a couple more things we will introduce, but you should be able to follow everything we do.
We will start with the previous part where we have a persistent title bar, but we will remove the sleep functions. We will begin by offering users the choice to see a list of names, or enter a new name.
End of explanation
###highlight=[23,34]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
choice = ''
display_title_bar()
while choice != 'q':    
    
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    choice = input("What would you like to do? ")
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        print("\nHere are the people I know.\n")
    elif choice == '2':
        print("\nI can't wait to meet this person!\n")
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: If you run this code, you will see that it doesn't quite work. There are no Python errors, but the logic is a little off. We can enter choices, but the call to display_title_bar() at the beginning of the loop clears the screen as soon as the output is printed.
We can fix this by moving the call to display_title_bar(), and putting it in two places. We call display_title_bar() once just before we enter the loop, when the program starts running. But we also call it right after the user makes a choice, and before we respond to that choice:
End of explanation
###highlight=[18,19,20,21,22,23,24,34]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
def get_user_choice():
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    return input("What would you like to do? ")
    
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
choice = ''
display_title_bar()
while choice != 'q':    
    
    choice = get_user_choice()
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        print("\nHere are the people I know.\n")
    elif choice == '2':
        print("\nI can't wait to meet this person!\n")
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: This works, so let's put the menu into a function:
End of explanation
###highlight=[28,29,42,43,45,46,47]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
def get_user_choice():
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    return input("What would you like to do? ")
    
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
names = []
choice = ''
display_title_bar()
while choice != 'q':    
    
    choice = get_user_choice()
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        print("\nHere are the people I know.\n")
        for name in names:
            print(name.title())
    elif choice == '2':
        new_name = input("\nPlease tell me this person's name: ")
        names.append(new_name)
        print("\nI'm so happy to know %s!\n" % new_name.title())
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: Now, let's make it so that the program actually does something.
We will make an empty list to store names.
We will print names from this list in choice 1.
We will get a new name in choice 2.
We will store that new name in the list of names.
End of explanation
###highlight=[26,27,28,29,30,32,33,34,35,36,52,54]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
def get_user_choice():
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    return input("What would you like to do? ")
    
def show_names():
    # Shows the names of everyone who is already in the list.
    print("\nHere are the people I know.\n")
    for name in names:
        print(name.title())
        
def get_new_name():
    # Asks the user for a new name, and stores the name.
    new_name = input("\nPlease tell me this person's name: ")
    names.append(new_name)
    print("\nI'm so happy to know %s!\n" % new_name.title())
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
names = []
choice = ''
display_title_bar()
while choice != 'q':    
    
    choice = get_user_choice()
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        show_names()
    elif choice == '2':
        get_new_name()
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: If you run this program, you will see that it works mostly as its supposed to. But the code in lines 37-50, where we are responding to the user's choice, is starting to get crowded. Let's move the code for choice 1 and choice 2 into separate functions:
End of explanation
###highlight=[36,37,38,39,40]
import os
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
def get_user_choice():
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    return input("What would you like to do? ")
    
def show_names():
    # Shows the names of everyone who is already in the list.
    print("\nHere are the people I know.\n")
    for name in names:
        print(name.title())
        
def get_new_name():
    # Asks the user for a new name, and stores the name if we don't already
    #  know about this person.
    new_name = input("\nPlease tell me this person's name: ")
    if new_name in names:
        print("\n%s is an old friend! Thank you, though." % new_name.title())
    else:
        names.append(new_name)
        print("\nI'm so happy to know %s!\n" % new_name.title())
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
names = []
choice = ''
display_title_bar()
while choice != 'q':    
    
    choice = get_user_choice()
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        show_names()
    elif choice == '2':
        get_new_name()
    elif choice == 'q':
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: This code doesn't behave any differently, but the main program itself is much easier to read. Lines 48-57 are a clean series of if-elif-else statements, each of which has a clear action.
Putting each action into its own function also lets us focus on improving that action. If you look at the function get_new_name(), you might notice that we are storing the name without checking anything about it. Let's put in a simple check to make sure we don't already know about this person.
End of explanation
import pickle
# This program asks the user for some animals, and stores them.
# Make an empty list to store new animals in.
animals = []
# Create a loop that lets users store new animals.
new_animal = ''
while new_animal != 'quit':
    print("\nPlease tell me a new animal to remember.")
    new_animal = input("Enter 'quit' to quit: ")
    if new_animal != 'quit':
        animals.append(new_animal)
# Try to save the animals to the file 'animals.pydata'.
try:
    file_object = open('animals.pydata', 'wb')
    pickle.dump(animals, file_object)
    file_object.close()
    
    print("\nI will remember the following animals: ")
    for animal in animals:
        print(animal)
except Exception as e:
    print(e)
    print("\nI couldn't figure out how to store the animals. Sorry.")
Explanation: This works well. Now the program only stores new names, and names that are already in the list are greeted as old friends.
It's interesting to note that you can run this program through python tutor, and step through each line of the code. It's pretty enlightening to see exactly how the Python interpreter steps through a program like this. You can see all of the jumps from the main program to each of the functions, and the change in flow when the user makes a particular choice. It's informative to see which lines are skipped when certain if tests pass or fail.
There is one last thing we'd like Greeter to do, to consider it a basic terminal app. Let's make it remember the list of names after the program closes. To do this, let's learn about pickling using a simpler example.
top
Basic Pickling
When we "pickle" something in the physical world, we soak it in salt and vinegar so it won't rot. "Pickling" an object in Python packages it up and stores it on disk in a way that we can get it back in its original form later. You don't want to use pickle for imporant data, but it's a good way to get started with storing data after your program closes.
Here is a simple program that asks the user for some input, and then stores the input in a list. The program dumps the list to a file using pickle, and the next time the program runs it loads that data back in. Run this program on your computer, and see if it works for you.
End of explanation
###highlight=[9,10,11,12,13,14]
import pickle
# This program asks the user for some animals, and stores them.
#  It loads animals if they exist.
# Try to load animals. If they don't exist, make an empty list
#  to store new animals in.
try:
    file_object = open('animals.pydata', 'rb')
    animals = pickle.load(file_object)
    file_object.close()
except:
    animals = []
# Show the animals that are stored so far.
if len(animals) > 0:
    print("I know the following animals: ")
    for animal in animals:
        print(animal)
else:
    print("I don't know any animals yet.")
# Create a loop that lets users store new animals.
new_animal = ''
while new_animal != 'quit':
    print("\nPlease tell me a new animal to remember.")
    new_animal = input("Enter 'quit' to quit: ")
    if new_animal != 'quit':
        animals.append(new_animal)
# Try to save the animals to the file 'animals.pydata'.
try:
    file_object = open('animals.pydata', 'wb')
    pickle.dump(animals, file_object)
    file_object.close()
    
    print("\nI will remember the following animals: ")
    for animal in animals:
        print(animal)
except Exception as e:
    print(e)
    print("\nI couldn't figure out how to store the animals. Sorry.")
Explanation: This program uses three new things:
A try-except block.
A try-except block is used when you think a section of code might create an error. If an error occurs in a try block, the program does not end. Instead, program execution drops into the except block.
In this case, we try to open a file to write out a list of animals.
If the file can not be opened for some reason, for example because the program doesn't have permission to create a new file, then the program drops to the except block.
In this case, we print the actual error message and a friendlier message of our own.
Opening and closing files.
Line 33 tries to open the file 'animals.pydata'.
Line 33 tells Python to open the file for writing. The 'b' argument tells Python to write the file in bytes.
If successful, the open file can be used through the file_object variable.
If the file does not yet exist, this line creates the file, in the same directory as the program.
Line 35 closes the file once we are finished working with it.
A call to pickle.dump().
Line 34 'dumps' the list animals into the file that was opened. (It is not dumped in a format that we can read.)
Note: This may work slightly differently in Python 2, and on Windows or Mac. This notebook will be updated to include those specific differences.
When you run this program on your computer, look for the file animals.pydata in the same directory as the program file. If that worked, we need to modify the program so that the next time it runs it loads the data from animals.pydata back in.
We do that with a try-except block at the beginning of the program, which tries to open the file and read the data back into the animals list. If that doesn't work, which will happen when the program is run for the first time or if you delete animals.pydata, we make the same empty list we had before.
End of explanation
###highlight=[43,44,45,46,47,48,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,69,84]
import os
import pickle
# Greeter is a terminal application that greets old friends warmly,
#   and remembers new friends.
### FUNCTIONS ###
def display_title_bar():
    # Clears the terminal screen, and displays a title bar.
    os.system('clear')
              
    print("\t**********************************************")
    print("\t***  Greeter - Hello old and new friends!  ***")
    print("\t**********************************************")
    
def get_user_choice():
    # Let users know what they can do.
    print("\n[1] See a list of friends.")
    print("[2] Tell me about someone new.")
    print("[q] Quit.")
    
    return input("What would you like to do? ")
    
def show_names():
    # Shows the names of everyone who is already in the list.
    print("\nHere are the people I know.\n")
    for name in names:
        print(name.title())
        
def get_new_name():
    # Asks the user for a new name, and stores the name if we don't already
    #  know about this person.
    new_name = input("\nPlease tell me this person's name: ")
    if new_name in names:
        print("\n%s is an old friend! Thank you, though." % new_name.title())
    else:
        names.append(new_name)
        print("\nI'm so happy to know %s!\n" % new_name.title())
        
def load_names():
    # This function loads names from a file, and puts them in the list 'names'.
    #  If the file doesn't exist, it creates an empty list.
    try:
        file_object = open('names.pydata', 'rb')
        names = pickle.load(file_object)
        file_object.close()
        return names
    except Exception as e:
        print(e)
        return []
        
def quit():
    # This function dumps the names into a file, and prints a quit message.
    try:
        file_object = open('names.pydata', 'wb')
        pickle.dump(names, file_object)
        file_object.close()
        print("\nThanks for playing. I will remember these good friends.")
    except Exception as e:
        print("\nThanks for playing. I won't be able to remember these names.")
        print(e)
        
### MAIN PROGRAM ###
# Set up a loop where users can choose what they'd like to do.
names = load_names()
choice = ''
display_title_bar()
while choice != 'q':    
    
    choice = get_user_choice()
    
    # Respond to the user's choice.
    display_title_bar()
    if choice == '1':
        show_names()
    elif choice == '2':
        get_new_name()
    elif choice == 'q':
        quit()
        print("\nThanks for playing. Bye.")
    else:
        print("\nI didn't understand that choice.\n")
Explanation: The new try-except block at the beginning of the file works like this:
    - It tries to open a file to read in a list of animals.
    - If the file exists, animals will contain the previously stored list.
    - If the file does not exist, line 9 will create an error, which would normally end the program.
    - Instead, the program drops to the except block, where an empty list is created.
Now the program should just build a cumulative list of animals every time it is run. This is our first example of persistent data, data that lasts even after our program stops running.
Now let's use these concepts to finish Greeter.
top
<a id="Exercises-pickling"></a>
Exercises
Pickling Games
Write a program that lets users enter a number of different games.
Save the games to disk, using pickle, before the program closes.
Load the games from the saved file at the beginning of your program.
top
Pickling in Greeter
We really just have a little left to do in order to finish Greeter. We need to dump the list of names before the program ends, and we need to load that list of names when the program starts. Let's do this by creating two new functions:
The function load_names() will load the names from a file when the program first starts. This function will be called before the main loop begins.
The function quit() will dump the names into a file just before the program ends.
End of explanation
<END_TASK>