简体   繁体   中英

Paired optional arguments

I have a function with two optional arguments that I'd like to require either both, or neither to be specified. What is the preferred way of enforcing this in Python? My current approach seems a bit awkward:

def myfunc(data, opt1=None, opt2=None):
    if opt1 is None or opt2 is None:
        if not (opt1 is None and opt2 is None):
            raise ValueError("Must specify both opt1 and opt2 or neither.")      

This question: Python Optional Argument Pair is the same as mine, but in the context of argparse specifically; I am interested in the default way of doing this within functions generally.

The simplified condition you're looking for is:

if (opt1 is None) != (opt2 is None):
    raise ...

This condition is true if both arguments don't fall on the same side of is None together.

You could define a function

def ensure_both_or_neither(opt1, opt2):
    if opt1 is None or opt2 is None:
        if not (opt1 is None and opt2 is None):
            raise ValueError("Must specify both opt1 and opt2 or neither.") 

Then call it from your function:

def myfunc(data, opt1=None, opt2=None):
    ensure_both_or_neither(opt1, opt2)

I don't think it's any better than your orignal approach, but it is slightly more explicit / readable?

def myfunc(data, *args):
    if(len(args)==0 or len(args)==2):
        #do something

Is how I would do it

This also enables you to have as many arguments as you want, and only if none or 2 are used the code is run

You can use the fact that a set removes duplicates:

def myfunc(data, opt1=None, opt2=None):
    if len({opt1 is None, opt2 is None}) - 1:
        raise ValueError("Must specify both opt1 and opt2 or neither.")

You could do it for any number of parameters:

def myfunc(data, *args):
    if len({arg is None for arg in args}) - 1:
        raise ValueError("Must specify all parameters or none.")

If you need neither or both, don't accept two separate arguments; accept a single optional tuple and document it. Don't give the user the opportunity to only provide one.

def myfunc(data, opts=None):
    """blah blah blah

    opts, if given, should be a tuple with two values, neither None.
    """
    opt1, opt2 = opts if opts is not None else (None, None)

You could make the default (None, None) , which would simplify the unpacking inside your function ( x1, x2 = opts ), but at the expense of cluttering your function's signature.

(In reality, opts can be an iterable with 2 elements, but if the user makes a call like myfunc(data, "hi") and expects opt1 to be hi and opt2 to be None , that's his fault, not yours.)

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