Search code examples
pythonpython-3.xfunctionkeyword-argumentcontrol-flow

Is there a pythonic way to control the flow depending on kwargs in a function?


i have register_users list that have list of user objects and every user object have password, username, email property i want to create a login function that get a **kwargs from input.

the kwargs input can be given to the function in 3 different ways.

  1. kwargs may have 3 keys username, password and email.

  2. kwargs may have 2 keys username or password.

  3. kwargs may have email or password.

in all the above we must check whether there is a user object in the register_user list whose information is the same as the given input or not.

And the question I have is What is the best way to determine how kwargs input is given?and how to do this with minimum use of if, ifelse?or a pythonic way to do this.

class User:
    def __init__(self, username, password, email):
        self.username = username
        self.email = email
        self.password = password


user1 = User("user1", "[email protected]", "test12345")
user2 = User("user2", "[email protected]", "test12345")

register_users = [user1, user2]

def login(**kwargs):
    pass # determine how kwargs is given to function and then check informations

login({"username": "user1", "email": "[email protected]", "password": "test12345"})
login({"username": "user1", "password": "test12345"})
login({"email": "[email protected]", "password": "test12345"})

Solution

  • Logically, you always need the password, and either the username or email. A pythonic way is to retrieve these fields from kwargs and take advantage of this to validate the input parameter. From there you can use getattr to retrieve either the username either the email from the user.

    
    
    def login(**kwargs):
         try:
             password = kwargs["password"]
             if "email" in kwargs:
                 auth_field, auth_value = "email", kwargs["email"]
             else:
                 auth_field, auth_value = "username", kwargs["username"]
    
         except KeyError:
             raise ValueError("Login requires password and either username or email")
    
         found_user = None
         for user in registered_users:
             if user.password == password and getattr(user, auth_field) == auth_value:
                 found_user = user
                 break
    

    I assume that this is just for Stackoverflow, but in a real system you probably won't want to store your users in a list, and actual password checking will be slightly more complicated


    EDITED to answer question in comment if we want to check either one of username/email, either both if they are both present

    
    def login(**kwargs):
         try:
             password = kwargs["password"]
             auth_fields = {}
             if "email" in kwargs:
                 auth_fields["email"] = kwargs["email"]
             if "username" in kwargs:
                 auth_fields["username"] = kwargs["username"]
    
         except KeyError:
             raise ValueError("Login requires password and either username or email")
    
         found_user = None
         for user in registered_users:
             if user.password == password and all([getattr(user, field) == value for field, value in auth_fields.items()):
                 found_user = user
                 break