How to edit strings in a list - python-3.x

What I want is this - I have a list of names created from user input. now i have to come up with a way for the user to edit a name by entering the name that they what to edit and then obviously edit it into what they want and store it in the list.
if it helps heres everything I have so far. def edit() is where im struggling.
def mainMenu():
print("\nMAIN MENU")
print("1. Display Members:")
print("2. Add A Member(s):")
print("3. Remove A Member:")
print("4. Edit Member:")
print("5. Exit:")
selection = int(input("\nEnter Choice: "))
if selection == 1:
display()
elif selection == 2:
add()
elif selection == 3:
remove()
elif selection == 4:
edit()
elif selection == 5:
exit()
else:
print("Invalid choice, enter 1-5.")
mainMenu()
def display():
#displaying roster...
print(roster)
mainMenu()
def add():
#adding team members...
size = int(input("How many players are you adding?"))
global roster
roster = [0] * size
for i in range(size):
roster[i] = input("Enter members name: ")
roster.append(roster)
mainMenu()
def remove():
#removing a team member...
roster.remove(input("Enter member to be removed: "))
mainMenu()
def edit():
#edit a team member...
roster.insert(input("Enter Name to be edited: "))
mainMenu()
mainMenu()

Removing and adding elements are pretty easy in python because they are directly supported by the language. Each of them can be translated into only one instruction.
When something doesn't seem very obvious, such as the editing functionality you are trying to implement, try breaking it down to things that can be expressed as a simple operation that holds one one line (even if not in order).
To find the answer I thought this: somewhere in my code, I want to type roster[ind_name_to_edit] = new_name.
I knew then that before typing this, I would want to find the value of ind_name_to_edit. This can be done by roster.index(name_to_edit). And you already know how to get the name to be edited and the name to edit ;)
If you're still unsure how to do what you want to do, re-read this answer and see the documentation of the index method of list in python3 and maybe some examples here.
N.B: If your list is supposed to be sorted in some way, you should implement your own search algorithm instead of using index, and you should consider re-sorting the list after the edit. I know it's a long shot but just in case.

Related

NameError: free variable 'addcontact' referenced before assignment in enclosing scope

please be kind with my n00b question but it is driving me crazy and googling it didn't help much unfortunately.
I am trying to write a simple phonebook script using an empty dictionary as a learning exercise but as I am self taught there is no one else to turn to.
So here's what's happening,
I want to write a menu function that includes subfunctions for adding, deleting and editing {name:number} contacts
it is mostly working except for when I try to call the add function from within the edit
this is part of the menu code including the add routine
def menu():
selection = (int(input("""1:View phonebook
2:Add contact
3:Delete contact
4:Search for a contact and if necessary edit it
5:Save and Exit
What would you like to to?""")))
if selection == 1:
if len(phonebook)== 0:
print("Phonebook is empty, please add a contact first.")
loop = input("Press Enter to continue ...")
menu()
else:
print(phonebook)
loop = input("Press Enter to continue ...")
menu()
elif selection == 2:
def addcontact():
first = (str(input("First name: ")))
last = (str(input("Last name: ")))
num = (str(input("Number? ")))
phonebook.update({last + " " + first: num})
loop = input("Contact saved, press Enter to continue.")
menu()
(other stuff...)
menu()
and this is the update subroutine that's giving me trouble
elif selection == 4:
def search_and_edit():
search = (str(input("Please type the exact name of the contact you are looking for: ")))
if search in phonebook.keys():
print("Name: ", search, "Number: ", phonebook[search])
edit = (str(input("Do you wish to edit this contact? Y/N")))
if edit == "N" or edit == "n":
menu()
if edit == "Y" or edit == "y":
phonebook.pop(search)
addcontact()
else:
print("Contact not found.")
loop = input("Press Enter to continue.")
menu()
and this is the error message from PyCharm
File "C:\Users\Derek\PycharmProjects\pythonProject\phonebook\phonebook.py", line 78, in search_and_edit
addcontact()
NameError: free variable 'addcontact' referenced before assignment in enclosing scope
Process finished with exit code 1
what am I doing wrong here? the other callbacks work fine ("loop" callbacks to return to the main menu for example) but the addcontact() one fails with a variable error message even though it's a function
welcome aboard. The issue boils down to the addcontact being defined within the scope of a conditional (if...elif...else) and as a result not visible to search_and_edit which is defined in a different and mutually exclusive branch. So, when you chose 4, the program hadn't really entered 2 and the addcontact had not been "created" yet.
If you wish to make a function available at multiple places, then define it where it would in scope for all the callers.

how to use input() and match the elements with a database

database = {'User Name':['John frecks','Nadal alpha','Rick Ziani'],
'Code':['9264','8345','2675']}
for i in database:
name = input('Enter your name: ')
if name in database['User Name']:
print('Welcome', name,'Enter your code')
else:
print('You are not a client! Enter your name again!')
name = input('Enter your name: ')
break
code = input('Enter your code: ')
if code in database['Code']:
print('you are welcome')
break
else:
print('your code is wrong!')
break
The result I want,if all is right :
Enter your name: Nadal alpha
Enter your code: 8345
Your are welcome
The problem in my program is that whatever the code or the name are, I still get the same result.
For instance:
Enter your name: Nadal alpha
Enter your code: 2675 #this is Rick Ziani's code
You are welcome
Maybe, I didn't make the program the right way, if there is a way to optimize it, please tell me.
Thanks
The problem you have is that your database isn't mapping between things in a useful way. Your keys are just constant strings, and the values are lists. Maybe you could use indexing into the lists to find out which code corresponds to which name, but there is a much better way.
Make your database dictionary map from name to code directly, with no lists:
database = {'John frecks': '9264', 'Nadal alpha': '8345', 'Rick Ziani': '2675'}
Now you can check if a name is know with if name in database. And you can lookup the corresponding code with database[name].
the way that you have designed your dictionary is not the best practice to create a dictionary. but for the sake of the question, lets take things as they are.
The problem is that you haven't made any relationships between codes and usernames except for their orders which means nothing to python in itself
here is how to fix it in your code, i'll include comments for convenience:
for i in database:
user_index = 0 # you have to start a variable to be used in inner scopes
name = input('Enter your name: ')
if name in database['User Name']:
user_index = database['User Name'].index(name) # get the index of the entered name
print('Welcome', name,'Enter your code')
print(database['Code'][user_index])
else:
print('You are not a client! Enter your name again!')
name = input('Enter your name: ')
break
code = input('Enter your code: ')
if code in database['Code'] and code == database['Code'][user_index]:
# in the second part of the line above, you make sure that code and name have the same index
print('you are welcome')
break
else:
print('your code is wrong!')
break

Python 3 How to Ask user for specific input and reject invalid inputs

I have a question on how to check a user's input and make sure they are returning a specific string. Currently, the function when called will ask the user for their input. However, if they choose a string that is not part of the function, the else statement will execute and continue the code. I am trying to figure out how to loop this function, until a user inputs one of the strings that the function is looking for. Can anyone help me with this? I am new to python and would appreciate any help.
def dwarf_class_definer(dwarf_class):
if dwarf_class == "Thane":
print("'Ahhh Nobility'")
elif dwarf_class == "Mekanik":
print("'Interesting a Mechanic'")
elif dwarf_class == "Ancestrite":
print("'A spiritualist. I see...'")
elif dwarf_class == "Prisoner":
print("'Never met a gen-u-ine 'Last chancer.'")
elif dwarf_class == "Civilian":
print("'ehhh a civilian? Wut you doing here?'")
else:
print("You aren't choosing a valid class.")
dwarf_class = input("Which Class will you choose?: ")
dwarf_class_definer(dwarf_class)
A while loop will keep going until you tell it not to anymore. You can see when an expected value is supplied, the break command will terminate the while loop. A dictionary can also make your code a lot cleaner and easier to maintain compared to a bunch of if statements.
dwarf_classes = {
"Thane": "'Ahhh Nobility'",
"Mekanik": "'Interesting a Mechanic'",
"Ancestrite": "'A spiritualist. I see...'",
"Prisoner": "'Never met a gen-u-ine 'Last chancer.'",
"Civilian": "'ehhh a civilian? Wut you doing here?'",
}
while True:
dwarf_class = input("Which Class will you choose?: ")
if dwarf_class in dwarf_classes.keys():
print(dwarf_classes[dwarf_class])
break
print("You aren't choosing a valid class.")
example:
$ python3 so.py
Which Class will you choose?: Python!
You aren't choosing a valid class.
Which Class will you choose?: Prisoner
'Never met a gen-u-ine 'Last chancer.'

How to get Python 3 to register a random word from a external file as a variable

I'm a computer science student at secondary school currently struggling with a certain aspect of my NEA, we are permitted to get help with the code. The aim of the NEA is to create a game which can choose a random song and artist from an external file and then get the user to guess which song it is. The issue I have run into is when I run the program the random aspect of the code (The Song name and artist chosen from the external file) does not seem to be registered by the if statement. I cannot think of a better way to explain my issue, but if you run the code I believe you will see the issue I'm having. I have taken out most of the excess code that is not part of the problem to make it easier to understand because like I said before I am still a novice at this. I have looked around for a while now and cannot seem to find an answer. Any sort of help would be very much appreciated.
username = 'Player1'
password = 'Password'
userInput = input("What is your username? (Case Sensitive)\n")
if userInput == username:
userInput = input("What Is Your Password? (Case Sensitive)\n")
if userInput == password:
print(
"Welcome! In this game you need to guess each songs name after being given its first letter and its artist. Good luck!"
)
else:
print("That is the wrong password. Goodbye ;)")
exit()
else:
print("That is the wrong username. Goodbye ;)")
exit()
startgame = 'Start' 'start'
userInput1 = input("Click Any Button And Click Enter To Begin Game:")
if userInput1 == startgame: 'Start'
print("Welcome To The Game")
import random
Song = [line.strip() for line in open("Songnames.txt")] #Currently in the external file I have removed all of the other songs apart from H______ By Ed Sherran.
print(random.choice(Song))
userguess = input("Whats Your Answer?\n")
if userguess == ("Happier") and (random.choice(Song)) == "H______ By Ed Sherran": #The program will continue to return 'Incorrect'.
print("Nice One")
else:
print ("Incorrect")
Any sort of help would be very much appreciated , I have looked for a while on this site and others for an answer however if it seems I have missed an obvious answer I do apologise.
When I run the code it seems to work. (My Songnames.txt contains one line, H______ By Ed Sherran.)
Is it possible that your Songnames.txt contains at least one empty line? If so, filtering the empty lines might fix the problem:
Song = [line.strip() for line in open("Songnames.txt") if line.strip()]
A few other suggestions for your code:
startgame = 'Start' 'start'
userInput1 = input("Click Any Button And Click Enter To Begin Game:")
if userInput1 == startgame: 'Start'
print("Welcome To The Game")
This doesn't make sense. Besides the misleading prompt about buttons and clicks, the if userInput1 == startgame: 'Start' doesn't do anything, not even print start. And the game starts regardless of what the user enters.
The actual game has a few issues as well, most importantly for when you actually have multiple songs is the fact that you choose a random song twice. Given enough songs, these will almost always be two different songs, so the print will be utterly misleading. Better choose one song and assign it to a variable:
import random
songs = [line.strip() for line in open("Songnames.txt") if line.strip()]
computer_choice = random.choice(songs)
print(computer_choice)
userguess = input("Whats Your Answer?\n")
if userguess.lower() == computer_choice.lower():
print("Nice One")
else:
print("Incorrect")
I took the liberty to make the comparison case insensitive by comparing the lowercase versions of the user guess and the computer's choice.

Using if statements to terminate a for loop

I wasn't entirely sure how to word this question, so I'll stick with explaining my specific goal.
I'm trying to implement an 'eat' option to a user_input function for a text adventure. I want it to check if the verb is 'eat', check if the item is in the player's inventory, check if the item is consumable or not, and then - my goal - show that the player eats it (and only show it once, see below). The 'eat' option has no functionality as of yet, I'm only testing print statements.
I'm totally aware that the code below is not the most efficient way to handle user input (I'm still tweaking ways to handle input that is unexpected), so I'm 100% open to criticism. This was just my initial way of handling it and I'd like to try to make it work. I have a few other verbs ('go', 'look', 'take', etc.) that work, I'm just having a lot of trouble with 'eat'.
def user_input(self):
player = Player()
while True:
user_input = input("> ").lower()
words = user_input.split(" ")
wordlist = list(words)
verb = wordlist[0]
if len(wordlist) == 2:
noun = wordlist[1]
if noun not in items:
print("Somehow '{}' isn't the right word.".format(noun))
continue
else:
pass
# The above works fine because I don't have
# an issue with any of the other verbs regarding
# that bit of code.
# There's more code between these blocks to:
# handle if the user enters a noun that is > 1 word,
# define a few more verbs,
# then,
if verb == "eat":
for item in player.inventory:
if item.name == noun:
if isinstance(item, Consumable):
print("You eat the {}.".format(noun))
break
else:
print("You can't eat that!")
break
else:
print("You don't have '{}'.".format(noun))
I had to use the for loop (at least, I think I had to) because I'm iterating over a list that has objects in them, not strings, so I couldn't just use
if noun in player.inventory:
(I still tried it a million times though, it took forever to come up with a solution for that problem). Here's my specific example for the code above:
class Fists(Weapons):
def __init__(self):
self.name = "fists"
# more instance variables for Fists()
class LeatherWallet(Classy):
def __init__(self):
self.name = "leather wallet"
# more ...
class Pizza(Consumable):
def __init__(self):
self.name = "pizza"
# more ...
class Player():
def __init__(self):
self.inventory = [Fists(), LeatherWallet(), Pizza()]
# other stuff
*eat fists
You can't eat that!
*eat leather wallet
You don't have 'leather wallet'.
You can't eat that!
*eat pizza
You don't have 'pizza'.
You don't have 'pizza'.
You eat the pizza.
From the looks of it, it has got to be a simple fix, because it's clear what's happening as it iterates over the list. I just don't know how to (or if you can) wrangle a for loop to make it check conditions first then print later. At the risk of sounding dumb, I turn to you all for help!
Thank you, and please let me know if I can make this question/my goal any clearer.
Edit:
Tried to make the goal a little clearer in opening paragraphs.
You're not saying what you want the output to be, but my best guess is you don't want to say "you don't have X" more than once.
One way to do this is to use a flag, initialized to false, set to true when you find the item. When you get out of the loop the flag will tell you if you found it.
Something like this:
if verb == "eat":
found = false
for item in player.inventory:
if item.name == noun:
found = true
if isinstance(item, Consumable):
print("You eat the {}.".format(noun))
break
else:
print("You can't eat that!")
break
if !found:
print("You don't have '{}'.".format(noun))
for loops have else clauses that are run if the loop doesn't exit with a break. The idea is that the loop is looking for an item, will break when it finds it, and the else clause handles the default case where you don't find what you're looking for. The variables used inside the loop are still valid after the loop ends so the found (or defaulted) variable can be used in the next bit of code.
In your case, if you move that final else clause out one level, it will only run if the item is not found. In your example output, the two "you don't have 'pizza1" lines will no longer be printed.
for item in player.inventory:
if item.name == noun:
if isinstance(item, Consumable):
print("You eat the {}.".format(noun))
break
else:
print("You can't eat that!")
break
else:
print("You don't have '{}'.".format(noun))
item = None # <-- you can give a default value if you want to
# use the variable later
Looping through the list is okay until the list gets large. Then you are better off indexing the list with a dict for faster lookup.
self.inventory = dict((item.name, item)
for item in (Fists(), LeatherWallet(), Pizza()))
Then the for loop is replaced with
try:
item = player.inventory[noun]
if isinstance(item, Consumable):
print("You eat the {}.".format(noun))
else:
print("You can't eat that!")
except KeyError:
print("You don't have '{}'.".format(noun))
So, another approach is to just make this work, right?
if noun in player.inventory:
...
You have (at least) two ways to do it.
List comprehension
The first and easy one is using a list comprehension:
inventory_items = [item.name for name in player.inventory]
if noun in inventory_items:
...
That's it.
Custom class
The second one is creating an Inventory class inheriting from list and overriding the __contains__ method so you can compare them however you want.
Something like:
class Inventory(list):
def __contains__(self, item):
"""
Override `list.__contains__`.
"""
# First, check whether `item` is in the inventory.
#
# This is what a normal `list` would do.
if list.__contains__(self, item):
return True
# If we couldn't find the item in the list searching
# the "normal" way, then try comparing comparing it
# against the `name` attribute of the items in our
# inventory.
for inventory_item in self:
# Ensure we can do `inventory_item.name` so we don't get
# an AttributeError.
if 'name' not in dir(inventory_item):
continue
if inventory_item.name == item:
return True
return False
Then you instantiate your inventory like:
self.inventory = Inventory([Fists(), LeatherWallet(), Pizza()])
Remember that Inventory inherits from list, so if you can do list(x) then you should also be able to do Inventory(x) and get a very similar result (depending on how much you override in your class).
You could also get creative and make all items inherit from an Item class where you define the __eq__ method and make Pizza() == 'pizza' to simplify the Inventory comparisons.

Resources