Sorry, I have searched and not managed to figure out an answer to this - I know there are lots of threads and questions in relation to it but cannot see an answer. Please redirect me or perhaps suggest a solution! TIA
I have an array of objects.
One (4 actually) of the properties of the objects in this array is another class.
Input taken from the user refers to one of the properties in the array which contains an instance of the other class. I simply want to read that data.
class direction():
dest = -1
lock = ''
class room():
roomname = ''
desc = ''
n = direction()
s = direction()
w = direction()
e = direction()
item = ''
rooms = []
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms.append( room() )
rooms[0].roomname = 'outside'
rooms[0].desc = ''
rooms[0].n.dest = 'bathroom'
rooms[0].item = ''
rooms[1].roomname = 'hall'
rooms[1].desc = 'The hallway has doors to the east and south'
rooms[1].s.dest = 2
rooms[1].e.dest = 3
rooms[1].item = ''
and so on..
Now I take input from the user eg: "go n"
and would like to check/read the 'lock' property from the property that relates to the taken direction in the current room. currentRoom is an integer that relates to the LIST element that it links to.
Please do not criticise my lack of constructors. I am trying to keep the code as simple as possible initially and will introduce those later on.
I take input as follows:
print('Your action:')
move = input('>>>').lower().split()
I use the following line of code to check that the taken direction exists in the current room as follows:
if getattr(rooms[currentRoom], move[1]) != '':
and then want to check the lock property for the given direction in the current room. Something like this... (which does not work)
if rooms[currentRoom].move[1].lock != '':
I hope this is clear enough! Many thanks.
if rooms[currentRoom].move[1].lock != '':
This line of code will not work because move[1] is a string. If you wanted to access the variable in the class you would have to call it in the line of code
if rooms[currentRoom].n.lock != '':
A solution would be to get the value stored in the object then as follows
x = getattr(rooms[currentRoom], move[1]) #getattr() returns direction() object
if x.lock != '': #check lock value in direction() object
I am pretty new to Python and am still figuring out the kinks as I go. I have a program that I've had a lot of assistance with writing that I've been perfecting and am having an issue as I go about debugging it that I cannot seem to resolve on my own so I wanted to see if anyone had any suggestions. When I run the menu() function and then select 'a' which calls the function thankyou() (NOTE: I left the other functions in that aren't throwing the errors but I just put in calls back to the menu() function because it would have become an even longer, cumbersome post with so much code); when I call thankyou() and I enter in either a new or existing name and then get to the point where I've set it up to ask for a donation amount (it is also able to accept 'Q' or 'q' to quit back to menu()) if I enter 'q' and go back to the menu and then proceed back to the thankyou() function and select the name that was entered the first time (whether it was newly created or it existed in the pre-assembled dictionary) once I get back to the donation solicitation section and enter in a numerical entry, I get the following error(s):
Traceback (most recent call last):
File "C:/FILEPATH.py", line 305, in <module>
menu() # Program starts here
File "C:/FILEPATH.py", line 64, in menu
switch_function.get(usr_sel)() # get user entry from dict
File "C:/FILEPATH.py", line 113, in thankyou
list(donor_dict.values())[get_index][1]) # current amt/ var from dict{[val]}
IndexError: list index out of range
I am trying to understand what is happening here so that I can figure out how to account for/prevent it. Does anyone have any ideas on what is causing this to happen and how I can address it? Thanks.
Code:
locale.setlocale(locale.LC_ALL, '')
today = time.strftime("%m/%d/%Y")
spacing = '- ' * 56 # formatting for DONOR header
donor_dict = {'Columns': ['NAMES', 'DONATION AMOUNT', 'NUMBER OF GIFTS', 'AVG. GIFTS'],
'Rudolph Soares': ['Rudolph Soares', 1335, 3, 445], # Donor info
'Josef Mistretta': ['Josef Mistretta', 7500, 4, 1875],
'Joye Agostini': ['Joye Agostini', 600, 2, 300],
'Rachelle Levan': ['Rachelle Levan', 12100, 5, 2420],
'Vena Ussery': ['Vena Ussery', 4000, 8, 500],
'Efrain Lager': ['Efrain Lager', 795, 9, 88.34],
'Mee Heine': ['Mee Heine', 4600, 4, 1150],
'Tanya Essex': ['Tanya Essex', 75000, 2, 37500]}
# ------------------------------------------------- PROCESSING --------------------------------------------------------
def menu():
"""Display menu of options to toggle between to perform separate actions"""
header = "-" * 110 # formatting for header
title = ' ' * 48 + "MAIL ROOM MENU" # title display
directions = "Select one of the three options:" # directions to user for menu
optA = "[A] Send a Thank you" # option(s) for menu
optB = "[B] Create a Report"
optC = "[C] Create Letters for All Donors"
optD = "[D] Quit"
whole_menu_header = header + '\n' + title + '\n' + header # header strung together as one uni
while True:
print(whole_menu_header) # display header
print(directions.center(110, ' '), '\n') # center directions with header display
print(optA + optB.center(37, ' ') + optC.center(36, ' ') + optD.center(25, ' ') + '\n')
switch_function = {
'A': thankyou, # dictionary holding menu options
'B': createreport,
'C': writeletters,
'D': quit_program,
}
try:
usr_sel = (input("Menu Selection: ")).upper() # user input for menu
switch_function.get(usr_sel)() # get user entry from dict
except KeyError:
print("Invalid Entry! Only enter A, B, C, or D.") # display error on any other entry
continue # continue back to start of menu
def thankyou():
"""Function enables user to add to dictionary data (adding new donors and donation amounts as well as
number of donations and average donations for new keys, and also updates existing keys."""
print("Leaving menu...\n")
while True:
print("Enter the name of the person you are writing to (or enter 'list' to see a list of names or Q to quit) ")
fname_prompt = input("First Name: ").strip().capitalize() # first name variable (strip any spaces)
if fname_prompt.upper() == "Q": # if Q, then quit to menu()
menu()
elif fname_prompt.lower() == "list":
displaylist()
else:
lname_prompt = input("Last Name: ").strip().capitalize() # last name variable
if lname_prompt.upper() == "Q": # if Q, back to menu
menu()
elif lname_prompt.lower() == "list": # if list, then list display
displaylist()
else:
key = fname_prompt + " " + lname_prompt
if key in donor_dict.keys():
existing_donor = input(
"That value is already in the list! Do you want to proceed with that selection? (Y/N): ")
if existing_donor.upper() == "Y": # if user proceeds, print display
donation_amt_str = input("Enter in the donation amount from Donor {0}: $".format(key))
if donation_amt_str.lower() == 'q':
menu()
try:
donation_amt = int(donation_amt_str)
except ValueError:
print("Error: invalid entry.\n")
else:
print(
'{0} has donated ${1:,.2f}'.format(key, donation_amt)) # display name and donation amt
int(donation_amt)
get_index = 0 # index variable
for item in range(0, len(donor_dict)): # set index var to current name
if list(donor_dict.values())[item][0] == key:
get_index = item
break
firstname = list(donor_dict.values())[get_index][0].split(' ', ).pop(
0) # separate first name, create variable
current_donations = int(
list(donor_dict.values())[get_index][1]) # current amt/ var from dict{[val]}
sum_donations = current_donations + donation_amt # sum of all donations (current + new)
list(donor_dict.values())[get_index][1] = float(sum_donations) # update sum
num_donations = int(list(donor_dict.values())[get_index][2]) + 1 # num donations = self + 1
list(donor_dict.values())[get_index][2] = num_donations # update num of donations
list(donor_dict.values())[get_index][3] = averagedonations(sum_donations,
num_donations) # update avg
email_display = str(
input("Display Donor Email? (Y/N or Q): ")) # ask user if they want to to
if email_display.upper() == "Y": # write email with name/amount
print(spacing)
print('Dear {0}, \n\nThank you for your continued support through your \
contribution of ${1:,.2f} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n\
Foundation Board of Directors\n'.format(firstname, sum_donations))
print(spacing)
elif email_display.upper() == 'Q':
menu()
else:
continue
else:
add_name = str(input("That name is not in the Donor list. Do you want to add it to the list? (Y/N) "))
if add_name.upper() == "Y": # if input response == "Y", proceed
pair = {key: [key]}
donor_dict.update(pair)
displaylist()
num_donations = 1 # add new item to new name index
donation_amt_str = input("Enter in the donation amount from Donor {0}: $".format(key))
if donation_amt_str.lower() == 'q':
menu()
try:
donation_amt = int(donation_amt_str)
except ValueError:
print("Error: Invalid entry.\n")
else:
print('{0} has donated ${1:,.2f}'.format(key, donation_amt))
get_index = 0 # counter, start at 0
for item in range(0, int(len(list(donor_dict.values())))): # for items in donor_dict
if list(donor_dict.values())[item][0] == key: # if item at[0] == full_name
get_index = item # set index to item
break
# noinspection PyTypeChecker
list(donor_dict.values())[get_index].append(
donation_amt) # append donation amount to end of current lst [don_idx]
# noinspection PyTypeChecker
list(donor_dict.values())[get_index].append(num_donations) # append donation count to end
avg = averagedonations(donation_amt, num_donations)
list(donor_dict.values())[get_index].append(avg) # append average to end of current index
firstname = list(donor_dict.values())[get_index][0].split(' ', ).pop(
0) # separate first name, create variable
email_display = str(input("Display Donor Email? (Y/N): ")) # ask user if they want to
if email_display.upper() == "Y": # print email message
print(spacing) # if Y, then print
print('Dear {0}, \n\nThank you for your continued support through your \
contribution of ${1:,.2f} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n\
Foundation Board of Directors\n'.format(firstname, donation_amt))
print(spacing)
elif email_display.upper() == 'Q':
menu()
else:
continue
def createreport():
"""Function creates organized report of donor information based on current dictionary contents.
Information is sorted in descending order based on total donation amounts."""
print("Leaving menu...")
while True: # continual loop unless user terminates
proceed = str(input("Generate Donor report? (Y/N): ")) # solicit user response to proceed
if proceed.upper() == "Y": # if user indicates yes
input("Generating Donor report... [Press Enter]") # on Enter press, proceed
new_list = list(donor_dict.values())[1:] # blank list to hold only values after headers
new_list.sort(key=lambda sort_on: sort_on[1], reverse=True) # sort list based on donation totals
lst_heading = list(donor_dict.values())[0:1] # container for only header
final_lst = lst_heading + new_list # join sorted list back with header
print(spacing)
print('{:>15s}'.format(str(final_lst[0][0])), end='') # format header for display
print(' |{:>20s}'.format(str(final_lst[0][1])), end='')
print(' |{:>19s}'.format(str(final_lst[0][2])), end='')
print(' |{:>15s}'.format(str(final_lst[0][3])))
print(spacing)
for i in range(1, int(len(final_lst))): # format list contents
print('{:>20s}'.format(str(final_lst[i][0])), end='')
print(' ${:>10,.2f}{:>17}'.format(float(final_lst[i][1]), int(final_lst[i][2])), end='')
print(' ${:>10,.2f}'.format(float(final_lst[i][3])))
else:
back_to_menu = str(input("Do you want to quit back to the main menu? (Y/N): ")) # escape sequence
if back_to_menu.upper() == "Y":
input("Quitting... [Press Enter]")
menu()
else:
continue # if no esc, then continue loop
def writeletters():
"""Function writes donor letter to file in user-directed file path"""
print("Leaving menu...")
names_list = [] # empty list to hold list of donor_dict names w/o whitespace (for filenames)
first_names = [] # first names separated out to be used for letters
default = os.getcwd() # get and assign current directory to variable
default = default + "\\" # format default so that it will be accepted (will work with Windows)
while True:
msg = input("Proceed to write letters to all donors in donor list? (Y/N) ") # if user selects Y, proceed
if msg.upper() == "Y": # check input
try:
working_directory = str(input('\nEnter the file path where you want to write the letters - '
'don\'t forget to use ''two \n\'\\\\\' as file separators to make sure'
' it is compatible if using Windows - (e.g. \'C:\\\\\': '))
except Exception as e: # exception handler - prints line of error, and type
print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
# working directory variable assignment by user - if blank, use default
if working_directory == "": # check for input on working_directory
working_directory = default
for x in range(int(len(donor_dict))): # for items in the span of donor_dict
firstname = list(donor_dict.values())[x][0] # firstname = donor_dict at index[item], column[0]
firstname = firstname.split(' ', ).pop(0) # format var to split on whitespace (only first name)
first_names.append(firstname) # append this value to empty list first_names
for i in range(int(len(list(donor_dict.values())))): # for items in the span of donor_dict
elem = list(donor_dict.values())[i][0] # elem = donor_dict at index[i], column[0]
elem = elem.replace(" ", "") # format name w/o whitespace
names_list.append(elem) # append to name_list
for names in range(1, int(len(names_list))): # omit header (range 0), for each name in names_list[]
try:
with open(working_directory + str(names_list[names]) + '.txt',
'a') as filename: # create files/file-names
filename.write(today) # write current date (mm/dd/yy)
filename.write('\n\nDear {0}, \n\nThank you for your continued support through your contribution '
'of {1} towards our Foundation\'s fundraising goal.\n\nBest wishes,\n'
'Foundation Board of Directors'
'\n'.format(str(first_names[names]),
locale.currency(list(donor_dict.values())[names][1], grouping=True)))
except Exception as e: # exception handler - prints line of error, and type
print('Error on line {}'.format(sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
# print letter message (first name and donation amount)
print("Files being written to " + working_directory + "...")
print("Done!") # message to user advising where files are going, and when it is done
elif msg.upper() == "N": # if user selected "N" for msg = input()
input("Exiting back to menu [Press ENTER]") # message to user, leaving this function
break # break out of while-loop - back to menu()
else:
print("That's an unrecognized value! Only Y or N are accepted.")
continue # invalid input, warning message: back to beginning of function
def quit_program():
"""Function quits all processes"""
input("Exiting Program...[Press ENTER]") # I use PyCharm and exit() w/o import worked fine but
from sys import exit # iPython was not running exit() without importing it from sys
exit() # so to avoid issues, I just kept this here
def displaylist():
"""Function returns current dictionary contents (names only)"""
cut_off = int(len(list(donor_dict.values())) / 2) # where list breaks for next line
if int(len(list(donor_dict.values()))) - 1 % 2 != 0: # even/odd check
for i in range(0, int(len(list(donor_dict.values())) - int(len(list(donor_dict.values())) - 2) / 2)):
if i == 0: # header check
print(spacing)
print('{:>44s}'.format(str(list(donor_dict.values())[i][0]))) # print Donor Name header
print(spacing)
elif cut_off + i >= len(list(donor_dict.values())): # if cut_off + i exceeds len(list)
print('{:>30s}'.format(list(donor_dict.values())[i][0])) # only print i (not cut_off + i)
continue
else:
print('{:>30s}'.format(list(donor_dict.values())[i][0]),
'{:>35s}'.format(list(donor_dict.values())[cut_off + i][0]))
else:
for i in range(0, int(len(list(donor_dict.values())) / 2)):
if i == 0: # header check
print(spacing)
print('{:>44s}'.format(str(list(donor_dict.values())[i][0]))) # print Donor Name header
print(spacing)
else:
print('{:>30s}'.format(list(donor_dict.values())[i][0]),
'{:>35s}'.format(list(donor_dict.values())[cut_off + i][0]))
print()
def averagedonations(donations, num):
"""Returns average of donor's gifts"""
sumgifts = donations
numgifts = num
average_donation = sumgifts / numgifts
return average_donation
# -------------------------------------------------- DISPLAY ----------------------------------------------------------
menu() # Program starts here
This error actually happens only when you enter a new donor name. When the user enters a new donor name and then press q to abort the donation, you already initialize the new donor entry with just pair = {key: [key]}, when in fact each entry is expected to have 4 items in the list, not just the person's name.
So when the user enters the same name next time and proceeds to enter a donation amount, your code at current_donations = int((donor_dict.values())[get_index][1]) cannot find the second item in the list for that donor, which is supposed to be the amount of the current donation.
To fix this, you simply have to change pair = {key: [key]} to pair = {key: [key, 0, 0, 0]} to properly initialize the list for the new entry.
The purpose of this program is to create a list of names for people attending a party. I would like to be able to grant the user the ability to continue adding names until they chose YES as an option to exit the loop. However, I have am stomped when it comes to having them enter a name they would like to remove in case they added someone by accident or if they would like to edit the list and remove or replace someone.
I am currently a newbie to programming, hence the lack of classes to this code. Any help would be greatly appreciated. Thank you all in advance!
#Initialize empty list
partyList = []
#Initilize empty entry
inviteeName = ''
endEntry = ''
#Run loop until YES is entered as a value
while endEntry != "Yes":
inviteeName = input("Please enter the name of the person you are inviting below." + "\nName: ")
inviteeName = inviteeName.title()
# Verifies if a name was not entered.
while inviteeName == "":
inviteeName = input("\nPlease enter the name of the person you are inviting below." + "\nName: ")
inviteeName = inviteeName.title()
endEntry = input("\tPress ENTER to continue or type Yes to finish: ")
endEntry = endEntry.title()
#Append every new name to the list
partyList.append(inviteeName)
#Adds the word "and" to finish sentence if there are more than one invitees. NOTE: Make a class please!
numOfInvitees = len(partyList)
if numOfInvitees > 1:
partyList.insert(-1, 'and')
#Remove brackets and quotes.
partyList = ', '.join(partyList)
#Print message
print("\nThis will be your final message:\n" + str(partyList) + "\nYou are invited to my party!\n")
I was trying to use this to assist the user with removing names entered by accident.
submit = input('Submit?: '.title())
submit = submit.title()
if submit == 'Yes':
print('Invite has been sent!')
elif submit == 'No':
remNameConfirmation = input('Would you like to remove a name from the list?: ')
remNameConfirmation = remNameConfirmation.title()
if remNameConfirmation == 'Yes':
uninviteName = (input('Who would you like to remove?: '))
uninviteName = uninviteName.title()
Here is the line that is giving some trouble
partyList.remove(uninviteName)
print(partyList)
When your code reaches
partyList = ', '.join(partyList)
it will set the variable partyList to a string. Since it is no longer a list it does not have the .remove method.
I have a program that maintains a flat file database of cd information. I am trying to write a function that updates the database. In this function I am checking to see if the artist exists and if so, appending the album name to this artist, but for some reason it will not see that the artist I type in already exists. I made sure that I type it in exactly like it is in the dictionary but for some reason python will not see that it is there. Why would this be happening? I have included sample input as well as the python program. Any help would be greatly appreciated.
import sys
def add(data, block):
artist = block[0]
album = block[1]
songs = block[2:]
if artist in data:
data[artist][album] = songs
else:
data[artist] = {album: songs}
return data
def parseData():
global data
file='testdata.txt'
data = {}
with open(file) as f:
block = []
for line in f:
line = line.strip()
if line == '':
data = add(data, block)
block = []
else:
block.append(line)
data = add(data, block)
return data
def artistQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
artists=sorted(data.keys())
for i in range(0,len(artists)) :
print str(i+1) + " : " + artists[i]
usrChoiceArt = raw_input("Please choose an artist or enter q to quit:")
if usrChoiceArt=='q' :
print "Quitting Now"
exit()
else :
albumQry()
def albumQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
usrArtist=artists[int(usrChoiceArt)-1]
albums=sorted(data[usrArtist].keys())
for i in range(0,len(albums)) :
print str(i+1) + " : " + albums[i]
usrChoiceAlb=raw_input("Please choose an album or enter a to go back:")
if usrChoiceAlb=="a":
artistQry()
else:
trackQry()
def trackQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
usrAlbum=albums[int(usrChoiceAlb)-1]
tracks=data[usrArtist][usrAlbum]
for i in range(0,len(tracks)) :
print tracks[i]
usrChoiceTrack=raw_input("Enter \"a\" to go back or \"q\" to quit:")
if usrChoiceAlb=="q":
print "Quitting Now"
exit()
elif usrChoiceTrack=="a":
albumQry()
else:
print "Invalid Choice"
trackQry()
def artistExist(Name):
for i in range(0,len(data.keys())):
if Name==data.keys()[i]:
return True
else:
return False
def updData():
artistName=raw_input("Please enter an artist name:")
albumName=raw_input("Please enter an album name:")
trackList=raw_input("Please enter the track list seperated by comma's:")
if artistExist(artistName):
data[artistName].append(albumName)
print data[artistName]
elif not artistExist(artistName):
print "Quitting"
exit()
if __name__ == '__main__':
data = parseData()
if sys.argv[1]=='-l':
artistQry()
elif sys.argv[1]=='-a':
updData()
Input data:
Bob Dylan
1966 Blonde on Blonde
-Rainy Day Women #12 & 35
-Pledging My Time
-Visions of Johanna
-One of Us Must Know (Sooner or Later)
-I Want You
-Stuck Inside of Mobile with the Memphis Blues Again
-Leopard-Skin Pill-Box Hat
-Just Like a Woman
-Most Likely You Go Your Way (And I'll Go Mine)
-Temporary Like Achilles
-Absolutely Sweet Marie
-4th Time Around
-Obviously 5 Believers
-Sad Eyed Lady of the Lowlands
In your function artistExist, you return False on the very first iteration! Instead, you must wait until all iterations are finished.
for i in range(0,len(data.keys())):
if Name==data.keys()[i]:
return True
return False
In addition to what Padraic Cunningham says below, the elif here is also redundant:
if artistExist(artistName):
...
elif not artistExist(artistName):
...
If something isn't True, then it can only be False. So really you should just have
if artistExist(artistName):
...
else:
...
And since the function is just a needless one-liner, an even better expression is
if artistName in data:
...
else:
...
Apart from returning too early by returning False in the loop you are doing way too much work, you simply need to use return Name in data:
def artistExist(Name):
return Name in data # will return True or False with O(1) lookup
Every time you call .keys you are creating a list in python2 so your lookup is actually quadratic in the worst case as opposed to 0(1) with the simple return Name in data. A big part of using a dict is efficient lookups which you lose calling .keys. If you actually wanted to iterate over the keys you would simply for key in data, no call to .keys and no need for range.
I am trying to make it so users can create text art and name then to their liking and then when they go onto the Art list they can see their art's name and show it. At the moment I have this:
#
#Text Art Thing
#15/05/2015
#By Dom
while True:
UserInput = input("##################################################\n1 - Create new art\n2 - Manage saved art\n3 - Watch a slideshow of all the art\n##################################################\n\n")
Art = []
def NewArt():
stop = False
x = input("What would you like to call your art? ")
vars()[x] = []
ln = 1
while stop == False :
inputln = input("" + str(ln) + ") ")
if inputln == "end" :
stop = True
print("You have exited the editor. Your art is shown below!\n##################################################\n")
print("\n".join(vars()[x]))
print("\n##################################################\n")
Art.append(vars()[x])
ln += 1
vars()[x].append(inputln)
if UserInput == "1" :
print("Loading...")
NewArt()
if UserInput == "2" :
print("Loading...")
SavedArt()
if UserInput == "3" :
print("Loading...")
SlideArt()
This can create multiple art fine but I only get this then I type in art:
[['Cat1', 'Cat2', 'end']]
The name does not show typing Cat only gets a error.
Hope you can help.
You can store all art in a Python dict, relating each "image" (ASCII art string) to a name.
Example:
art = {}
# ...
x = input("What would you like to call your art? ")
art[x] = []
while stop == False :
# ...
art[x].append(inputln)