4

I am looking at some code which apparently runs, as nobody has complained about it, but am well confused by what they have written:

if a and b is not None:
    # do something

I have always thought of the 'and' operator as something which returns True or False, now am starting to doubt myself.. What else would it return, a number.. It is probably not pythonic, but am I missing something - how can someone write something like that?

cardamom
  • 6,873
  • 11
  • 48
  • 102

5 Answers5

5

It means if a is Truthy and b is not None and not what you thought it meant i.e. a and b is Truthy

a = 999
b = None

if a and b is not None:
    print("a is True but b is None")
else:
    print("a is True and b is not None")
DirtyBit
  • 16,613
  • 4
  • 34
  • 55
2

The code above means:

If a (is truthy), AND b isn't None, then #do something.

Nick is tired
  • 6,860
  • 20
  • 39
  • 51
Thijs Kramer
  • 1,082
  • 8
  • 17
2

According to [Python 3]: Operator precedence (emphasis is mine):

The following table summarizes the operator precedence in Python, from lowest precedence (least binding) to highest precedence (most binding).

...
and                                                 Boolean AND
not x                                               Boolean NOT
in, not in, is, is not, <, <=, >, >=, !=, ==        Comparisons, including membership tests and identity tests
...

The fact that is not comes after and, means that it will be evaluated before and (both might not be evaluated at all, due to lazy evaluation - thanks @NickA for the comment), so the expression is equivalent to (adding parentheses for clarity):

if a and (b is not None):

Also, according to [Python 3]: Truth Value Testing:

Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below.

your if statement is perfectly OK (produces a bool).

Examples (using [Python 3]: class bool([x])):

>>> bool(0)
False
>>> bool(100)
True
>>> bool([])
False
>>> bool([0])
True
>>> bool(None)
False
>>> bool({})
False
>>> bool({1: 1})
True
>>> bool(None is not None)
False
>>> bool(1 is not None)
True
>>> bool(2 and 1 is not None)
True
CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • Thanks, those two links are very helpful. I wish people could just put in brackets though. That 'Operator precedence' table is worse than what we had to learn in arithmetic in school. I notice that PyCharm does not object if you do put in the (redundant) brackets, so it can't be bad style, not sure if it is good or bad. – cardamom Jan 09 '19 at 11:52
  • 1
    You're welcome. Well the operators precedence are in a table for every language (including the arithmetic), I'm not sure whether there is a user friendlier manner that they could be expressed as. I didn't see notes in the *PEP8* that would forbid redundant parentheses, but I think that it would make sense to have them where things are unclear. – CristiFati Jan 09 '19 at 12:04
1

In this code, you evaluate b is not None first, which is a boolean.

And then a is implicitly converted into a boolean (For a list/dict, False if it is empty. For a number, False if it is 0)

then and is evaluated which always return a boolean.

BlueSheepToken
  • 5,751
  • 3
  • 17
  • 42
1

It is most certainly valid.

When we take a variable which has been assigned a value and perform the AND operation with another variable with a null (in python - None), the AND operation results in a None. Hence, the check can be made. To make my point clear, please refer below.

a=2;c=None; b=11
if a and c is not None:
    print("T")
else:
    print("F")

and

print(a and c)

results in None

and

print(a and b)

results in Non-null value - in our case 11

gireesh4manu
  • 109
  • 2
  • 12
  • 1
    The output of your last statement there was interesting.. I really thought that 'and' returned only True or False but looks like it works a bit differently, you just don't normally notice as it is in an 'if' statement. – cardamom Jan 09 '19 at 11:49