1

I'm faced with what might seem a trivial, but nevertheless very annoying conundrum. While checking for membership using the "not in" operator combined with Boolean "and" and "or" on a following dictionary:

    data = {"name": "david", "age": 27, "income": "absurd"}

I've found that:

#1 - found
if "name" not in data:
    print "not found"
else:
    print "found"

#2 - found
if "name" not in data and "income" not in data:
    print "not found"
else:
    print "found"

#3 - found
if "name" and "income" not in data:
    print "not found"
else:
    print "found"

#4 - found
if "name" not in data or "income" not in data:
    print "not found"
else:
    print "found"

#5 - NOT found (though it should be?)
if "name" or "income" not in data:
    print "not found"
else:
    print "found"

For my money #4 and #5 are logically identical, but clearly they can't be. I looked over the official Python reference but it only added to confusion. Could someone shed a light on this?

  • 6
    This question has been asked many, many times. Hint: `"name" or "income" not in data` means `("name" or "income") not in data`. What is the value of `"name" or "income"`? – BrenBarn Sep 01 '15 at 06:57
  • 3
    @BrenBarn: actually, that's `("name") or ("income" not in data)`. [`or` has a lower precedence than `not in`](https://docs.python.org/2/reference/expressions.html#operator-precedence). – Martijn Pieters Sep 01 '15 at 07:01
  • 1
    Why do they keep thinking that would work? `"name" or "income" not in data` is the incorrect way of writing `any(prop not in data for prop in ["name", "income"])`. – Dan D. Sep 01 '15 at 07:01
  • You can also convert a dict to a set (containing the dict's keys). So you can code `if set(data).intersection(properties_list): ...` (empty set is Falsey, non-empty is Truthy) Not sure if this is better or worse than Dan D's solution. – nigel222 Sep 01 '15 at 08:39

1 Answers1

0

Note that not in binds more strongly than both and and or. So #4 gets parsed as you would expect, while #5 is equal to if ("name") or ("income" not in data): – since non-empty strings are truthy in python, this means it always ends up in the "not found" branch.

llogiq
  • 13,815
  • 8
  • 40
  • 72