Reputation: 63
I think I have the right idea of solving this function, but I'm not sure why I don't get the desired results shown in the docstring. Can anyone please help me fix this?
def check_password(s):
'''(str, bool)
>>> check_password('TopSecret')
False
>>> check_password('TopSecret15')
True
'''
for char in s:
if char.isdigit():
if char.islower():
if char.isupper():
return True
else:
return False
Upvotes: 1
Views: 667
Reputation:
I've gone way overboard here (because I'm bored I guess) and whipped up an extensible password-checking system. Perhaps it will help clarify why your version doesn't do what you want (or maybe it won't).
The essential problem with your code is that it checks for a single characteristic instead each of the required characteristics.
def check_password(password):
# These are the characteristics we want a password to have:
characteristics = [
length(8), # At least 8 characters
lower_case(1), # At least 1 lower case letter
upper_case(1), # At least 1 upper case letter
number(1), # At least 1 number
]
# Check to see if the supplied password has *all* of the desired
# characteristics:
return all(
characteristic(password)
for characteristic in characteristics
)
def length(n=10):
# Ensure password has at least N characters
def check(password):
return len(password) >= n
return check
def lower_case(n=1):
# Ensure password has at least N lower case characters
def check(password):
count = 0
for char in password:
if char.islower():
count += 1
if count == n:
return True
return False
return check
def upper_case(n=1):
# Ensure password has at least N upper case characters
def check(password):
count = 0
for char in password:
if char.isupper():
count += 1
if count == n:
return True
return False
return check
def number(n=1):
# Ensure password has at least N numbers
def check(password):
count = 0
for char in password:
if char.isdigit():
count += 1
if count == n:
return True
return False
return check
# Doesn't have any numbers:
>>> print(check_password('TopSecret'))
False
# Acceptable:
>>> print(check_password('TopSecret15'))
True
# Has lower case, upper case, and number, but it's not long enough:
>>> print(check_password('Ab1'))
False
Notes:
check
functions could be one-liners).Upvotes: 0
Reputation: 7037
Your logic is flawed it should look like this:
def check_password(s):
has_digit = False
has_lower = False
has_upper = False
for char in s:
if char.isdigit():
has_digit = True
if char.islower():
has_lower = True
if char.isupper():
has_upper = True
# if all three are true return true
if has_digit and has_upper and has_lower:
return True
else:
return False
Now, let's talk about what's wrong with your code.
def check_password(s):
for char in s:
if char.isdigit():
if char.islower(): # we only get to this check if char was a digit
if char.isupper(): # we only get here if char was a digit and lower
# it is not possible to get here
# char would have to be a digit, lower, and upper
return True
else:
return False
As an example let's look at TopSecret15, we start with T
isdigit
= False so we immediately return false for 'T'isdigit
would be true, but islower
would be false so again it returns falseDo you see how it is impossible for all three of these to be true for the same char?
Your code is equivalent to:
if char.isdigit and char.islower and char.isupper:
# this will never happen
Upvotes: 2
Reputation: 766
See this answer: https://stackoverflow.com/a/2990682/7579116 the best way to check if a password match all the requirements is by using a regex.
Upvotes: 0
Reputation: 2971
The reason this doesn't work is that for any given character, it first checks if it's a digit, then if it's lower, then if it's upper. Obviously, one character cannot be all three of these at once. You instead want to check each character to see if it's a digit, lowercase, or uppercase, and then flip a boolean value like has_upper
. Then, after the for
loop, you'll check to see if all of the boolean values are true.
Upvotes: 1