Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a dictionary of parameters from keyword arguments

I'm trying to generate a dict containing the names and the value of the non-None parameters current call. This very much feels like something that should be a built-in, but can't find anything that quite does it in the Python documentation.

For example, when

def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):

   # code to generate dict of non-`None` named arguments (see below)

   ...  # other things happen later

is called with the parameters foo(limit=5, lower_bound=100), I need the following dict: {limit=5, lower_bound=100}.

Is there something that conveniently does that for me?


Potential Solutions

So far, I have looked into the following, all of which seem flawed:

  1. Manually making lists (which has a downside of having more places to things to make changes if, for example, an argument has its name changed)
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    keys = ('limit', 'offset', 'lower_bound', 'upper_bound')
    values = (limit, offset, lower_bound, upper_bound)
    magic_dict = {k: v for k, v in zip(keys, values) if v is not None}
  1. locals() — link — which would need everything removed that shouldn't make it into the dictionary (i.e. the keys with the value of None). This also seems potentially error prone if variables definitions get added above the magic dictionary code, which would also need to be removed.
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    magic_dict = {k: v for k, v in locals().items() if v is not None}
  1. inspect's — link — signature and bind, which still requires would a list of the parameters
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    sig = signature(foo)
    sig_args = sig.bind(limit, offset, lower_bound, upper_bound).arguments
    magic_dict = {k: v for k, v in sig_args.items() if v is not None}

Other thoughts included making a class to make getattr available

It feels like I'm missing something obvious — feedback would be appreciated!


Someone suggested What is an elegant way to select all non-None elements from parameters and place them in a python dictionary?, whose responses are primarily "move to **kwargs". My initial reaction is that I would prefer to keep a specific list of arguments — is that bad logic by me? What is typical best practice with Python?

like image 812
user12394023 Avatar asked Sep 30 '21 18:09

user12394023


People also ask

How can arguments are passed as a dictionary?

Passing Dictionary as kwargs “ kwargs ” stands for keyword arguments. It is used for passing advanced data objects like dictionaries to a function because in such functions one doesn't have a clue about the number of arguments, hence data passed is be dealt properly by adding “**” to the passing type.

What symbols are needed in front of a parameter to create a dictionary from keyword arguments?

The ** symbol is used before an argument to pass a keyword argument dictionary to a function, this syntax used to successfully run the code when we don't know how many keyword arguments will be sent to the function. u can pass the object of Foo class in func foo as a parameter.

How do you create a dictionary from a list of keys and values?

Using zip() with dict() function The simplest and most elegant way to build a dictionary from a list of keys and values is to use the zip() function with a dictionary constructor.

Can you pass Kwargs as a dictionary?

Introduction to the Python **kwargs parametersWhen a function has the **kwargs parameter, it can accept a variable number of keyword arguments as a dictionary.


1 Answers

You can try using decorators:

def capture(func):
    capture.kwds = None
    def wrap(*args, **kwargs):
        capture.kwds = kwargs
        return func(*args, **kwargs)
    return wrap
    
@capture
def foo(limit=None, offset=None, lower_bound=None, upper_bound=None):
    return None

Now you can call:

>>> foo(limit=1, offset=2, lower_bound=3, upper_bound=4)
None
>>> capture.kwds
{'limit': 1, 'offset': 2, 'lower_bound': 3, 'upper_bound': 4}
like image 107
Sayandip Dutta Avatar answered Oct 03 '22 11:10

Sayandip Dutta