6

I have a conceptual question about Python. This is the code

list1=['assistant manager', 'salesperson', 'doctor', 'production manager', 'sales manager', 'schoolteacher', 'mathematics teacher']
sub1 = "teacher"
sub2 = "sales"
ans=[]

for item in list1:
    if (sub1 and sub2) in item:
        ans.append(item)

Here, I expect the list to be empty as none of the items satisfy the condition if sub1 and sub2 in item: But when I print the list I get the output#1 as this

>>> ans
['salesperson', 'sales manager'] # I expected an empty list here

Also, when I use or instead of and as given below

for item in list1:
    if (sub1 or sub2) in item:
        ans.append(item)

the output#2 I get is

>>> ans
['schoolteacher', 'mathematics teacher'] # I expected a list of words containing sub1 or sub2 as their substrings

I saw a similar looking solution here, but it does not exactly solve my problem. Both the times I get a result which I do not expect while using and and or. Why is this happening during both these operations?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sssssuppp
  • 683
  • 1
  • 7
  • 29
  • 2
    `(sub1 and sub2) in item` what will be the result of the expression in the brackets? That will be checked against `item`. – Klaus D. Feb 22 '19 at 07:13
  • Change `(sub1 and sub2) in item` to `sub1 in item and sub2 in item` – Tom Karzes Feb 22 '19 at 07:14
  • 2
    Possible duplicate of [can Python 'and' return None?](https://stackoverflow.com/questions/54108493/can-python-and-return-none) – DirtyBit Feb 22 '19 at 07:18

2 Answers2

17

("teacher" and "sales") in "salesmanager" do not mean the same in Python and in English.

In English, it is synonynous to ("teacher" in "salesmanager") and ("sales" in "salesmanager") (which Python would understand as you thought it should, and evaluate to False).

Python on the other hand will first evaluate "teacher" and "sales", because it is in parentheses, and thus has higher priority. and will return the first argument if falsy, otherwise the second argument. "teacher" is not falsy, so "teacher" and "sales" evaluates as "sales". Then, Python continues to evaluate "sales" in "salesmanager", and returns True.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • So far as I know, all languages give parentheses first priority, not just Python. But you are correct in explaining what Python returns for `( X and Y )` – Carl Witthoft Feb 22 '19 at 14:00
  • You might want to suggest `any` and `all` for this pattern. – Neil G Feb 24 '19 at 21:04
  • @NeilG I thought about it, then figured there's a big disparity between the level where precedence needs to be explained, and the level where someone can understand generators and functions like `all`, and that it would just confuse the asker (i.e. a person who would be ready to benefit from that would not be looking for this question in the first place). – Amadan Feb 25 '19 at 04:56
6

The and and or operators don't do what you think they do. Try breaking up your expressions:

if sub1 in item or sub2 in item:

if sub1 in item and sub2 in item:

The and operator evaluates its left-hand operand and, if the result is truthy, returns the right-hand operand, otherwise the left-hand operand.

The or operator evaluates its left-hand operand and, if the result is falsy, returns the right-hand operand, otherwise the left-hand operand.

So, in your first expression evaluates as follows:

(sub1 and sub2) in item
("teacher" and "sales") in item
("sales") in item

which is not what you expected.

Similarly for your second expression:

(sub1 or sub2) in item
("teacher" or "sales") in item
("teacher") in item
Robᵩ
  • 163,533
  • 20
  • 239
  • 308