Reputation: 25
First post here although I have lurked for many years
I am currently working on a programming project and am stuck. The goal of the project is to take input from a user, a username and password, and verify through a text file to see if it is correct. If correct, it will print "Welcome!" and end, if not, it will ask for the username and password and loop through until a correct combination is entered.
The textfile is in the following format:
Darth:Vader
Boba:Fett
R2:D2
ObiWan:Kenobi
Luke:Skywalker
Here is my code:
# Lets user know what this program will do
print("Please login");
# Opens accounts txt file
accounts_file = open("accounts.txt", "r")
# Flag to terminate while loop
complete = False
# Runs loop until username and password are correct
while complete == False:
# Asks user for username and stores as variable
usernameInput = input("Username:");
# Asks user for password and stores as variable
passwordInput = input("Password:");
# Reads each line of the text file line by line
# Darth:Vader
# Luke:Skywalker
# R2:D2
# ObiWan:Kenobi
# Boba:Fett
for line in accounts_file:
# Stores each line in file as a username/password combo
username, password = line.replace("\n","").split(":")
# If username and password match, breaks out of the loop and sets complete to True
if usernameInput == username and passwordInput == password:
complete = True
break
# Sets complete to False and loops back
else:
complete = False
continue
if complete == True:
print("Welcome!");
I can get it to run correctly if enter a correct name the first time: For instance:
Please login:
Username:Darth
Password:Vader
Welcome!
- ends program
If I enter the wrong name, it loops back like so:
Please login:
Username:Darth
Password:Fett
Username:.....
However, if I enter a wrong username and then correct username, it will not end the program like I want it to, and continue to loop: Example:
Please login:
Username:Luke Password:Vader
Username:Darth Password:Vader
Username:R2 Password:D2
Any idea what is causing it to not accept the next input by the user and finishing the loop?
Thank you for the help!
Upvotes: 2
Views: 3648
Reputation: 114290
Once you open a file and iterate through it, the iterator is exhausted. Just because your outer loop goes into another iteration does not restart the file iteration.
When you do for x in [1, 2, 3]:
, python calls iter([1, 2, 3]
under the hood. For a list, this returns a new iterator object every time. When a similar loop calls iter(accounts_file)
, a new iterator is not returned: the file object is the iterator.
You have two basic options to restart the iteration:
Reopen the file every time. Normally, the idiomatic way to do that is with a with
block, as that will also close the file automatically in case of error:
while not complete:
usernameInput = input("Username:")
passwordInput = input("Password:")
with open("accounts.txt", "r") as accounts_file:
for line in accounts_file:
username, password = line.replace("\n","").split(":")
if usernameInput == username and passwordInput == password:
complete = True
break
This option is less desirable because it does a lot of disk I/O every time the user enters a wrong option.
Load the entire file into a list. That lets you iterate over and over without hitting the disk multiple times. You can pre-load before the loop, or do it lazily after the first input. The first option is shown here:
with open("accounts.txt", "r") as accounts_file:
lines = accounts_file.readlines()
while not complete:
usernameInput = input("Username:")
passwordInput = input("Password:")
for line in lines:
username, password = line.replace("\n","").split(":")
if usernameInput == username and passwordInput == password:
complete = True
break
A third option would be a hybrid of these two, which might work for large files. You could pre-load an index into the file, and then look up small snippets based on user input.
Notice that the else
clause is not necessary. complete
is False
and only changes when you want to break out of the loop.
It's more idiomatic to write while not complete:
. The expression in the condition of a while
loop is always interpreted as a boolean: there is no need to make the comparison explicit. And even then, bool
values True
and False
are singletons. In the relatively rare situations when you need to compare against them explicitly, use the identity operator is
rather than ==
. I.e., complete is False
is more pythonic than complete == False
.
You could actually get rid of the complete
variable entirely by using an arcane feature of for
loops: the else
clause. This clause gets triggered whenever a loop completes without breaking:
while True:
usernameInput = input("Username:")
passwordInput = input("Password:")
with open("accounts.txt", "r") as accounts_file:
for line in accounts_file:
username, password = line.replace("\n","").split(":")
if usernameInput == username and passwordInput == password:
break
else:
continue
break
Also, don't use semicolons normally in python. They aren't invalid, but they aren't conventional except in rare situations like command-line interaction.
Upvotes: 2
Reputation: 47
print("Please Login !")
accounts_file = open("accounts.txt", "r")
USERS = []
for line in accounts_file:
if line.replace("\n","").split(":") != [""]:
accounts.append(line.replace("\n","").split(":"))
accounts_file.close()
def passCheck(username , password):
if [username,password] in USERS:
return
else:
return passCheck(input("Enter your username : ") , input("Enter your password"))
passCheck(input("Enter your username : ") , input("Enter your password"))
print("Welcome!")
Upvotes: 0
Reputation:
How about this:-
ACCOUNTS = {}
with open('accounts.txt') as afile:
for line in afile.readlines():
tokens = line.split(':')
ACCOUNTS[tokens[0]] = tokens[1].strip()
print('Please log in')
while True:
n = input('Please enter your name: ')
p = input('Please enter your password: ')
if (password := ACCOUNTS.get(n)) and password == p:
break
print('Incorrect username or password')
print('Welcome')
Upvotes: 0
Reputation: 1054
It it doing so because your file is empty in the second time you try to read it.
After the first time you ran on the whole file here:
for line in accounts_file:
# Stores each line in file as a username/password combo
username, password = line.replace("\n","").split(":")
# If username and password match, breaks out of the loop and sets complete to True
if usernameInput == username and passwordInput == password:
complete = True
break
# Sets complete to False and loops back
else:
complete = False
continue
The file is empty, so called ‘depleted’. You need to make a new file object every time all over again if the user is wrong. Just do like so:
accounts_file = open("accounts.txt", "r")
for line in accounts_file:
# Stores each line in file as a username/password combo
username, password = line.replace("\n","").split(":")
# If username and password match, breaks out of the loop and sets complete to True
if usernameInput == username and passwordInput == password:
complete = True
break
# Sets complete to False and loops back
else:
complete = False
continue
account_file.close() # Very important to close the file for next time!
Or you could use with ... as ...
like so:
with open("accounts.txt", "r") as accounts_file:
for line in accounts_file:
# Stores each line in file as a username/password combo
username, password = line.replace("\n","").split(":")
# If username and password match, breaks out of the loop and sets complete to True
if usernameInput == username and passwordInput == password:
complete = True
break
# Sets complete to False and loops back
else:
complete = False
continue
Upvotes: 3