2

In some_function, I have two parameters freq and frac, I don't want users to specify both of them, or none of them. I want them to specify just one of them.

Here is the working code:

def some_function(freq=False, frac=False):
    if (freq is False) & (frac is False):
        return (str(ValueError)+': Both freq and frac are not specified')
    elif (freq is not False) & (frac is not False):
        return (str(ValueError)+': Both freq and frac are specified')
    elif (freq is not False) & (frac is False):
        try:
            print ('Do something')
        except Exception as e:
            print (e)
    elif (freq is False) & (frac is not False):
        try: 
            print ('Do something else')
        except Exception as e:
            print (e)
    else: return (str(ValueError)+': Undetermined error')

Are there better and less verbose practices to express this in Python?

jpp
  • 159,742
  • 34
  • 281
  • 339
KubiK888
  • 4,377
  • 14
  • 61
  • 115

3 Answers3

2

You can use assert before your if statement. The type of your inputs is unclear; in general, I would use None if I know this isn't a valid input.

def some_function(freq=None, frac=None):

    freq_flag = freq is not None
    frac_flag = frac is not None

    assert freq_flag + frac_flag == 1, "Specify exactly one of freq or frac"

    if freq_flag:
        print('Do something')

    elif frac_flag:
        print('Do something else')
jpp
  • 159,742
  • 34
  • 281
  • 339
2

There's a lot you're doing wrong here. You can test not frac instead of frac is False, you should be using logical and instead of bitwise &, and you should be raising those ValueErrors, not returning them:

def some_function(freq=False, frac=False):
    if not freq and not frac:
        raise ValueError('Both freq and frac are not specified')
    elif freq and frac:
       raise ValueError('Both freq and frac are specified')
    elif freq:      
        print ('Do something')
    else:
        print ('Do something else')

Generally though, you're looking for one of two options. Why not require that the user pass a single boolean, then represents freq if True and frac if False?

def some_function(freq):
    if freq: 
        print ('Do something')
    else:
        print ('Do something else')
Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96
  • If the same argument doubles for `freq` OR `fraq`, you still need an argument `flag` to indicate whether that first argument is `freq` or `fraq`. I think the use case is not with Booleans but with an actual value (number, string, or list) instead, for only one of the two. – Jongware Nov 09 '18 at 15:55
  • True, the real user case is to have None or actual float value. But thanks very much for pointing out my errors in coding (never cease to learn the nuances). – KubiK888 Nov 09 '18 at 16:00
0

Dead simple pythonic solution: use two distinct functions (they can eventually just be facades for the real one):

__all__ = ["freqfunc", "fracfunc"]

# private implementation
def _somefunc(freq=False, frac=False):
   # your code here

def freqfunc(freq):
    return _somefunc(freq=freq)

def fraqfunc(frac):
    return _somefunc(frac=frac)

Now there might be better solutions but it's impossible to tell without more details...

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118