0

So here is my code:

def formateUserData(FirstName = None, MiddleName = None, LastName = None, DOB = None, Gender = None):
    formatedUserData = {}
    dataFieldKeys = ['First Name', 'Middle Name', 'Last Name', 'DOB', 'Gender']
    dataFieldValues = [FirstName, MiddleName, LastName, DOB, Gender]

    for key, value in zip(dataFieldKeys, dataFieldValues):
        if value: formatedUserData[key] = value

    return formatedUserData

As you can see, the keyword arguments has to be repeated 3 times (first in line 1, second in line 3 and third in line 4). Is there a way I could do the same thing without by just storing the keyword arguments once? Maybe by using some way to iterate through the keyword arguments if that possible? BTW, I'm looking to not use **kwargs.

piny
  • 153
  • 4
  • Have a look at `locals()` or other answers as mentioned here: https://stackoverflow.com/questions/582056/getting-list-of-parameter-names-inside-python-function – ScootCork Feb 02 '21 at 21:37
  • 2
    You can pass an object insted of multiple args and then itarate on its attributes – idan ovadia Feb 02 '21 at 21:38
  • The usual way here would be to level-up the abstraction, making a model class which has attributes for those fields. Then you just pass one instance, `user`, when you call this function. – wim Feb 02 '21 at 21:48

2 Answers2

1

maybe this scratch inspires you to condsider dataclasses which I find very handy

from dataclasses import dataclass, fields
from datetime import date
from typing import Literal, Optional

@dataclass
class User:
    first_name: Optional[str] = None
    middle_name: Optional[str] = None
    last_name: Optional[str] = None
    dob: Optional[date] = None
    gender: Optional[Literal['male', 'female']] = None


def not_none_dict(user: User) -> dict:
    not_none = {}
    for field in fields(user):
        value = getattr(user, field.name)
        if value:
            not_none[field.name] = value
    return not_none

print(
    not_none_dict(User(
        first_name='Joe',
        last_name='Doe'
    ))
)
>>> {'first_name': 'Joe', 'last_name': 'Doe'}
Raphael
  • 1,731
  • 2
  • 7
  • 23
0

For my point of view the shortest solution is to use locals():

def formateUserData2(FirstName = None, MiddleName = None, LastName = None, DOB = None, Gender = None):
    return {k:v for k,v in locals().items() if v}

But this solution don't consider the change of labels, so a binding is required

def formateUserData(FirstName = None, MiddleName = None, LastName = None, DOB = None, Gender = None):
    binding = {'First Name':FirstName, 
               'Middle Name':MiddleName,
               'Last Name':LastName,
               'DOB':DOB,
               'Gender':Gender}
    return {k:v for k,v in binding.items() if v}

Use an explicit binding is a good practice, because it clarify what is your expectation.

Glauco
  • 1,385
  • 2
  • 10
  • 20