Taking advantage of *args and **kwargs

Posted by wocos on Thursday, March 9, 2023

Taking Advantage of *args and **kwargs

I consistently forget the option word I have included in a function and so I had to design a way to accept different keywords (option) names to trigger features with in a function.

As an example, assigning a color to a box border is very easy by just adding something like this to a function’s arguments:

def buildabox(msg, border_color="red"):
  """
  docs go here to put a box around msg
  """
  ...

But, if you accidenally call the function like this, it will fail. my_box = buildabox(“my message”, box_color=“white on back”): …

Or maybe you used this and it will fail again.. my_box = buildabox(“my message”, box_clr=“white on back”): …

So there is a way to deal with all of those possibilities using **kwargs and using the function kvarg_val() listed here below.

So instead of declaring each key-value pair we can do this:

def buildabox(msg, **kwargs):
  """
  docs go here to put a box around msg
  """
  box_clr = kvarg_val(["border_color", "border_clr", 'box_color', "box_clr"], kwargs, dflt="red")
  # now, if any key is used that is in that list box_clr reflect the value provided
  # and if none is provided then the default assignment of "red"
  ...

Now, what about a boolean value where you use a similar key word but not the stipulated var name. For example:

def buildabox(msg, display=False, **kwargs):
  """
  docs go here to put a box around msg
  options:
    - display: bool
  returns lines suitable for printing the returned box
  """
  box_clr = kvarg_val(["border_color", "border_clr", 'box_color', "box_clr"], kwargs, dflt="red")
  ...
  returns lines

If I call this function like this it will fail:

lines = buildabox("my message", 'print', box_clr="white"):

Unless I take advantage of *args and use the bool_val function below… like this

def buildabox(msg, *args, **kwargs):
  """
  docs go here to put a box around msg
  options:
    - display: bool
  returns lines suitable for printing the returned box
  """
  box_clr = kvarg_val(["border_color", "border_clr", 'box_color', "box_clr"], kwargs, dflt="red")
  display = bool_val(["display", "print", "prnt", "show"], args, kwargs, dflt=False)
  # Now this call will work:
  # buildabox(msg, 'show', box_color="yellow! on black") # or any key-name listed
  ...
  returns lines

There are probably better ways to do this but this works for me.

# #######################################
def kvarg_val(key, kwargs_d={}, *args, **kwargs):
    # ###################################
    """
    purpose: returns a value when the key in a key=value pair matches any key given
    NOTE: key can be a string or a list of strings
    option: dflt="Whatever default value you want"
    use: used in function to get a value from a kwargs ky=value pair
    - eg:
        def my_function(*args, **kwargs):
            txt_center = kvarg_val(["text_center", "txt_cntr", "txtcntr"], kwargs, dflt=1)
    - so if you call my_function(txt_center=99) then txt_center will be set to 99
    ---
    If any key in the list is set = to a value, that value is returned
    see: bool_val which process both args and kvargs and returns bool_val
    input key(string), kvargs_d(dictionary of key,vals), default(string; optional)
    purpose: return a value given by a key=value pair using a matching key (in key list if desired)
    options:
    -  key provided can be a string or a list of strings
    -  dflt="Whatever default value you want - can be a string, list, int, float... whatever" <-- this is optional, if not declared "" is returned
    if key in kvargs:
        return val
    else:
        return default
    returns str(key_val) or default_val(which is "" if none is provided)
    """
    """--== Init ==--"""
    required = False
    if "required" in args:
        required = True
    if 'required' in list(kwargs.keys()):
        required = True
    mydflt = ""
    if 'dflt' in kwargs:
        mydflt = kwargs['dflt']
    """--== Validate ==--"""
    if required:
        found_flag = False
        for my_k in kwargs_d.keys():
            if my_k in key:
                found_flag = True
        if not found_flag:
            dbug(f"A value for a key: {key} is required for this operation.", 'ask', 'boxed')
    """--== Init ==--"""
    my_val = mydflt
    if not isinstance(kwargs_d, dict):
        dbug(f"Supplied kwargs_d: {kwargs_d} MUST be a dictionary! Returning...")
        return
    """--== Convert ==--"""
    if isinstance(key, list):
        keys = key
    else:
        keys = [key]
    """--== Process ==--"""
    for k in keys:
        if k in kwargs_d:
            my_val = kwargs_d[k]
            if my_val == "False":
                my_val = False
            if my_val == "True":
                my_val = True
    return my_val
    # ### EOB def kvarg_val(key, kwargs_d={}): ### #

def bool_val(key_l, args_l, kvargs={}, **kwargs): # ####################################### """ purpose: look at args and kwargs with a list of possible option strings and return the default True or False requires: - key_l: str | list # this is the string or list of strings to check args and kwargs against options: - default | dflt: bool # the default value to return - opposite | opposites: str | list # a list of opposites eg: prnt = bool_val(["print", "prnt"], args, kwargs, dflt=True, opposites=['noprnt', 'no_prnt', 'no_print']) return True or False Notes: key_l can be a str or list args_l must be provided kvargs is optional used to see if a string or a list of stings might be declared true by being in args or seeing it has a bool value set in kvargs use: DBUG = bool_val('dbug', args, kvargs) or DBUG = bool_val(['dbug', 'DBUG'], args, kvargs) """ """–== Config ==–""" bool_v = kvarg_val(["default", "dflt"], kwargs, dflt=False) opposite_words = kvarg_val(['opposite', 'opposites'], kwargs, dflt=[]) """–== Validate ==–""" if not isinstance(opposite_words, list) and opposite_words != []: opposite_words = [opposite_words] """–== Convert ==–""" if isinstance(key_l, str): key_l = [key_l] # make it a list for k, val in kvargs.items(): if kvargs[k] == "False": kvargs[k] = False if kvargs[k] == "True": kvargs[k] = True """–== Init ==–""" opposite_b = False """–== Process ==–""" for key in key_l: if key in args_l: bool_v = True if key in kvargs: bool_v = kvargs[key] for word in opposite_words: if word in args_l: opposite_b = True if word in kvargs: # convert strings to boolean when needed if kvargs[word] == "False": kvargs[word] = False if kvargs[word] == "True": kvargs[word] = True if isinstance(kvargs[word], bool): opposite_b = kvargs[word] if opposite_b: bool_v = False return bool_v

Enjoy!


comments powered by Disqus