3

I have a function clans(), that accepts 8 arguments. I need to add key and value pair to dictionary if argument is not None. There is my solution:

def clans(self, name: str = None, warFrequency: str = None, location: str = None,
            minMembers: int = None, maxMembers: int = None,
            minClanPoints: int = None, minClanLevel: int = None,
            labels: list[str] = None):
    params = {} # <- the dictionary to add to

    # very much if-conditions
    if name is not None:
        params['name'] = name
    if warFrequency is not None:
        params['warFrequency'] = warFrequency
    ... # <- other function arguments and if conditions
    if labels is not None:
        params['labels'] = labels
    
    return params

I think it is not the most optimal solution due to the large amount of code and poor readability, how can I improve that code? I have an idea like (but I dont know how to realize it):

params = {}
for arg in args: # <- args is list of function arguments
    if arg is not None:
        params[arg.key()] = arg.value() # <- arg.key() is argument name, arg.value() is value
bone_appettit
  • 105
  • 1
  • 6
  • if you have a list of keys and a list of values you can do `dict(zip(myKeys, myValues))` so you don't even need the loop. Now instead of clans accepting 8 parameters, make it accept a list with the value of the parameters, that will be your myValues list. myKeys list is just a static list that you can create inside the function. –  Feb 10 '22 at 16:34
  • @SembeiNorimaki, but i have only arguments..... and its values..... – bone_appettit Feb 10 '22 at 16:36
  • You already know how to add `key:value` to your dictionary if `value` is not `None`. You're actually asking how to get the arguments to a function in a list / dict / other iterable so that you don't have to explicitly specify their names in a bunch of `if` statements and can replace it with a loop. Please consider changing the title of your question to reflect your actual question. [Ask] – Pranav Hosangadi Feb 10 '22 at 16:58
  • Does this answer your question? [Get a list/tuple/dict of the arguments passed to a function?](https://stackoverflow.com/questions/2521901/get-a-list-tuple-dict-of-the-arguments-passed-to-a-function) This is why it is important to what you actually want to ask. – Pranav Hosangadi Feb 10 '22 at 16:59

2 Answers2

3

You might reconsider your strategy.

It's better to have a dictionary with a value of None for certain keys than an inconsistent dictionary where some keys might not exist.

So if you allow the function clans to be called with some missing info, just create that key and assign a value of none. That's perfectly fine since maybe you don't have that info at this point.

Later on you can have a function that updates those values, so you just reassign a dictionary key which already exist and you don't have to worry about those keys not existing.

So, I would do something like:

def clans(self, name: str = None, warFrequency: str = None, location: str = None,
            minMembers: int = None, maxMembers: int = None,
            minClanPoints: int = None, minClanLevel: int = None,
            labels: list[str] = None):
    myKeys = ["name", "warFrequency", "location", "minMembers", "maxMembers", "minClanPoints", "minClanLevel"]
    myValues = [name, warFrequency, location, minMembers, maxMembers, minClanPoints, minClanLevel]
    return dict(zip(myKeys, myValues))

This way you have a consistent dictionary. You will have to check later if some values are None.

Creating a dictionary with missing keys will force you to check if they exist in a future, instead not you can just check if they are None

So instead of doing

if "location" in myDict.Keys():

You just do

if myDict["location"] is not None:

-1

I have found an answer, based on @RJ Adriaansen solution, there it is (this will also check if argument is not self):

def clans(self, name: str = None, warFrequency: str = None, location: str = None,
                minMembers: int = None, maxMembers: int = None,
                minClanPoints: int = None, minClanLevel: int = None,
                labels: list[str] = None):
        params = {k: v for k, v in locals().items() if v is not None and v != self}
        #                                                            ^^^^^^^^^^^^^
        #                                                            small change
        return params

bone_appettit
  • 105
  • 1
  • 6