While loop never meets condition - python

So, for context I am trying to write a script that checks a text input fulfils all of the necessary requirements for a username.
However, the section I wrote to repeat the function if the conditions are not met always repeats after the first attempt even if the conditions are met. The first attempt works as intended.
This is the section that uses a list of conditions not met to establish whether or not to repeat the function, however even when the username is correct it repeats if after the first attempt.
if error_stack != []:
repeat = True
else:
repeat = False
return repeat
repeat = username_input(input("Please enter a username with only numbers and letters, which is above 2 characters and below 15 characters. If the username is taken you will be asked to pick a new one. \n|:"))
print(repeat) #please help its always true.....
while repeat == True:
repeat = username_input(input("Please enter a username with only numbers and letters, which is above 2 characters and below 15 characters. If the username is taken you will be asked to pick a new one. \n|:"))
print(repeat) #please help its always true.....
if __name__ == "__main__":
main()
In this screenshot I input 1 username which should result in the control var being set to True and the loop repeating, then I input 1 username which should result in the control var being set to False and the loop not repeating.
2 inputs 1 works other doesnt
In this screenshot I input 1 user name which should result in the control var being set to False and the loop not repeating. It then works as intended.
1 input works
Can someone please explain to me why the condition only functions as it should (as far as I'm aware it should check if the condition is met every time the loop ends after the first time) the first time, then after refuses to exit?
Edit: Full code of section
import os
STANDARD_CHARS = list("abcdefghijklmnopqrstuvwxyz1234567890 ")
ERROR_DICT = {
"NonStandardCharacterError":"Your username should only have letters and numbers in it, please pick another.",
"CurrentUserError":"Your username has already been taken, please pick another.",
"LengthError":"Your username should be more than 2 characters in length, and fewer than 15 characters in length, please pick another.",
}
def main():
printed_errors = []
error_stack = []
current_users = []
def username_input(word_input):
for char in list(word_input.lower()):
if char not in STANDARD_CHARS:
error_stack.append("NonStandardCharacterError")
if word_input.lower() in current_users:
error_stack.append("CurrentUserError")
if len(word_input) > 15 or len(word_input) < 3:
error_stack.append("LengthError")
for error in error_stack:
try:
if error not in printed_errors:
print(ERROR_DICT[error])
printed_errors.append(error)
except KeyError:
print("Your username has thrown an unknown error , please try again later or pick another username.")
if error_stack != []:
repeat = True
else:
repeat = False
return repeat
repeat = username_input(input("Please enter a username with only numbers and letters, which is above 2 characters and below 15 characters. If the username is taken you will be asked to pick a new one. \n|:"))
print(repeat)
while repeat == True:
repeat = username_input(input("Please enter a username with only numbers and letters, which is above 2 characters and below 15 characters. If the username is taken you will be asked to pick a new one. \n|:"))
print(repeat)
if __name__ == "__main__":
main()

You initialize error_stack to [] in main, and append to it in username_input. But after its initial creation, you never reset it back to the empty list. So error_stack grows and grows, retaining old errors even when the user enters valid input.
Try creating error_stack inside username_input instead of inside main. Then it will be set to the empty list for every new user input prompt.
def main():
printed_errors = []
current_users = []
def username_input(word_input):
error_stack = []
for char in list(word_input.lower()):
#...
If, for some reason, it is necessary to keep error_stack in the higher scope, you can instead clear it with the clear method.
def main():
printed_errors = []
error_stack = []
current_users = []
def username_input(word_input):
error_stack.clear()
for char in list(word_input.lower()):
#...

Related

Querying a dictionary user input infinite loop python

Newbie trying to learn some basic python, I've imported a json file containing a dictionary of terms. I'm trying to create a script that lets users look up definitions from my dictionary. I'm getting stuck on lines 14-15. I don't want the script to stop after just two attempts. I can work out how to set it to a max # of attempts but not how to make it infinite allowing unlimited tries. Each new query should be followed by a close match result using the get_close_matches method in difflib if the attempt is not an exact match, with the user prompted to accept or reject the closest match. My script, however, will stop after two attempts and if the 2nd query is not an exact match error out instead of presenting the 3 (the default for the method) closest matches to the word. Any ideas?
import json
from difflib import get_close_matches
data=json.load(open('data.json'))
def translate(w):
w=w.lower()
if w in data:
return data[w]
elif len(get_close_matches(w,data.keys()))>0:
yn=input("Did you mean %s? Enter Y or N: " % get_close_matches(w,data.keys())[0]).upper()
while yn =="N":
i=input("Enter Word: ")
return data[get_close_matches(i,data.keys())]
else:
return data[get_close_matches(w,data.keys())[0]]
word=input("Enter Word: ")
print(translate(word))
Your current approach isn't working because of the return statement inside the while yn == "N" loop. That return immediately takes you out of the function, regardless of whether the loop has completed, so there's no way for this loop to run more than once.
You could edit the loop to prevent it from always returning, but it's easier to move the loop outside the function. That way you don't have to worry about whether you're working with the initial input or a subsequent input, and you can cut down on duplicate code:
def translate():
w = input("Enter Word: ").lower()
if w in data:
return data[w]
close_matches = get_close_matches(w, data.keys()) # This only runs if w was NOT in data
if len(close_matches) > 0:
yn = input("Did you mean %s? Enter Y or N: " % close_matches[0]).upper()
if yn == 'Y':
return data[close_matches[0]]
return None # This is optional. Reaching the end of a function will return None by default
translated_word = None # Force at least one iteration of the loop
while translated_word is None: # Keep going until there's a match or the user types "Y"
translated_word = translate()
print(translated_word) # This will only run once the loop condition is False

Error Tapping a section of code

I have a while statement which works well and I have a whole section of code that asks the user to input how many names they have which will then ask them for a name that amount of times and then each time a name will be entered.
I need the section of the names entered to be error tapped but I don't know how to do it, as I have a while statement and I may need to put another while statement in, although I have error tapped the section for amount of names in numbers.
Also there is code further on with a dictionary and sorts but I need help with the one section of error tapping started at while currentnum part
print("Please enter each name when asked without any spaces.") #The program will post this
print("Please enter each of your names individually also.") #Program will again post this
names = [] #This is the value of names which will be changed depending on the input
currentnum = 0 #Currentnum value is 0
while True: #While loop as it will revert to the start if question answered incorrectly
try:
numofnames = int(input("How many names do you have? "))
except ValueError: #if the input is not an integer or a whole number it will
print("Sorry that was not a valid input please retry")
continue #it will loop back and ask the question again as it says that the unput was not valid
else:
break #If the input is correct then the loop will break and continue to the next section of the program
while currentnum < numofnames: #This means that while currentnum is smaller than input for numofnames it will continue to ask question. This is another loop
currentnum = currentnum + 1 # every time the question is asked it means that currentnum gets 1 added to it and will continue to ask untill it is the same as the input for numofnames
name = str(input("Enter your name: ")) #Name asked to be entered in string
name = name.upper() #This changes all letters to upper case no matter what so there is no error for upper and lower case or a bigger dictionary showing lower and upper case values.
names.append(name)
Yep. The easiest way to describe what you're doing is to use the .isalpha attribute in an if statement. First you will have to def your while loop
Like the following:
def Loop():
name_input_complete = False
while name_input_complete != True:
string = input("Please input :")
string = str(string)
if string.isalpha():
name_input_complete = True
else:
print("Please do not use numbers and spaces")
Loop()
Loop()
Baisically you have to define the loop and then run it. The if statement(which is the part you should add to your loop) then checks if there is nothing other than letters. If true, your done with error trapping and the loop is exited. The program continues outside the loop. If not then the while is repeated because the Loop() function is called again.
Your code looks very good to me. I dont see what input can the user put that could cause an error, since most data in python can be stringed AND names can be pretty much anything!. If you could comment exactly what error could be caused i might be able to help you

Taking Mutiple line input in python using basic python

I am trying to solve some problems in CodeAbbey using Python.I have run into a wall trying to take input for these programs.I have spent so much time analyzing how to take the input data without even solving the question.Hope someone explains how to take input.
Problem:I have to input the following numbers in One go. I have tried using 'input()' but it takes only one line. Is there any work around to do it in a simple way? i wasted so much time trying to analyse various options
632765 235464
985085 255238
621913 476248
312397 751031
894568 239825
702556 754421
474681 144592
You can find the exact question here: http://www.codeabbey.com/index/task_view/sums-in-loop
You can just repeat input() until you get all your data, e.g.:
try:
input = raw_input # fix for Python 2.x compatibility
except NameError:
pass
def input_pairs(count):
pairs = [] # list to populate with user input
print("Please input {} number pairs separated by space on each new line:".format(count))
while count > 0: # repeat until we get the `count` number of pairs
success = True # marks if the input was successful or not
try:
candidate = input() # get the input from user
if candidate: # if there was some input...
# split the input by whitespace (default for `split()`) and convert
# the pairs to integers. If you need floats you can use float(x) instead
current_pair = [int(x) for x in candidate.split()]
if len(current_pair) == 2: # if the input is a valid pair
pairs.append(current_pair) # add the pair to our `pairs` list
else:
success = False # input wasn't a pair, mark it as unsuccessful
else:
success = False # there wasn't any input, mark it as unsuccessful
except (EOFError, ValueError, TypeError): # if any of the conversions above fail
success = False # mark the input as unsuccessful
if success: # if the input was successful...
count -= 1 # reduce the count of inputs by one
else: # otherwise...
print("Invalid input, try again.") # print error
return pairs # return our populated list of pairs
Then you can call it whenever you need number pairs like:
my_pairs = input_pairs(7) # gets you a list of pairs (lists) entered by user
My first attempt would be to try a typing like "632765 235464\n985085 255238[...]" so you could read it as one line. This would be pretty hacky and not a good idea if its real userinput.
The other idea: Why not taking the input line by line and putting these lines in a list / appending them to a string?
EDIT:
I found some Code on SO, but its python2.7 i guess. ->Here
The Python3.X style would be:
#!/usr/bin/python
input_list = []
while True: # Infinite loop, left by userinput
input_str = input(">") #The beginning of each line.
if input_str == ".": #Userinput ends with the . as input
break # Leave the infinite loop
else:
input_list.append(input_str) #userinput added to list
for line in input_list: #print the input to stdout
print(line)
Hope this will help :)

Python Password Prigram

I am creating a password program for my programming class, the requirements are:
8 Characters/1 letter/1 Digit/Alphanumeric only
The problem is the .isalpha or .isdigit cancel each other out because they require all of the string to be letters or numbers.
Is there anyways I can make it check if atleast 1 character is a number or letter
###############################
# PROLOG SECTION
# new_password.py
# Program to check a user's proposed
# password.
# (today's date goes here)
# (programmer names go here)
# (tester names go here)
# Possible future enhancements:
# Unresolved bugs:
###############################
###############################
# PROCESSING INITIALIZATION SECTION
###############################
# code goes here
minlength = 8
valid = False
###############################
# PROCESSING SECTION
# Branching code:
# Looping code:
###############################
# code goes here
# get the user input
password = str(input("Type in your password: "))
# test the password length
if len(password) >= minlength:
# test for all alphanumeric
if password.isalnum():
if password.isalpha():
if password.isdigit():
# if the password meets BOTH conditions, set valid to true
valid = True
else:
#otherwise, give the user a meaningful error message
print("Error, password does not contain a number.")
else:
#otherwise, give the user a meaningful error message
print("Error, password does not contain a letter.")
else:
# otherwise, give the user a meaningful error message
print("Error, password is not alphanumeric.")
else:
# otherwise, give the user a meaningful error message
print("Error, password is less than",minlength,"characters.")
###############################
# CLEANUP, TERMINATION, and EXIT
# SECTION
###############################
# code goes here
# print informational messages
# if the password meets the condition (at least 8 characters)
if valid == True:
# print the "successful" message
print("Your new password is valid.")
else:
# otherwise, print the "unsuccessful" message
print("Your new password is not valid.")
Use any():
valid = any(c.isalpha() for c in password) and any(c.isdigit() for c in password)
This will satisfy the requirement that there is at least 1 alpha character and 1 digit. Combine that with password.isalnum() and the length check and you should be able to vet your passwords.
There are several (innumerable?) ways to accomplish this.
Looking at the code you have, you've taken care of testing the length and making sure you have only alphanumeric characters. So consider some candidate password which has cleared these two hurdles. You want to let through any candidate that contains at least one letter and at least one digit.
So figure out what you want to stop (there are basically two 'bad' cases), and how you could identify these with .isalpha and .isdigit. (i.e. once you know what the 'bad' candidates look like, what would they give you for each of those methods?)
Use Regex. OR
If you only want to check if at least 1 char is number or a letter. Then use this:
#To check for at least 1 digit
>>> str="yogi123yogi"
>>> [chr.isdigit() for chr in str]
[False, False, False, False, True, True, True, False, False, False, False]
any() comes in handy here:
>>> any([chr.isalpha() for chr in str])
True
Similarly check of 1 alphabet also:
>>> any([chr.isalpha() for chr in str])
True
Note: Well you can process the above information from isdigit() and isalpha to figure out the total count and match with the password length.
Total num of digits + Total num of alphabets == Password Length
Else don't accept the password.

how to stop a loop

I wrote this code that I'm trying to get it to work. What I am trying to do is to prompt user to enter names of employees and use a list to store the names.
Now the part that I am having trouble with is with the loop, the loop is suppose to stop when the user types 'done', and then display the number of names entered, and with another loop, display the names entered each on its own line.
I don't know what I am doing wrong with the code but, after the user enters then names it will say: 'Press enter to continues adding names' and it will also say: 'If you would like to stop adding names, type=done'
If the user hits enter, then it should ask for another name and repeat the questions to see if user wants to add more or stop. But for some reason, even if the user press enter to continue adding names, it still outputs the number of names entered and the list of names. I don't want that to happen, I'm trying to get it to where it will display the result ONLY if the user types 'done' but the word 'done, cannot be displayed in the output. I've looked over and over the code and can't figure out what if am doing wrong.
Here is my code:
employee_list=[]
stop='done'
while stop == 'done':
employee_name=input('Enter name of employee:')
employee_list.append(employee_name)
print('Press enter to continues adding names')
enter_another=input('If you would like to stop adding names, type=done ')
print()
list_size=len(employee_list)
print('The number of employees you have entered: ', list_size)
for index in range(list_size):
print(employee_list[index])
You haven't got a check in your code if a person types done.
For example:
if enter_another == "done":
stop == "finished now"
But this doesn't make sense, your check is saying "if stop is done then keep going", which makes no sense semantically.
Try this instead:
more_employees = True
while more_employees: # Never do thing == True
# ... your code
enter_another=input('If you would like to stop adding names, type=done ')
if enter_another == "done":
more_employees = False
# ... the rest of your code
As stated, PEP8 recommends against comparing thing == True:
Don't compare boolean values to True or False using ==.
Yes: if greeting:
No: if greeting == True:
Worse: if greeting is True:
Try this. I have put your printing condition outside the loop.
employee_list=[]
stop='done'
while stop == 'done':
employee_name=raw_input('Enter name of employee: ')
employee_list.append(employee_name)
print 'Press enter to continue adding names'
enter_another=raw_input('If you would like to stop adding names, type=done \n')
if enter_another == 'done':
stop = 'random'
print
list_size=len(employee_list)
print 'The number of employees you have entered: ', list_size
for index in range(list_size):
print employee_list[index],

Categories

Resources