Password Validation in Python I coded a python solution for the question below. I am after the fastest solution. Also, I would be grateful if you could point out parts that are not pythonic / inefficient.


  Question: A website requires the users to input username and password
  to register. Write a program to check the validity of password input
  by users. Following are the criteria for checking the password:
  
  
  At least 1 letter between [a-z]
  At least 1 number between [0-9]
  At least 1 letter between [A-Z]
  At least 1 character from [$#@]
  Minimum length of transaction password: 6
  


import warnings
password = 'P@ss1234'
def check_number(s):
    ''' Check whether the input string is a digit. '''
    try: 
        int(s)
        return True
    except:
        # do not catch error
        return False
def check_validity(pw):
    ''' Return True if input pw is valid, and return False if invalid.'''
    special_chars = ['$','#','@']
    if isinstance(pw,str): pw=list(pw) # I could have appointed to a diff var name
    else: warnings.warn('Password has to be a string object.')
    res = False
    valid_dict={'small_let':False, 'num':False, 'special_chars':False, 
                'cap_let':False, 'len':False } # is using a dict efficient?
    if len(pw)&gt;= 6: valid_dict['len']=True
    for i in pw:
        if i.islower(): valid_dict['small_let'] = True
        if i in special_chars: valid_dict['special_chars'] = True
        if i.isupper(): valid_dict['cap_let'] = True
        if not valid_dict['num']:  valid_dict['num'] = check_number(i)
    if all(valid_dict.values()): res = True
    return res

print check_validity(password)


P.S: I am not interested in a module / package that can do this faster or more securely. There does not actually exist a website or a username, this is a simple coding exercise.

Also, linked to this post.
You shouldn't use bare excepts, this is as it can prevent things like KeyboardInterrupt.
That's just bad.
password is a better variable name than pw, at first I was quite confused about what it was.
You can return early if you know the password is not valid.
This can save you a lot of checks in your program.
Your program goes through each character and checks if it's one of the four valid groups.
Instead you can check if it shares any items with that set.
If it doesn't it's not valid.
You're creating warnings un-neededly, currently, excluding the cast, the functionality is the same if it's a list.
Instead of a warning you should either raise an error, or return.

This is as if I pass ['P', 'a', '$', '2', 1, 2] it probably shouldn't return True, which it might on a different implementation.
Instead you can either hard limit your input to strings, or check if the contents of the input are strings. Or both.


In short, just change password to a set, and use &amp; with the groups it needs to be a part of.
This can remove the need to make the function check_number, and makes the code much more readable:

import string

def check_validity(password):
    ''' Return True if input pw is valid, and return False if invalid.'''
    if isinstance(password, str) \
            or not all(isinstance(c, str) for c in password):
        return False

    if len(password) &lt; 6:
        return False

    password = set(password)
    checks = [
        set(string.ascii_lowercase),
        set(string.ascii_uppercase),
        set(string.digits),
        {'$', '#', '@'},
    ]

    for check in checks:
        if not check &amp; password:
            return False
    return True

print check_validity('P@ss1234')