Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require one out of two keyword arguments

Tags:

python

I have a function which can take keyword arguments and I want to require one of them. Let's say dollar and euro and I want one and only one of them. Right now, I'm doing it like this (exemplification) but I find it quite complex. Is there any other better way?

def set_value(country, **kargs):

    if len(kargs) == 1:
        if kargs.keys()[0] == 'dollar':
            pass # do something
        elif kargs.keys()[0] == 'euro':
            pass # do something
        else:
            raise ValueError('One keyword argument is required: dollar=x or euro=x')
    else:
        raise ValueError('One keyword argument is required: dollar=x or euro=x')

Thanks!

like image 989
Diego Herranz Avatar asked Oct 01 '13 18:10

Diego Herranz


People also ask

How do you force keyword arguments in Python?

However, in Python 3, there is a simple way to enforce it! By adding a * in the function arguments, we force all succeeding arguments to be named. E.g. by having the first argument be * , we force all arguments to be named.

How do you specify a keyword arguments in function?

Keyword arguments (or named arguments) are values that, when passed into a function, are identifiable by specific parameter names. A keyword argument is preceded by a parameter and the assignment operator, = . Keyword arguments can be likened to dictionaries in that they map a value to a keyword.

How do you pass multiple keyword arguments in Python?

**kwargs: Pass multiple arguments to a function in Python If so, use **kwargs . **kwargs allow you to pass multiple arguments to a function using a dictionary. In the example below, passing **{'a':1, 'b':2} to the function is similar to passing a=1, b=1 to the function.

What is the utility of 1 default arguments II keyword arguments?

There are two advantages – one, using the function is easier since we do not need to worry about the order of the arguments. Two, we can give values to only those parameters to which we want to, provided that the other parameters have default argument values.


1 Answers

You can use set operations on the dictionary keys view:

if len(kargs.viewkeys() & {'dollar', 'euro'}) != 1:
    raise ValueError('One keyword argument is required: dollar=x or euro=x')

In Python 3, use kargs.keys() instead.

Demo of the different outcomes of the set operation:

>>> kargs = {'dollar': 1, 'euro': 3, 'foo': 'bar'}
>>> kargs.viewkeys() & {'dollar', 'euro'}
set(['dollar', 'euro'])
>>> del kargs['euro']
>>> kargs.viewkeys() & {'dollar', 'euro'}
set(['dollar'])
>>> del kargs['dollar']
>>> kargs.viewkeys() & {'dollar', 'euro'}
set([])

In other words, the & set intersection gives you a set of all keys present in both sets; both in the dictionary and in your explicit set literal. Only if one and only one of the named keys is present is the length of the intersection going to be 1.

If you do not want to allow any other keyword arguments besides dollar and euro, then you can also use proper subset tests. Using < with two sets is only True if the left-hand set is strictly smaller than the right-hand set; it only has fewer keys than the other set and no extra keys:

if {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}:
    raise ValueError('One keyword argument is required: dollar=x or euro=x')

On Python 3, that can be spelled as:

if set() < kargs.keys() < {'dollar', 'euro'}:

instead.

Demo:

>>> kargs = {'dollar': 1, 'euro': 3, 'foo': 'bar'}
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False
>>> del kargs['foo']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False
>>> del kargs['dollar']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
True
>>> del kargs['euro']
>>> {}.viewkeys() < kargs.viewkeys() < {'dollar', 'euro'}
False

Note that now the 'foo' key is no longer acceptable.

like image 69
Martijn Pieters Avatar answered Sep 20 '22 02:09

Martijn Pieters