If (foo or bar or baz) - None:

I refactored some pretty cruel code and came across the following pretty odd construct:

#!/usr/bin/env python2.7 # ... if (opts.foo or opts.bar or opts.baz) is None: # (actual option names changed to protect the guilty) sys.stderr.write("Some error messages that these are required arguments") 

... and I was wondering if this could ever make any conceivable meaning.

I changed it to something like:

 #!/usr/bin/env python2.7 if None in (opts.foo, opts.bar, opts.baz): # ... 

I started the interpreter and actually tried the first construct ... it only works if the values ​​are false and the last of these false values ​​is None. (In other words, the CPython implementation returns the first true or last false value from the expression chain or ).

I still suspect that the correct code should use either the built-in elements any () or all () that were added 2.5 (2.7 is already required for this code). I'm not sure what the preferred / intended semantics are as I am just starting out on this project.

So, are there any cases where this source code would make sense?

+8
python styles correctness
source share
4 answers

Short circuiting causes foo or bar or baz return the first of three values, which is logical-true, or the last value if all values ​​are boolean-false. Thus, it basically means "if everything is false, and the last is None."

Your modified version is a little different. if None in (opts.foo, opts.bar, opts.baz) , for example, will go into the if block, if opts.foo is None and the other two are 1, while the original version will not (because None or 1 or 1 will be evaluated to 1, which is not None). Your version will go into if if any of the three is None, regardless of the other two, while the original version will go into if only if the last is None and the other two are any booleans.

Which of the two versions you want depends on how the rest of the code is structured and what values ​​the parameters can have (in particular, whether they can have logical values ​​other than None, such as False or 0 or an empty string). Intuitively, your version seems more reasonable, but if there are tricks in the code like this in it, you never know which corner cases may occur.

+5
source share

This behaves this way because or is a short circuit operator, details are in the docs . So your first if is:

 if opts.baz is None 

We could guess what the author of this code expected. I think that, as you already mentioned, he was thinking about using not all([opts.foo, opts.bar, opts.baz]) .

+5
source share

I would prefer

  if any(i is None for i in (opts.foo, opts.bar, opts.baz)) 

because it accurately expresses the intended purpose.

Oto

 not all([opts.foo, opts.bar, opts.baz]) 

checks fake, not None .

The source code does not make sense; it seems that someone did not know what they were doing.

0
source share

try both codes:

 In [20]: foo = True In [22]: bar = None In [23]: baz = None In [24]: foo or bar or baz Out[24]: True In [25]: (foo or bar or baz) is None Out[25]: False In [28]: ((foo or bar or baz) is None) == (None in (foo, bar, baz)) Out[28]: False 

You can see that your rewriting file does not match the source code.

Your first condition only returns True when all your variables are None

 In [19]: (None or None or None) is None Out[19]: True 

so you can rewrite your first condition:

 if foo == bar == bar == None: 
0
source share

All Articles