if statement – Python syntax for if a or b or c but not all of them

if statement – Python syntax for if a or b or c but not all of them

If you mean a minimal form, go with this:

if (not a or not b or not c) and (a or b or c):

Which translates the title of your question.

UPDATE: as correctly said by Volatility and Supr, you can apply De Morgans law and obtain equivalent:

if (a or b or c) and not (a and b and c):

My advice is to use whichever form is more significant to you and to other programmers. The first means there is something false, but also something true, the second There is something true, but not everything. If I were to optimize or do this in hardware, I would choose the second, here just choose the most readable (also taking in consideration the conditions you will be testing and their names). I picked the first.

How about:

conditions = [a, b, c]
if any(conditions) and not all(conditions):
   ...

Other variant:

if 1 <= sum(map(bool, conditions)) <= 2:
   ...

if statement – Python syntax for if a or b or c but not all of them

This question already had many highly upvoted answers and an accepted answer, but all of them so far were distracted by various ways to express the boolean problem and missed a crucial point:

I have a python script that can receive either zero or three command
line arguments. (Either it runs on default behavior or needs all three
values specified)

This logic should not be the responsibility of library code in the first place, rather it should be handled by the command-line parsing (usually argparse module in Python). Dont bother writing a complex if statement, instead prefer to setup your argument parser something like this:

#!/usr/bin/env python
import argparse

parser = argparse.ArgumentParser()
parser.add_argument(--foo, nargs=3, default=[x, y, z])
args = parser.parse_args()

print(args.foo)

And yes, it should be an option not a positional argument, because it is after all optional.


edited: To address the concern of LarsH in the comments, below is an example of how you could write it if you were certain you wanted the interface with either 3 or 0 positional args. I am of the opinion that the previous interface is better style (because optional arguments should be options), but heres an alternative approach for the sake of completeness. Note were overriding kwarg usage when creating your parser, because argparse will auto-generate a misleading usage message otherwise!

#!/usr/bin/env python
import argparse

parser = argparse.ArgumentParser(usage=%(prog)s [-h] [a b c]n)
parser.add_argument(abc, nargs=*, help=specify 3 or 0 items, default=[x, y, z])
args = parser.parse_args()
if len(args.abc) != 3:
    parser.error(expected 3 arguments)

print(args.abc)

Here are some usage examples:

# default case
$ ./three_or_none.py 
[x, y, z]

# explicit case
$ ./three_or_none.py 1 2 3
[1, 2, 3]

# example failure mode
$ ./three_or_none.py 1 2 
usage: three_or_none.py [-h] [a b c]
three_or_none.py: error: expected 3 arguments

Leave a Reply

Your email address will not be published. Required fields are marked *