0

So let's say I have a function which takes two params, but at least one of them should be present:

 def foo_bar(foo = None, bar = None):

The problem is that both of them are optional, but in practice either foo or bar will be passed in. Right now I check for existence in the function like this:

do_this() if foo else do_that() sort of logic.. 

But I don't like the way this looks.

What's the best way to deal with this?

5
  • Have you thought about using keyword args instead? Commented Jul 26, 2012 at 17:18
  • 3
    @JoelCornett: The OP is using keyword arguments already. Commented Jul 26, 2012 at 17:18
  • @SvenMarnach: I meant **kwargs. Commented Jul 26, 2012 at 17:21
  • Would it be an error for both arguments to be None, or just unlikely? Commented Jul 26, 2012 at 17:21
  • @SvenMarnach: Those appear to be positional args with default values. Commented Jul 26, 2012 at 17:22

4 Answers 4

4

I think you've got it right. The params can also be read with the kwargs syntax:

def foo(*args, **kwargs):
    if 'foo' in args:
        do_this()
    elif 'bar' in args:
        do_that()
    else:
        raise ValueError()

OR, you could do something like this:

def foo(param, flag):
    if flag == 'foo':
        do_this()
    elif flag == 'bar':
        do_that()
    else:
        raise ValueError()

Either way should be fine. Hope this helps

Sign up to request clarification or add additional context in comments.

3 Comments

not sure what's better about the **kwargs version compared to the original... I like the param/flag version though.
It works as flags like you said. It also works in allowing params to be passed in any (essentially orderless) order. The key/value pairs of the dict become how params are passed (and parsed), as opposed to the positional passing of parameters which is what would happen if the function signature was def foo(param1, param2, …). Also, check out the answers to this other SO question
I know how that works, but with a signature like def foo(x,y,z) you can also pass the parameters in any order by name (foo(z=1, x=2, y=3)), which is why I'm not sure there's any advantage to the **kwargs signature in this case.
2

3 ways to deal with it come to mind:

If you can switch behavior based upon some rules about the parameters (one is of one type, one is of another, one matches 1 regex, 1 another, etc), pass one parameter and figure out what to do inside the function.

Create 2 functions that both call some other function for their shared behavior but handle the foo and bar specific cases independently.

Pass 1 data value and another control value:

def foo_bar(val, control):
    if control=='foo':
        #Do foo stuff
    elif control=='bar':
        #Do bar stuff

Comments

2

You are on the right track, but What if both are specified? What I usually do is:

def some_func(foo=None, bar=None):
    "either one, or neither, but not both, are allowed"
    if foo is not None and bar is not None:
        raise TypeError("cannot specify both 'foo' and 'bar'")
    if foo is not None:
        pram = foo
    elif bar is not None:
        pram = bar
    else:
        pram = None  # or whatever

Simple, easy to understand.

Comments

0

Why not simply check to see which one is None, and say that the other one must be the one that is present?

if foo == None:
    do bar()
elif bar == None:
    do foo()
else:
    throwUpYourHandsInFrustration()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.