简体   繁体   中英

function not recognizing args and kwargs

I am trying to define a function like so:

def get_event_stats(elengths, einds, *args, **kwargs):

    master_list = []

    if avg:
        for arg in args:
             do stuff...
    if tot:
        for arg in args:
             do stuff...

    return master_list

I would like elengths and einds to be fixed positional args (these are just arrays of ints). I am trying to use the function by passing it a variable length list of arrays as *args and some **kwargs, in this example two (avg and tot), but potentially more, for example,

avg_event_time = get_event_stats(event_lengths, eventInds, *alist, avg=True, tot=False)

where

alist = [time, counts]

and my kwargs are avg and tot, which are given the value of True and False respectively. Regardless of how I've tried to implement this function, I get some kind of error. What am I missing here in the correct usage of *args and **kwargs?

If you meant that avg and tot should be passed in as keyword args, like in your example get_event_stats(..., avg=True, tot=False) then they are populated in kwargs . You can look them up in the kwargs dict using a key lookup (like kwargs['avg'] .

However if they are not present at all, then that will give a key error, so use it with the dict.get() method: kwargs.get('avg') which returns None if it is not present, which is boolean False . Or use kwargs.get('avg', False) if you explicitly want a False if it's not present.

def get_event_stats(elengths, einds, *args, **kwargs):

    master_list = []

    if kwargs.get('avg'):
        for arg in args:
             do stuff...
    if kwargs.get('tot'):
        for arg in args:
             do stuff...

    return master_list

**kwargs creates a dict , it doesn't inject arbitrary names into your local namespace. If you want to look for whether a particular keyword was passed, you can't test if avg: (there is no variable named avg ), you need to check if avg is in the dict , eg if 'avg' in kwargs: , or to check both existence and "truthiness", so passing avg=False is equivalent to not passing it at all, test if kwargs.get('avg'): (using kwargs.get('avg') ensures no exception is thrown if avg wasn't passed at all, unlike if kwargs['avg']: ).

Note: You should really move to Python 3 if at all possible. It makes writing this function much more obvious and clean, as you could avoid the need for kwargs completely, and verify no unrecognized keyword arguments were passed by just defining the function as:

def get_event_stats(elengths, einds, *args, avg=False, tot=False):
    master_list = []

    if avg:
        for arg in args:
             do stuff...
    if tot:
        for arg in args:
             do stuff...

    return master_list

Note how the body of the function you already wrote works without modification if you explicitly name your keyword arguments after the positional varargs, making your code far more self-documenting (as well as more efficient, and with better self-checks; the clean Py3 code will error out informing you of the unrecognized argument if you pass avrg=True to it, while the **kwargs approach would require explicit checks for unknown arguments that would slow you down and bloat the code.

The closest you could get to the Py3 error-checks with minimal overhead and similar correctness/readability would be:

def get_event_stats(elengths, einds, *args, **kwargs):
    master_list = []
    # Unpack the recognized arguments (with default values), so kwargs left should be empty
    avg = kwargs.pop('avg', False)
    tot = kwargs.pop('tot', False)

    # If any keywords left over, they're unrecognized, raise an error
    if kwargs:
        # Arbitrarily select alphabetically first unknown keyword arg
        raise TypeError('get_event_stats() got an unexpected keyword argument {!r}'.format(min(kwargs)))

    if avg:
        for arg in args:
             do stuff...
    if tot:
        for arg in args:
             do stuff...

    return master_list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM