24

Which of the following if statements is more Pythonic?

if not a and not b:
    do_something

OR

if not ( a or b ):
    do something

Its not predicate logic so I should use the Python key words because its more readable right?

In the later solution more optimal than the other? (I don't believe so.)

Is there any PEP-8 guides on this?

Byte code of the two approaches(if it matters):

In [43]: def func1():
    if not a and not b:
        return
   ....:     
   ....:     

In [46]: def func2():
    if not(a or b):
        return
   ....:     
   ....:     

In [49]: dis.dis(func1)
  2           0 LOAD_GLOBAL              0 (a)
              3 UNARY_NOT           
              4 JUMP_IF_FALSE           13 (to 20)
              7 POP_TOP             
              8 LOAD_GLOBAL              1 (b)
             11 UNARY_NOT           
             12 JUMP_IF_FALSE            5 (to 20)
             15 POP_TOP             

  3          16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        
        >>   20 POP_TOP             
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        

In [50]: dis.dis(func2)
  2           0 LOAD_GLOBAL              0 (a)
              3 JUMP_IF_TRUE             4 (to 10)
              6 POP_TOP             
              7 LOAD_GLOBAL              1 (b)
        >>   10 JUMP_IF_TRUE             5 (to 18)
             13 POP_TOP             

  3          14 LOAD_CONST               0 (None)
             17 RETURN_VALUE        
        >>   18 POP_TOP             
             19 LOAD_CONST               0 (None)
             22 RETURN_VALUE        
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
nialloc
  • 805
  • 7
  • 17
  • What do you mean about using Python keywords? You're using Python keywords in both cases. – sepp2k Oct 22 '12 at 13:36
  • Apologies I meant the not() syntax. In my case some stuff will look worse if I use not( a or b) syntax. Hence I'm leaning more toward the first snippet of code – nialloc Oct 22 '12 at 13:44
  • I tend to think that 'do_something' and 'do something' (no underscore) may be different – Uri London Oct 22 '12 at 14:00
  • 2
    Since this is about what is the most "Pythonic" it seems strange to include the bytecode... also, `a` and `b` may include function calls. – Andy Hayden Oct 22 '12 at 14:29
  • The title doesn't make sense. "De Morgan's Law" isn't either of those versions of the code; it is the logical rule that tells you *that they will do the same thing*. The law can't be assessed as "pythonic" or not; it's a brute fact of logic, which is true whether you like it or not. I assume the intended question is about which way of writing the code is clearer. – Karl Knechtel Jul 04 '22 at 00:09

6 Answers6

15

I'd say whichever is easier for you to read, depending on what a and b are.

Mike Corcoran
  • 14,072
  • 4
  • 37
  • 49
  • We are being instructed to change a lot of code because someone believes the latter is more readable. Its python 2.6 so the any and all functions can be used for more complex statements but when two items are being compared does it matter. I think the first reads easier but I have no case to say the other isn't. . . Lots of code changes and unit test to be run!! – nialloc Oct 22 '12 at 13:34
  • a lot of times stuff like this is more preference; or sometimes you need to follow conventions already in place. if you're working on a shared code base, and a few people prefer one over the other, i'd go with the convention. it makes the overall code base much more coherent. – Mike Corcoran Oct 22 '12 at 13:42
15

I think both your examples are equally readable, however if I wanted to "push the boat out" on readability I would go with:

not any((a, b))

Since to me this reads much more like English, and hence is the most Pythonic.

Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
  • Huh. +1 for surprising me -- I don't think I've ever used this pattern in my code, and I can't quite explain why. It's true I tend to avoid `((` and `))` where I can, but it's not too bad here. – DSM Oct 22 '12 at 13:55
  • 9
    This will, however, fully evaluate both `a` and `b`, which regular Boolean operators will not. Not a reason not to use it, but something to be aware of. – kindall Oct 23 '12 at 17:11
  • While `any` and `all` are good tools to know about, this doesn't actually address the elephant in the room. The same logical principles allow you to transform between `not any((a, b))` and `all((not a, not b))`. – Karl Knechtel Jul 04 '22 at 00:10
3

Which to use? Whichever is more readable for what you're trying to do.

As to which is more efficient, the first one does do an extra not so it is technically less efficient, but not so you'd notice in a normal situation.

kindall
  • 178,883
  • 35
  • 278
  • 309
1

They are equivalent and whether one is faster than the other depends on circumstances (the values of a and b).

So just choose the version which you find most readable and/or understandable.

Roy Dictus
  • 32,551
  • 8
  • 60
  • 76
1

I personally like the Eiffel approach, put into pythonic form

if a and then b: dosomething

if a and b: dosomething

The first approach differs from the second if a is false. It doesn't evaluate b in the first case, in the second it does.

The or equivalent is "or else"

http://en.wikipedia.org/wiki/Short-circuit_evaluation

and/or are eager.

and then/or else short circuit the evaluation

The nice thing about the syntax is that it reads well, and it doesn't introduce new keywords.

Nickle
  • 367
  • 3
  • 5
  • In Python, you can get much the same effect as the "eager" operators by adding or multiplying Booleans. e.g. `bool(a) + bool(b)` is an "eager" `or` (always evaluates both `a` and `b`) and `bool(a) * bool(b)` is "eager" `and`. Of course, the usual `and` and `or` short-circuit. – kindall Oct 22 '12 at 15:56
0

For a piece of code to be Pythonic, it must be both pleasing to the reader in and of itself (readable) and in the context of its surroundings (consistent). Without having the context of this piece of code, a good opinion is hard to give.

But, on the other hand... If I were being Pythonic in my opinion giving I would need to operate consistently with my surroundings, which seem not to take context into consideration (e.g. the OP).

The top one.

vrume21
  • 561
  • 5
  • 15