Question

Is there any difference between the following?

print(x if x else 'no x available')
# compared to:
print(x and x or 'no x available')
Was it helpful?

Solution 2

In practice they are the same; in theory they are different, but only when the __bool__ method has side effects:

>>> class Weird:
    state = False
    def __bool__(self):
        self.state = not self.state
        return self.state


>>> x = Weird(); print(x if x else 'no x available')
<__main__.Weird object at 0x0000000003513160>
>>> x = Weird(); print(x and x or 'no x available')
no x available

If you run into this theoretical case you have worse problems to worry about.

Also note that:

>>> x = Weird(); print(x or 'no x available')
<__main__.Weird object at 0x00000000035071D0>

so Klass Ivan's answer is technically wrong.

Bottom line, use the if expression as that expresses what you mean much more clearly.

OTHER TIPS

Both lines are same as:

print(x or 'no x available')

About second alternative: Always keep in mind, that according to operator precedence and is evaluated first, so it first calculates x and x, which is totally useless - it equals x

Running this:

import dis
def f1():
  print(x if x else 'no x available')
def f2():
  print(x and x or 'no x available')
def f3():
  print(x or 'no x available')
dis.dis(f1)
dis.dis(f2)
dis.dis(f3)

We get, for f1:

  4           0 LOAD_GLOBAL              0 (x)
              3 POP_JUMP_IF_FALSE       12
              6 LOAD_GLOBAL              0 (x)
              9 JUMP_FORWARD             3 (to 15)
        >>   12 LOAD_CONST               1 ('no x available')
        >>   15 PRINT_ITEM          
             16 PRINT_NEWLINE       
             17 LOAD_CONST               0 (None)
             20 RETURN_VALUE        

For f2:

  7           0 LOAD_GLOBAL              0 (x)
              3 POP_JUMP_IF_FALSE       12
              6 LOAD_GLOBAL              0 (x)
              9 JUMP_IF_TRUE_OR_POP     15
        >>   12 LOAD_CONST               1 ('no x available')
        >>   15 PRINT_ITEM          
             16 PRINT_NEWLINE       
             17 LOAD_CONST               0 (None)
             20 RETURN_VALUE        

For f3 taken from @Klass Ivan:

 10           0 LOAD_GLOBAL              0 (x)
              3 JUMP_IF_TRUE_OR_POP      9
              6 LOAD_CONST               1 ('no x available')
        >>    9 PRINT_ITEM          
             10 PRINT_NEWLINE       
             11 LOAD_CONST               0 (None)
             14 RETURN_VALUE        

So f1 and f2 are not the same. They do have different logic, as Klass mentions. f3 and f1 versions also differ, even though logically they should be equivalent, f3 spares some operations.

Code-wise I think this has been covered but I would note that what you're doing here is linguistically very different and is likely to have a very different effect on people reading your code, and perhaps the subconscious of those merely navigating front-end of the website (people with even a passing involvement with or knowledge of code may find themselves psychologically influenced by the underlying 'symbolic links'*). To break this down further, let's consider a string value for x:

var x = "spoon";
print(x if x else 'no x available')
# compared to:
print(x and x or 'no x available')

It's still difficult to see exactly what will happen to "spoon" here, so to make things clearer we could just call our variable "hasSpoon" instead of assigning it a string (but you can believe we've assigned it a string of "spoon" too if you like...):

print(hasSpoon if hasSpoon is true else 'no hasSpoon available')
# compared to:
print(hasSpoon and hasSpoon or 'no hasSpoon available')

As we can see, in the first instance the logical reading would be that our metaphorical cutlery wielder has a spoon if they have a spoon, which I think we will probably agree on (and on the other hand they have the condition of not having a spoon available to them, rather than not actually having a spoon which is a little odd, but possible, but let's leave it aside for now.)

In the second expression the logical implication is rather that our theoretical diner has a spoon and also has a spoon, which is tautological in a whole other way.

So, if you wanted to express to any would-be readers of the code, and also anyone who might be potentially influenced by it by-proxy, that people who have spoons are very likely to have spoons, and those that don't have the option to not have a spoon, you would use the first option. If, on the other hand, you wished to express that a particular person both has a spoon and has a spoon, or else they have the condition of not having a spoon open to them, you would use the second expression.

Or something.

*I use the term symbolically here, if you'll pardon the pun.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top