I started Python 3 days ago. This user login code is the first project I completed, not following along with a tutorial. The idea is that you can create a user and login with it. I am wondering if there are ways to make this code much more efficient or shorter. If it needs anything, I'd love to learn new things.
def choices():
print("Please choose what you would like to do.")
choice = int(input("For Signing Up Type 1 and For Signing In Type 2: "))
if choice == 1:
print("Please Provide")
username = str(input("Username: "))
f = open("usernames.txt", 'r')
info = f.read()
if username in info:
print("Username unavailable. Please Try Again.")
return print(choices())
f.close()
password = str(input("Password: "))
f = open("passwords.txt", 'r')
info1 = f.read()
f.close()
f = open("usernames.txt", 'w')
info = info + " " + username
f.write(info)
f.close()
f = open("passwords.txt", 'w')
info1 = info1 + " " + password
f.write(info1)
f.close()
print("Congratulations! You have successfully created an account. You may now login in.")
return print(choices())
elif choice == 2:
print("Please Provide")
username = str(input("Username: "))
f = open("usernames.txt", 'r')
info = f.read()
if username in info:
password = str(input("Password: "))
f = open("passwords.txt", 'r')
info1 = f.read()
if password in info1:
print("Welcome Back " + username + "!")
else:
print("Your password is incorrect. Please try again.")
return print(choices())
else:
print("Your username is either incorrect or nonexistent. You can either try again or create a new account.")
return print(choices())
else:
raise TypeError
print(choices())
2 Answers 2
Use with
to handle file operations
A common way to handle files is by creating a file instance with open
statement and closing it when you are done with the handler, while this would work, it is prone to error. What if you forget to close the file? It leads to either the file not saving or the handler might be corrupted with garbage. with
automatically closes the file once operations on it are done. A simple example is as follow
with open('usernames.txt', 'r') as f:
f.read()
Recursion is expensive
Your choices
function uses recursion which might become expensive. Recursion creates temporaries in the stack frame and as it recur more and more, your stack frame might eventually be filled, though it can be elegant to solve a problem with recursion, limit it usage. Any function that can be written recursively can also be written with an iterative approach. Iterative approach tends to be faster and does not create temporaries
Consider reducing the complexity of choices
Right now choice
does way too much, signs up a user and also login a user. Your functions should do just one thing and do it very well. The name choices
is very misleading, from the name, I would expect it to make a choice or rather I make a choice among a list of values, rather is suprisingly signs up and login a user. Avoid function side-effect. Function side-effect is when a function promises one thing and does another.
Use a dictionary pair
I really think a dictionary is needed in this scenario. Dictionaries as we all know are very fast. Storing a key-value pair of username and password makes the code clean and easy to reason about.
Detour
You might want to use
open('filename.txt', 'a')
when you want to append to a file, using 'w' overwrites the content of the file and is similar to callingtruncate
on the file.When you want to recieve string input, no need for this statement
str(input("Enter"))
, input automatically recieves strings.Avoid variable names suchh as
f
This is an editted version of the code
def signup():
with open("usernames.txt", 'r') as user:
usernames = user.read().splitlines()
with open("passwords.txt", 'r') as pwd:
passwords = pwd.read().splitlines()
info = dict(zip(usernames, passwords))
print("Please Provide")
username = input("Username: ")
while username in info.keys():
print("Username unavailable. Please Try Again.")
username = input("Username: ")
password = input("Password: ")
with open("usernames.txt", 'a') as user:
user.write(username + '\n')
with open("passwords.txt", 'a') as pwd:
pwd.write(password + '\n')
print("Congratulations! You have successfully created an account. You may now login in.")
def login():
with open("usernames.txt", 'r') as user:
usernames = user.read().splitlines()
with open("passwords.txt", 'r') as pwd:
passwords = pwd.read().splitlines()
info = dict(zip(usernames, passwords))
username = input("Username: "))
password = input("Password: "))
if info.get(username, None) is None:
print("Your username is either incorrect or nonexistent. You can either try again or create a new account.")
signup()
return
if password != info[username]:
print("Your password is incorrect. Please try again.")
return
print("Welcome Back " + username + "!")
if __name__ == '__main__':
print("Please choose what you would like to do.")
choice = int(input("For Signing Up Type 1 and For Signing In Type 2: "))
if choice == 1:
signup()
elif choice == 2:
login()
ere are the points in your code that needs to be fixed:
Calling a function inside that function would sooner or later result in a
RecursionError
error. instead, usewhile
loop, and abreak
statement for when a user successfully logs in. Whenever invalid information is given, thecontinue
statement will make the program jump to the top of thewhile
loop again.Always use a
with
statement over simply assigning anopen
function to a variable.It is unnecessary to convert the user's input to an integer, especially when it is prone to cause a
ValueError
when the user inputs any characters tat aren't digits.There is no need to convert the user's input into a string, as the input will be of string type by default. Doing so only wastes efficiency.
Checking if a string is in a file in its single-string form will cause bugs. For example, if your file is currently:
Sally Bobby Timmy Bobble Deusovi Bubbler Ention
and the user inputs "Bob"
, the program will assume that "Bob"
is among the usernames.
Instead of spaces as the delimiter, which can cause confusion when a user inputs their last name, use line breaks \n
,
and convert the file's content into a list of names before checking if the user's input is valid.
Here is the full implementation:
def choices():
while True:
print("Please choose what you would like to do.")
choice = input("For Signing Up Type 1 and For Signing In Type 2: ")
if choice == '1':
print("Please Provide")
username = input("Username: ")
with open("usernames.txt", 'r') as f:
info = f.read()
if username in info:
print("Username unavailable. Please Try Again.")
continue
password = input("Password: ")
with open("passwords.txt", 'r') as f:
info1 = f.read()
with open("usernames.txt", 'w') as f:
info = f'{info}\n{username}'
f.write(info)
with open("passwords.txt", 'w') as f:
info1 = f"{info1}\n{password}"
f.write(info1)
print("Congratulations! You have successfully created an account. You may now login in.")
elif choice == '2':
print("Please Provide")
username = input("Username: ")
with open("usernames.txt", 'r') as f:
info = f.read().splitlines()
if username in info:
password = input("Password: ")
with open("passwords.txt", 'r') as f:
info1 = f.read().splitlines()
if password in info1:
print(f"Welcome Back {username}!")
break
print("Your password is incorrect. Please try again.")
else:
print("Your username is either incorrect or nonexistent. You can either try again or create a new account.")
else:
print("Invalid option.")
choices()