Why do my python dictionaries keep overwriting - python

What I am trying to do is create a dictionary within a dictionary. It is supposed to be a movie lover's club in which you can add movies to a member's account, but when I try to add it, it gets overwritten.
Below is my code:
import sys
movies = {}
def option_one():
print('Club Members')
print('=' * 12)
for name in movies:
print(name)
application()
def option_two():
name = input('Please enter the user\'s name: ')
for movie in movies[name]:
title = movies[name][movie]
watch = movies[name][movie]['Watched']
rate = movies[name][movie]['Rating']
print('Movie', 'Rating', 'Watched', sep=' ' * 5)
print('=' * 30)
print(movie, movies[name][movie]['Rating'], movies[name][movie]['Watched'], sep=' ' * 8)
application()
def option_three():
name = input('Please enter the member\'s name: ')
if name in movies:
movie = input('Please enter the name of the movie: ')
movies[name][movie]['Watched'] = movies[name][movie]['Watched'] + 1
for movie in movies[name]:
if movie not in movies[name][movie]:
print('Movie not found. ')
else:
print('Times watched incremented. ')
else:
print('Sorry, member not found. ')
application()
def option_four():
name = input('Please enter the member\'s name: ')
# if the name exists in movies add the movie
if name in movies:
# enter information and update dictionary
movie_title = input('Enter movie name: ')
times_watched = int(input('Enter times watched: '))
rating = input('Enter rating: ')
add_movie = {name: {movie_title: {'Watched': times_watched,
'Rating': rating}}}
movies.update(add_movie)
print('Movie added')
# if name not in movies print member not found call option 4 again
else:
print('Member not found')
option_four()
application()
def option_five():
name = input('Enter new member name: ')
nameDict = {name: ''}
# update the movies dictionary with name dictionary as key
movies.update(nameDict)
print('Member added')
application()
def application():
print('=' * 33)
print('Movie Lover\'s club')
print('=' * 33)
print('1. Display all club_members.')
print('2. Display all movie information for a member.')
print('3. Increment the times a specific movie was watched by a member.')
print('4. Add a movie for a member.')
print('5. Add a new member.')
print('6. Quit')
print('=' * 33)
# get name input for selection
name_selection = (input('Please enter a selection: '))
# if statement directing name choice to corresponding method
if name_selection == '1':
option_one()
if name_selection == '2':
option_two()
if name_selection == '3':
option_three()
if name_selection == '4':
option_four()
if name_selection == '5':
option_five()
if name_selection == 'Q':
print('=' * 33)
print('Thank you for using Movie Lover\'s Club')
print('=' * 33)
sys.exit()
else:
input('Pick a number between 1 and 5 or Q to exit program. Press enter to continue.')
application()
The code above is working as expected but it will not add movie titles only overwrite them. Any help is very much appreciated.

Edit2: With your updated code, here's the solution to your problem. You were actually really close, the only issue was that you were using .update on the movies dictionary, rather than the movies[name] dictionary, so you would replace movies[name] with your new movie dict each time. The solution here is to update movies[name] instead. Also, I made a change to your option_five function so that when you add a new member, they have an empty dictionary by default rather than an empty string, so it can be updated:
def option_four():
name = input('Please enter the member\'s name: ')
# if the name exists in movies add the movie
if name in movies:
# enter information and update dictionary
movie_title = input('Enter movie name: ')
times_watched = int(input('Enter times watched: '))
rating = input('Enter rating: ')
# notice how I got rid of {name: ...} and instead only used the movie
new_movie = {movie_title: {'Watched': times_watched, 'Rating': rating}}
# now update the user's movie dict rather than the entire movies dict
movies[name].update(new_movie)
# if name not in movies print member not found call option 4 again
else:
print('Member not found')
option_four()
application()
def option_five():
name = input('Enter new member name: ')
nameDict = {name: {}} # notice that I replaced '' with {}
# update the movies dictionary with name dictionary as key
movies.update(nameDict)
print('Member added')
application()
Now you can add movies for a user at will without overwriting

The reason it gets overwritten is because you overwrite a member's list every time you would like to add a new movie. Specifically, when you execute:
add_title = movies[name] = {movie_title: {'Watched': '', 'Rating': ''}}
movie[name] now only contains {movie_title: {'Watched': '', 'Rating': ''}}
Here is a new version of your code:
def option_four():
name = input('Please enter the member\'s name: ')
# enter information
movie_title = input('Enter movie name: ')
times_watched = int(input('Enter times watched: '))
rating = input('Enter rating: ')
if name not in movies:
movies[name] = {}
#create the movie title value dictionary make 'movie_title input the name of dict
movies[name][movie_title] = {'Watched': '', 'Rating': ''}
#add watched and rating values to the movie_title dict
movies[name][movie_title]['Watched'] = times_watched
movies[name][movie_title]['Rating'] = rating

Related

Any idea why this code doesn't work as intended?

This is my first python code. The code is supposed to prompt user with options and then perform actions based on the user input.
However, when I run the code, instead of prompting for the menu I get the prompt to enter the movie title. Here's the code I have written so far.
# code starts here
MENU_PROMPT = "\nEnter 'a' to add a movie, 'l' to see your movies, 'f' to find your movie or 'q' to quit: "
movies = []
def add_movie():
title = input("Enter the movie title: ")
director = input("Enter the movie director: ")
year = input("Enter the movie year: ")
movies.append({
'title': title,
'director': director,
'year': year
})
def show_movies():
for movie in movies:
print_movie(movie)
def print_movie(movie):
print(f"Title : {movie['title']}")
print(f"Director : {movie['director']}")
print(f"Release Year : {movie['year']}")
def find_movie():
search_title = input("Enter movie title you are looking for: ")
for movie in movies:
if movie["title"] == search_title:
print_movie(movie)
user_options = {
"a" : add_movie(),
"l" : show_movies(),
"f" : find_movie()
}
def menu():
selection = input(MENU_PROMPT)
while selection != "q":
if selection in user_options:
selected_function = user_options[selection]
selected_function()
else:
print('Unknown command, Please try again')
selection = input(MENU_PROMPT)
menu()
#code ends here
When you create a dictionary with a value being a function, it will run that function to fill in the value of the dictionary. So that is why it is running add_movie() first before anything else.
The proper way to do your menu would be like this:
>>> def x():
... print("hi")
...
>>> y = {'a':x}
>>> y['a']()
hi
We save the value of the dictionary as the function name, then call it by adding the () to the returned value.

how do we grab a specific information like the name from this?

I'm looking at this example and I want to figure out how can I search up a name instead of the ID, then display all the information for the name? For example if it has the ID of 1, name: Bob, department: sales, and job title: manager. If we search up "Bob", everything will display. Sorry this is long.
class Employee:
def __init__(self, name, ID, department, job_title):
self.__name = name
self.__ID = ID
self.__dept = department
self.__job = job_title
def set_name(self, name):
self.__name = name
def set_department(self, department):
self.__dept = department
def set_job_title(self, job_title):
self.__job = job_title
def get_name(self):
return self.__name
def get_ID_number(self):
return self.__ID
def get_department(self):
return self.__dept
def get_job_title(self):
return self.__job
def __str__(self):
return 'Name: ' + self.__name + '\n' + \
'ID Number: ' + str(self.__ID) + '\n' + \
'Department: ' + self.__dept + '\n' + \
'Job Title: ' + self.__job
import pickle
def pickle_it(employees):
# Open file in binary write mode
output_file = open('employees.dat', 'wb')
# Write the data to the file
pickle.dump(employees, output_file)
# Close the file
output_file.close()
def unpickle_it():
try:
# Attempt to open file in binary read mode
input_file = open('employees.dat', 'rb')
except IOError:
# If the file doesn't exist, then create it by opening using write
# mode. Then just close and reopen in binary read mode.
file = open('employees.dat', 'wb')
file.close()
input_file = open('employees.dat', 'rb')
# Load the employees dictionary or create an empty dictionary if file is
# empty
try:
employees = pickle.load(input_file)
except:
employees = {}
# Close the file
input_file.close()
# Return the employees dictionary
return employees
import menu_choices
import save_load_dict
# Global constants for menu choices
LOOK_UP = 1
ADD = 2
CHANGE = 3
DELETE = 4
QUIT = 5
def main():
employees = save_load_dict.unpickle_it()
choice = menu_choices.get_menu_choice()
while choice != QUIT:
if choice == LOOK_UP:
menu_choices.look_up(employees)
elif choice == ADD:
menu_choices.add(employees)
elif choice == CHANGE:
menu_choices.change(employees)
elif choice == DELETE:
menu_choices.delete(employees)
choice = menu_choices.get_menu_choice()
save_load_dict.pickle_it(employees)
main()
import employee_class
# Global constants for menu choices
LOOK_UP = 1
ADD = 2
CHANGE = 3
DELETE = 4
QUIT = 5
def get_menu_choice():
print('\n\033[4m' + 'Employee Directory' + '\033[0m')
print('1. Look up an employee')
print('2. Add a new employee')
print('3. Edit an employee\'s information')
print('4. Delete an employee')
print('5. Quit\n')
# Get the user's choice.
choice = int(input('Enter your choice: '))
# Validate the choice.
while choice < LOOK_UP or choice > QUIT:
choice = int(input('Enter a valid choice: '))
# return the user's choice.
return choice
# The look_up function looks up an employee and displays their information.
def look_up(employees):
# Get a name to look up.
ID = input('Enter an employee ID number: ')
# Look it up in the dictionary.
if ID in employees:
print(employees[ID])
else:
print('That ID number is not found.')
# The add function adds a new entry into the dictionary.
def add(employees):
# Get employee information.
name = input('Enter the employee\'s name: ')
ID = input('Enter the employee\'s ID number: ')
department = input('Enter the employee\'s department: ')
job_title = input('Enter the employee\'s job title: ')
# If the name does not exist, add it.
if ID not in employees:
employees[ID] = employee_class.Employee(name, ID, department, \
job_title)
else:
print('An entry with that ID number already exists.')
Your question heading asks for how to search using email while the class Employee has no email attribute.
To search using other attribute like Name:
Though the code snippets you pasted doesn't define what employees object is, it's a dict mapping between id and corresponding Employee object.
If you only need to search by name, you can make the employees dictionary as a mapping between Name and Employee objects (list, as multiple employee can have same name).
If you need a more dynamic solution that lets you search by just about anything, then you need to match with all attributes of each Employee object. And also will need to take care of case insensitivity in search.
def look_up(employees):
# Get any searchtext to lookup
searchtext = input('Enter search query to lookup')
matches = [emp for emp in employees.values()
if searchtext.lower() in [
emp.get_name().lower(),
emp.get_ID_number(), # Add .lower() if needed
emp.get_department().lower(), #.lower() for case insensitive match
emp.get_job_title().lower()
]
]
if not matches:
print(f'No employee matches any attribute for searchtext {searchtext}')
return None
# If there are valid matches
print(matches)
Eliminate any of the above fields if not needed.
You can go more crazier in terms of matching the string with partial matches like doing searchtext in candidate for candidate in [emp.<some_attributes>,..] or use levenshtein distance.
You'll need to take into account that two employees could have the same name. The following code (adapted from your existing look_up function) will return all the employees with the name specified, or a message that there are no employees with that name :
# The look_up function looks up an employee by name and displays their information.
def look_up_by_name(employees):
# Get a name to look up.
name = input('Enter an employee Name: ')
matches = [emp for emp in employees if emp['name'] == name]
if len(matches) == 0:
print('No employees with name "{}" found'.format(name))
else:
for m in matches:
print(m)

Updating a list in a Python class

I want to update a list to include new items added by a user. There are a few conditions such as the code must be 7 digits long. If the code already exists, the system will notify the user. If the user tries to add another copy of 'up' with a different code, the system will not allow it. It will make them try again as the code must be the same. Eventually I will include a video number, so if there are two copies of 'up' they will have two different video numbers but the same video code.
Can someone show me why the following code is not working for me?
all_movies = []
class Movie(object):
movie_list = []
def __init__(self, code, title, director):
self.code = code
self.title = title
self.director = director
Movie.movie_list.append(self)
#staticmethod
def add_movie():
mv_code = input("Code of movie: ")
movie_code = int(mv_code)
movie_title = input("Name of movie: ")
movie_director = input("Director: ")
if len(mv_code) == 7:
all_movies.append(Movie(movie_code, movie_title, movie_director))
print("movie added to database")
else:
print("the code must be 7 digits long, add movie again.")
def check_validity(movie_code, all_movies):
if movie_code in all_movies:
return True
else:
return False
if check_validity(movie_code, all_movies):
all_movies[all_movies] += Movie
print()
print("updated")
else:
all_movies[movie_code] = [movie_code, movie_title, movie_director]
def main():
movie1 = Movie(1122334, 'Up', 'Director')
movie2 = Movie(1231235, 'Taxi Driver', 'Film-maker')
This is the error message that I am receiving:
all_movies[movie_code] = [movie_code, movie_title, movie_director]
IndexError: list assignment index out of range
First of all this structure is not suitable for your desires.
About the error you got, I should say that you have to define you all movies as a dictionary not a list (because of the that you want to use for each movie).
try this:
all_movies = {}
in you add_movie method:
#staticmethod
def add_movie():
mv_code = input("Code of movie: ")
movie_code = int(mv_code)
movie_title = input("Name of movie: ")
movie_director = input("Director: ")
if len(mv_code) == 7:
if movie_code in all_movies.keys():
print("the movie already exists")
# what do you want to happen here ?
else:
all_movies[movie_code] = (movie_code, movie_title, movie_director)
print("movie added to database")
else:
print("the code must be 7 digits long, add movie again.")
This will add a movie to the all_movies and you don't need the rest your code, and i didn't understand the usage of init and movie_list.
Try this, then tell me what happens if the code already exists in the movies, I will update my answer for you.
UPDATE:
According to your desires in comment the method will updated to something like this:
#staticmethod
def add_movie():
mv_code = input("Code of movie: ")
movie_code = int(mv_code)
movie_title = input("Name of movie: ")
movie_director = input("Director: ")
if len(mv_code) == 7:
if movie_code in all_movies.keys():
print("the movie is already exists, adding it with another video number")
# all_movies[movie_code][-1] is the last video with an existing key
# all_movies[movie_code][-1][-1] last video number generated
new_video_number = all_movies[movie_code][-1][-1] + 1
all_movies[movie_code].append([movie_title, movie_director, new_video_number]) # adding it with new video number
print("movie added to database with new video number")
else:
all_movies[movie_code] = []
all_movies[movie_code].append([movie_title, movie_director, 1]) # 1 is the first movie added(video number)
print("movie added to database")
else:
print("the code must be 7 digits long, add movie again.")
This will returns all_movies like this:
{
'1231235':[
['Taxi Driver', 'Film-maker', 1]
]
'1122334':[
['Up', 'Director',1],
['Up', 'Director',2],
['Up', 'Director',3],
]
'1122333':[
['Another movie', 'Another Director',1],
['Another movie', 'Another Director',2],
]
}
The last element of inner list are the video_numbers that generated automatically by system.

Tying values to keys in a dictionary and then printing

This is a smaller portion of the main code I have been writing. Depending on user selection they can add player informationa and then print the information from the dictionary player roster. I want to store the information and then print in this format but I havent been able to figure out how to do this.
Name ****
Phone Number ****
Jersey Number ****
Im new to dictionaries but I have spent hours reading and searching over the past couple of days about dictionaries and have tried several different ways to do this but failed. I have gotten the closest the way I have it setup now but it still doesnt work right. I feel like I am storing the information incorrectly into the dictionary for starters, any help would be greatly appreciated.
player_roster = {}
def display_roster(self): #Print Roster
if len(player_roster) != 0:
for x in player_roster.keys():
print('Name:', x, 'Phone Number:', player_roster[x])
else: #Print No One on Roster
len(player_roster) == []
print('No names have been entered:')
def add_player(self,): #Enter Members Name
name = input('Enter New Players Name:')
phone_number = input('Enter Players Phone Number:')
jersey_number = int(input('Enter Players Jersey Number'))
player_roster[name] = phone_number, 'Jersey Number', jersey_number
#If I input Toby as Name 444-444 as Phone Number and 3 as Jersey number it outputs like this
Name: Toby Phone Number: ('444-4444', 'Jersey Number', 3)
# I would like it to output like
Name: Toby
Phone Number: 444-4444
Jersey Number: 3
There are some things i would change in your code but to keep this close to what you asked for take a look at this:
def display_roster():
if len(player_roster) != 0:
for x in player_roster.keys():
print('Name:', x)
print('Phone Number:', player_roster[x][0])
print('Jersey Number:', player_roster[x][1])
else:
print('Roster is empty.')
return
player_roster = {}
def add_player():
name = input('Enter New Players Name:\t')
phone_number = input('Enter Players Phone Number:\t')
jersey_number = int(input('Enter Players Jersey Number:\t'))
player_roster[name] = [phone_number, jersey_number]
return
add_player()
display_roster()
# PRINTS:
#Name: Toby
#Phone Number: 444-4444
#Jersey Number: 3
Printing in multiple lines gives you the result you want. As stated in the comments this can also be done with a single print() statement but i do not think compact code makes much difference to you yet.
Further, this len(self.player_roster) == [] line does not make sense. This is as good as simply writing True in a line. The "emptiness" of the team is checked by the else:.
Finally, i would slightly change the way players are stored in the "Roster" dictionary and have it like this: {"Toby": ['444-4444', 3], ...}
I would propose that you replace the print statement to this:
print(" Name: %s \n Phone Number: %s \n Jersey Number: %d") % player_roster[x]
You're pretty much there. The below modification would allow you to print as you need (and is slightly more readable):
class PlayerDictionary():
def __init__(self):
pass
player_roster = {}
def display_roster(self): #Print Roster
if len(self.player_roster) != 0:
for key, value in self.player_roster.iteritems():
print(str(key) + ": " + str(value))
else: #Print No One on Roster
len(self.player_roster) == []
print('No names have been entered:')
def add_player(self,):
self.player_roster['Name'] = input('Enter New Players Name:')
self.player_roster['Phone Number'] = input('Enter Players Phone Number:')
self.player_roster['Jersey Number'] = int(input('Enter Players Jersey Number'))
if __name__ == "__main__":
player = PlayerDictionary()
player.add_player()
player.display_roster()
A slightly more maintainable solution would be to create a class for Player. Set the properties on the object and overload the str function e.g.
class Player(object):
def __init__(self):
self.__name = ""
self.__phone_number = ""
self.__jersey_number = ""
#property
def name(self):
return self.__name
#property
def phone_number(self):
return self.__phone_number
#property
def jersey_number(self):
return self.__jersey_number
#name.setter
def name(self, val):
self.__name = val
#phone_number.setter
def phone_number(self, val):
self.__phone_number = val
#jersey_number.setter
def jersey_number(self, val):
self.__jersey_number = val
def __str__(self):
return ("Name: %s\nPhone Number: %s\nJersey Number: %s" % (str(self.__name), str(self.__phone_number), str(self.__jersey_number)))
if __name__ == "__main__":
player = Player()
player.name = input('Enter New Players Name:')
player.phone_number = input('Enter Players Phone Number:')
player.jersey_number = int(input('Enter Players Jersey Number'))
print(player)

Grouping string input by count

I'm trying to do a question out of my book and it asks:
Implement function names that takes no input and repeatedly asks the
user to enter a student's first name. When the user enters a blank
string, the function should print for every name, the number of
students with that name.
Example usage:
Usage:
names()
Enter next name: Valerie
Enter next name: Bob
Enter next name: Valerie
Enter next name: John
Enter next name: Amelia
Enter next name: Bob
Enter next name:
There is 1 student named Amelia
There are 2 students named Bob
There is 1 student named John
There are 2 students named Valerie
So far I have this code:
def names():
names = []
namecount = {a:name.count(a) for a in names}
while input != (''):
name = input('Enter next name: ')
names = name
if input == ('')
for x in names.split():
print ('There is', x ,'named', names[x])
I'm really lost here and any input would help out tons. Also if possible please explain how to fix my code
There are a lot of issues with namings in your function, you are using such variables like 'names' that is used for function name as well as 'input' that is a python function name for reading user input - so you have to avoid using this. Also you defining a namecount variable as a dict and trying to initialize it before fill. So try to check solution below:
def myFunc():
names = []
name = ''
while True: #bad stuff you can think on your own condition
name = raw_input('press space(or Q) to exit or enter next name: ')
if name.strip() in ('', 'q', 'Q'):
for x in set(names):
print '{0} is mentioned {1} times'.format(x, names.count(x))
break
else:
names.append(name)
myFunc()
OR:
from collections import defaultdict
def myFunc():
names = defaultdict(int)
name = ''
while True: #bad stuff you can think on your own condition
name = raw_input('press space(or Q) to exit or enter next name: ')
if name.strip() in ('', 'q', 'Q'):
for x in set(names):
print '{0} is mentioned {1} times'.format(x, names[x])
break
else:
names[name] += 1
I rewrote your function for you:
def names():
names = {} # Creates an empty dictionary called names
name = 'cabbage' # Creates a variable, name, so when we do our while loop,
# it won't immediately break
# It can be anything really. I just like to use cabbage
while name != '': # While name is not an empty string
name = input('Enter a name! ') # We get an input
if name in names: # Checks to see if the name is already in the dictionary
names[name] += 1 # Adds one to the value
else: # Otherwise
names[name] = 1 # We add a new key/value to the dictionary
del names[''] # Deleted the key '' from the dictionary
for i in names: # For every key in the dictionary
if names[i] > 1: # Checks to see if the value is greater for 1. Just for the grammar :D
print("There are", names[i], "students named", i) # Prints your expected output
else: # This runs if the value is 1
print("There is", names[i], "student named", i) # Prints your expected output
When doing names():
Enter a name! bob
Enter a name! bill
Enter a name! ben
Enter a name! bob
Enter a name! bill
Enter a name! bob
Enter a name!
There are 3 students named bob
There are 2 students named bill
There is 1 student named ben
Let's analyse your code:
def names():
names = []
namecount = {a:name.count(a) for a in names}
while input != (''):
name = input('Enter next name: ')
names = name
if input == ('')
for x in names.split():
print ('There is', x ,'named', names[x])
There seem to be a few problems, let's list them
The while loop's conditional
What you want to do check if input from user is '' (nothing)..
input is a built-in function for getting input from user, so it never will be ('').
The names = name statement
What you want to do is add name to the list names.
Here you are changing names to a string, which isn't what you want.
The if's conditional
same as 1.
The for loop
let's ignore.. just not valid.. here..
We fix these problems as follows(solution has same numbering as problem above that it solves)
Change the conditional to something like name != ''.
Also, before the loop begins, you need to get input once for this to work, which in this case has a bonus, the first input can have a different prompt.
Use names.append(name) to add name to names.
Same as 1.
Just look at the for loop below...
Try this
def names():
names = []
name = input('Enter a name: ').strip() # get first name
while name != '':
names.append(name)
name = raw_input('Enter next name: ').strip() # get next name
for n in set(names): # in a set, no values are repeated
print '%s is mentioned %s times' % (n, names.count(n)) # print output
def names():
counters = {}
while True:
name = input('Enter next name:')
if name == ' ':
break
if name in counters:
counters[name] += 1
else:
counters[name] = 1
for name in counters:
if counters[name] == 1:
print('There is {} student named {}'.format(counters[name],name))
else:
print('There are {} student named {}'.format(counters[name],name))
names()

Categories