Python Invalid Else Placement (Beginner) - python

I'm getting a syntax error after an else statment. Is it due to indentation?
if choice == 2:
actor = input('Enter actor:')
actorLower = actor.lower()
for name in actors:
nameLower = name.lower()
if actorLower in nameLower:
print(actors[name])
else:
print('Actor not found')
elif choice == 1:
movie = input('Enter movie:')
print(moviedict[movie])
else: #**This is where I'm getting the syntax error**
print('Movie not found')
elif choice != 0:
print('Invalid choice')
query('movies.txt')

In plain english, else means otherwise, so you have to specify a condition of validity (the if key word) and a case when this if is not met (that is your else)
From your example on the second block:
elif choice == 1:
movie = input('Enter movie:')
print(moviedict[movie])
else:
print('Movie not found')
is not valid because
else:
print('Movie not found')
does not have a if, you never test if the movie belongs to the dictionnary. A solution to that would be:
movie = input("Enter movie:")
if movie in moviedict.keys():
print(moviedict[movie])
else:
print('Movie not found')
Would be a solution in that case. Same thing for your first "Actor not found"

The error occurs here
elif choice == 1:
movie = input('Enter movie:')
print(moviedict[movie])
else:
print('Movie not found')
You have added an else statement without an if. That is the reason it says invalid else placement. Either add a if before the else or remove the else part.

Related

Python TypeError: cannot unpack non-iterable bool object

I am getting TypeError: cannot unpack non-iterable bool object when I am trying to search through a list. and when I return a boolean and the index value of the item I am searching for.
def name_ser(name):
found = False
for i in range(len(names)):
if names[i] == name:
found = True
return found, names.index(name)
else:
found = False
return found,None
def main_menu():
print('Welcome!\nPlease Choose from the following options...')
print('1: Create an account\n2: Login ')
opt = int(input('Enter Your Choice: '))
if opt == 1:
name_search = input('Enter Name... ')
found, _ = name_ser(name_search)
if found == True:
print("Account Already excites!")
elif found == False & len(names) == 0:
acc_creation(name_search)
print('Account created!')
error:
Traceback (most recent call last):
File "/Users/darkmbs/VS-Code/FirstPythonProject/accounts.py", line 100, in <module>
main_menu()
File "/Users/darkmbs/VS-Code/FirstPythonProject/accounts.py", line 77, in main_menu
found, _ = name_ser(name_search)
TypeError: cannot unpack non-iterable NoneType object
name_ser can return 3 different objects.
def name_ser(name):
found = False
for i in range(len(names)):
if names[i] == name:
found = True
return found, names.index(name) <== returns 2-tuple
else: <== if name[0] doesn't match,
found = False executes immediately
return found <== returns boolean
<== if names is empty, returns None
You need a consistent return type. But really, this function shouldn't exist at all. Its trying to return the index of name in names, or False. str.find just pretty much just that.
def main_menu():
print('Welcome!\nPlease Choose from the following options...')
print('1: Create an account\n2: Login ')
opt = int(input('Enter Your Choice: '))
if opt == 1:
name_search = input('Enter Name... ')
if name_search in names:
print("Account Already exists!")
else:
acc_creation(name_search)
print('Account created!')
I also removed the check for name_ser being empty before adding an account. I think it would be strange if only 1 person could create an account.
As mentioned in some of the earlier comments, you cannot return both one or two values. My recommendation is to return the index of the name. Or if it is not found, return the value -1.
def name_ser(name):
# Check if element is in list
if name in names:
# Return index of element
return names.index(name)
else:
# Name was not found in the list
return -1
def main_menu():
print('Welcome!\nPlease Choose from the following options...')
print('1: Create an account\n2: Login ')
opt = int(input('Enter Your Choice: '))
# Create account
if opt == 1:
name_search = input('Enter Name... ')
found = name_ser(name_search)
if found >= 0:
print("Account Already exists!")
elif found == -1 & len(names) == 0:
acc_creation(name_search)
print('Account created!')
# Login to Account
if opt == 2:
# Update to use index instead of boolean

Binary Search tree python. Iterative search

I was wondering if someone could help me see what i am doing wrong with this search function for a binary search tree. Have to use the iterative version due to the size of data. I keep getting stuck in an infinite while loop when i print out values for debugging. Thanks!
I also get this error:
while (word_search.value != user_input) and (word_search.value != None):
AttributeError: 'NoneType' object has no attribute 'value'
def iterative_word_search(current, user_input):
word_search = current.root
print("User input value", user_input)
print("Word Search Value", word_search.value)
while (word_search.value != None) and (word_search.value != user_input):
print("While Loop value: ", word_search.value)
if(user_input < word_search.value):
word_search = word_search.left
# print("If statement value: " ,word_search.value)
elif(word_search.right != None):
word_search = word_search.right
print("Else statement value: ", word_search.value)
elif(word_search.value == None):
print("Word does not exist")
return word_search
return word_search
You need to assert that left and right are not None before calling .value on them:
Python lazy evaluation of expressions allows you to do this on one line. if word_search is None or word_search.value is None will evaluate word_search, and if it is None, will not evaluate word_search.value.
def iterative_word_search(current, user_input):
word_search = current.root
while True:
if word_search is None or word_search.value is None:
print("not found")
break
if word_search.value == user_input:
print("found")
break
if(user_input < word_search.value):
word_search = word_search.left
elif(word_search.right != None):
word_search = word_search.right
return word_search
Thank you for all the help!
Solved the problem. It dealt with user input and the files that i read in.
The files that i read in had a '\N' attached to it. Which is why i kept getting multiple errors and it was not searching the word.

Force case on dictionary to compare user input in Python

I'm making a user input decision tree and I want to force the dictionary that the input is being compared to into lowercase. I've placed .lower() at various points and keep getting errors.
not_found = True
while True:
if OPTIONS == "1" or 'a':
ARTIST_PICK = str(raw_input(
"Please pick an artist\n"
"Or Q to quit: ")).lower
print ARTIST_PICK
**entries = allData(filename).data_to_dict()
for d in entries:
arts = d['artist']**
if ARTIST_PICK in arts:
print "found it"
elif ARTIST_PICK == 'q':
break
else:
print "Sorry, that artist could not be found. Choose again."
not_found = False
This is a sample of the "entries" I'm trying to make lower and compare the user input to:
[{'album': 'Nikki Nack', 'song': 'Find a New Way', 'datetime': '2014-12-03 09:08:00', 'artist': 'tUnE-yArDs'},]
If your problem was just comparing the artist names, then you could use list comprehension to make everything lowercase.
entries = allData(filename).data_to_dict()
if ARTIST_PICK in [ d['artist'].lower() for d in entries ]:
print("found it")
elif ARTIST_PICK == "q":
break
else
print("Sorry, that artist could not be found. Choose again.")
Or if you'd rather use a for loop (rearranged a little for readability):
if(ARTIST_PICK != 'q'):
entries = allData(filename).data_to_dict()
found = False
for d in entries:
if ARTIST_PICK == d['artist'].lower():
found = True
break
elif ARTIST_PICK == "q":
break
if(found):
print("found it")
else:
print("Sorry, that artist could not be found. Choose again.")
else:
# handle the case where the input is 'q' here if you want
By the way, as a matter of principle you should name your boolean variables as though you were using them in a sentence. Instead of setting a variable not_found to False if the variable isn't found, set a variable named found to False or set not_found to True. Makes things easier in the long run.
ARTIST_PICK = str(raw_input(
"Please pick an artist\n"
"Or Q to quit: ")).lower()

Python not reading string a second time

I'm writing a text adventure (does anyone remember Zork?), and I'm having troubles with this code:
from random import randint
def prompt():
action = input(">>> ").lower()
if action == "exit":
quit()
elif action == "save":
save()
else:
return action
def action_error(custom=False):
if custom != False:
print(custom)
else:
phrases = ["A bunch", "of funny", "error phrases"]
print(phrases[randint(1, len(phrases)-1)])
return prompt()
action = prompt()
while True:
print(action) #Debugging purposes
if action.find("switch") != -1:
if action.find("light") != -1:
second_room() #Story continues
else:
action = action_error("What do you want to switch?")
action = action_error()
The matter is that if I enter a string that contains "switch", the next input is not picked up.
Also, anyone has better ways to parse verb-noun strings like "switch the light", "open the door" or "look around"/"look at OBJECT"?
First of all I noticed that if you enter switch twice the second time it's caught as an error by your program.
I think the problem lies at the end of the action_error function where you assign the return value to prompt(), so the input get consumed too early.
A possible fix would be:
def action_error(custom=False):
if custom != False:
print(custom)
else:
phrases = ["A bunch", "of funny", "error phrases"]
print(phrases[randint(1, len(phrases)-1)])
while True:
action = prompt()
print(action) #Debugging purposes
if action.find("switch") != -1:
if action.find("light") != -1:
second_room() #Story continues
else:
action_error("What do you want to switch?")
else:
action_error()
So no return value for action_error() and direct assignment at the beginning of the while loop.
How about, in the case of a partially entered compound action, you concatenate the new input to the old one? Then "switch" becomes "switch light", and both of your conditionals will pass.
action = prompt()
while True:
print(action) #Debugging purposes
if action.find("switch") != -1:
if action.find("light") != -1:
second_room() #Story continues
else:
action = action + " " + action_error("What do you want to switch?")
continue
action = action_error()
Bonus style suggestions:
replace a.find("b") != -1 with "b" in a
use random.choice(phrases) instead of phrases[randint(1, len(phrases)-1)]

How to make the user only enter one character at a time

OK so what I need to do is make my code only allow the user to enter one letter and then one symbol at a time. The example below shows what I want in a better view.
At the moment my code allows the user to enter more than one character at a time which I don't want.
What letter would you like to add? hello
What symbol would you like to pair with hello
The pairing has been added
['A#', 'M*', 'N', 'HELLOhello']
What I want is a message to be displayed like this and the pairing not to be added to the list.
What letter would you like to add? hello
What symbol would you like to pair with hello
You have entered more than one character, the pairing was not added
['A#', 'M*', 'N',].
So far my code for this section is as follows...
It would also be great for when the user enters a number in the letter section, an error message to be printed.
def add_pairing(clues):
addClue = False
letter=input("What letter would you like to add? ").upper()
symbol=input("\nWhat symbol would you like to pair with ")
userInput= letter + symbol
if userInput in clues:
print("The letter either doesn't exist or has already been entered ")
elif len(userInput) ==1:
print("You can only enter one character")
else:
newClue = letter + symbol
addClue = True
if addClue == True:
clues.append(newClue)
print("The pairing has been added")
print (clues)
return clues
The easiest way to ensure user input is with a loop:
while True:
something = raw_input(prompt)
if condition: break
Something set up like this will continue to ask prompt until condition is met. You can make condition anything you want to test for, so for you, it would be len(something) != 1
Your method can be simplified to the following if you let the user enter a letter and symbol pair:
def add_pairing(clues):
pairing = input("Please enter your letter and symbol pairs, separated by a space: ")
clues = pairing.upper().split()
print('Your pairings are: {}'.format(clues))
return clues
Not exactly sure what you want to return but this will check all the entries:
def add_pairing(clues):
addClue = False
while True:
inp = input("Enter a letter followed by a symbol, separated by a space? ").upper().split()
if len(inp) != 2: # make sure we only have two entries
print ("Incorrect amount of characters")
continue
if not inp[0].isalpha() or len(inp[0]) > 1: # must be a letter and have a length of 1
print ("Invalid letter input")
continue
if inp[1].isalpha() or inp[1].isdigit(): # must be anything except a digit of a letter
print ("Invalid character input")
continue
userInput = inp[0] + inp[1] # all good add letter to symbol
if userInput in clues:
print("The letter either doesn't exist or has already been entered ")
else:
newClue = userInput
addClue = True
if addClue:
clues.append(newClue)
print("The pairing has been added")
print (clues)
return clues
I am fan of raising and catching exceptions in similar cases. Might be shocking for people with 'C-ish' background (sloooow), but it is perfectly pythonic and quite readable and flexibile in my opinion.
Also, you should add check for characters outside of set you are expecting:
import string
def read_paring():
letters = string.ascii_uppercase
symbols = '*##$%^&*' # whatever you want to allow
letter = input("What letter would you like to add? ").upper()
if (len(letter) != 1) or (letter not in letters):
raise ValueError("Only a single letter is allowed")
msg = "What symbol would you like to pair with '{}'? ".format(letter)
symbol = input(msg).upper()
if (len(symbol) != 1) or (symbol not in symbols):
raise ValueError("Only one of '{}' is allowed".format(symbols))
return (letter, symbol)
def add_pairing(clues):
while True:
try:
letter, symbol = read_paring()
new_clue = letter + symbol
if new_clue in clues:
raise ValueError("This pairing already exists")
break # everything is ok
except ValueError as err:
print(err.message)
print("Try again:")
continue
# do whatever you want with letter and symbol
clues.append(new_clue)
print(new_clue)
return clues

Categories

Resources