We'd like to make a function that lets users log in. The function return True
on successful login, and False
otherwise.
The function locks the user out if there are three consecutive unsuccessful logins.
The function returns different things for the same inputs depending on what happened before. That means that we need to use global variables (or something equivalent) in order to keep track of the state: the information that determines what the function should return based on what happened before.
We saw an example of this before, when we generated pseudorandom numbers (we needed to keep track of what x
was).
# login.py
def login(user, password):
global n_attempts, locked_out # may need to change those
if locked_out:
return False
if user not in users:
n_attempts += 1
if n_attempts == 3:
locked_out = True
return False
if passwords[users.index(user)] != password: # can now safely use users.index(user)
# since user is in users
n_attempts += 1
if n_attempts == 3:
locked_out = True
return False
# N.B., could also user if user not in users or passowrds[users.index(user)] != password
# because of short-circuiting -- we'll discuss this later
n_attempts = 0 # succesful attempt: reset n_attempts
return True
def initialize():
global users, passwords
global n_attempts, locked_out
users = ["guerzhoy", "cluett", "stangeby"]
passwords = ["ILovePython", "matrix", "rigorous"]
n_attempts = 0 # initially, 0 consecutive failed attempts
locked_out = False # initialliy, not locked out
initialize() # call the function outside the main block
# user_login.py
import login # intialize is run
if __name__ == __main__:
print(login.login("guerzhoy", "ILovePython")) # True
print(login.login("guerzhoy", "ILikePython")) # False
print(login.login("guerzhoy", "ILikePython")) # False
print(login.login("guerzhoy", "ILikePython")) # False, locked out
print(login.login("guerzhoy", "ILovePython")) # False, because locked out