Does `not x in y` follow the operator precedence rules? [duplicate] - python

This question already has answers here:
"x not in y" or "not x in y"
(6 answers)
Closed 3 years ago.
The canonical question on the difference between not x in y and x not in y states that these two are equivalent in implementation (in CPython). The operator precedence rules state that the Boolean not has higher precedence than in. So shouldn't not x in y be implemented to be equivalent to (not x) in y?
Consider
x = False
list2 = ['a']
not x in list2
Out[19]: True
(not x) in list2
Out[20]: False
I would have expected second last statement to be False, if I'm understanding the precedence rules correctly.

Rather subtle but if you look in the official documentation that you linked to, you will see that "not in" is its own operator, which has a higher precedence than "not" and the same precedence as "in".
Your mistake is probably coming from reading the operator precedence rules the wrong way around. As it currently stands, the lowest precedence comes higher up in the list.
So not x in list2 is equvalent to not (x in list2).
Your last assumption will, because you have surrounded it with parentheses, first evaluate not x to a boolean (False), then check if that boolean is in the list (which it is not, there's only a string in the list), and return False.

Related

Understanding the "and" operator - Why is "None and None" not False? [duplicate]

This question already has answers here:
Logical operators in Python [duplicate]
(4 answers)
Closed 2 years ago.
I though I understood Python the "and" operator. But after seeing
assert (None and None) is None
it was apparently that my understanding was not precise. Which was that None and None would be the same as bool(None) and bool(None).
Does anybody have definition of the "and" operator and can explain the logic.
According to the official documentation:
help('and')
[...] The expression "x and y" first evaluates x; if x is false,
its value is returned; otherwise, y is evaluated and the resulting
value is returned. [...]
and returns the first value if it is "falsey"*. Otherwise it returns the second one.
For example:
3 and 6 -> 6
0 and 7 -> 0
[] and 'abc' -> []
* a thing is falsey if bool(thing) is False

Why does 'a' and 'b' equal 'b' in Python? [duplicate]

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
How does the logical `and` operator work with integers? [duplicate]
(2 answers)
"4 and 5" is 5, while "4 or 5" is 4. Is there any reason? [duplicate]
(4 answers)
Closed 3 years ago.
What does 'a' and 'b' in Python mean and why does it equal 'b'? Why does it not equal 'a'?
>>> 'a' and 'b'
'b'
From the Pycharm docs:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Because 'a' is not False 'b' is evaluated and returned.
Also nice to know. What is evaluated as True and what as False:
the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.
Either 'a' or 'b' would be an acceptable answer to 'a' and 'b' (since both are truthy), but only False would be an acceptable answer to 'a' and False, just as only 0 would be an acceptable answer to 'a' and 0 (since the result of this evaluation must be false-y to be logically correct).
Having a short-circuiting boolean evaluation follow the right-hand path when the left-hand is true allows there to be a single rule that applies in all cases.

Testing multiple string 'in' conditions in list comprehension [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 5 years ago.
I am trying to add multiple 'or' clauses to a python if statement using list comprehension. My code is shown below. I would like to keep the list comprehension. In terms of pseudocode, the logic would simply be:
Alive_Beatles = each name that contains '(Beatle)' and either ('Paul', 'Yoko' or 'Ringo')
The code only returns Paul and skips Ringo and Yoko.
Names = ["John Lennon (Beatle)", "Paul McCartney (Beatle)", "Ringo Starr (Beatle)", "Yoko Ono (Beatle)", "Mick Jagger (Rolling Stone)", "Brian Jones (Rolling Stone)", "Alex Jones (na)", "Adam Smith (na)"]
Alive_Beatles = [n for n in Names if ("Beatle" and ("Paul" or "Ringo" or "Yoko")) in n]
print Alive_Beatles
You need to test each name explicitly if it's in n:
[n for n in Names if ("Beatle" in n and ("Paul" in n or "Ringo" in n or "Yoko" in n))]
Otherwise the and and or use the truth value of you search strings (and each non-empty string is always True) and finally tests if Paul in n (the first truth value of the ors).
The documentation explicitly mentions this:
4.2. Boolean Operations — and, or, not
These are the Boolean operations, ordered by ascending priority:
Operation Result Notes
x or y if x is false, then y, else x (1)
x and y if x is false, then x, else y (2)
not x if x is false, then True, else False (3)
Notes:
(1) This is a short-circuit operator, so it only evaluates the second argument if the first one is false.
(2) This is a short-circuit operator, so it only evaluates the second argument if the first one is true.
(3) not has a lower priority than non-Boolean operators, so not a == b is interpreted as not (a == b), and a == not b is a syntax error.
So "Beatle" and (...) evaluates according to (2) to the second argument because "Beatle" is truthy and according to (1) it evaluates to the first argument of the chained ors: "Paul" because it's also truthy.
This doesn't do what you expect because the expression
("Paul" or "Ringo" or "Yoko")
evaluates to "Paul". Type it in at an interpreter prompt to confirm this.
And even that only seems to work because
("Beatle" and ("Paul" or "Ringo" or "Yoko"))
also evaluates to "Paul".
The most straightforward solution is to just list
[n for n in Names if "Beatle" in n and ("Paul" in n or "Ringo" in n or "Yoko" in n)]
But you could use any to get a bit closer to what you tried initially:
[n for n in Names if "Beatle" in n and any(x in n for x in ("Paul", "Ringo", "Yoko"))]

Does python store one value for an int and many references? [duplicate]

This question already has answers here:
"is" operator behaves unexpectedly with integers
(11 answers)
Closed 7 years ago.
I'm wondering why this evaluates to True.
x = 1
if x is 1:
print "Does x and 1 point to the same object?"
print "Does this mean python doesn't store redundant values?"
It doesn't work for this case as I expect.
x = range(10)
y = range(10)
if not x is y:
print "I expect this"
My understanding is that is checks to see if two names are pointing to the same object. Does this imply that python has a mechanism to avoid creating redundant values?
This is an implementation detail of the CPython interpreter, but integers with small values are "interned" -- whenever the result of an expression falls within a certain range, an existing int object with the same value is returned.
You could check the range that gets interned by using the following code:
interned_range = [i for i in range(-1000, 1000) if i+0 is i]
print min(interned_range), max(interned_range)
My CPython inters integers between -5 and 256 inclusive.
Being an implementation detail, this behaviour should generally not be relied upon.

When checking if an item does not exist in a list, why doesn't this code work - if item in list == False: [duplicate]

This question already has answers here:
python operator precedence of in and comparison [duplicate]
(3 answers)
Closed 9 years ago.
Consider this list:
list = [1,2,3,4,5]
I want to check if the number 9 is not present in this list. There are 2 ways to do this.
Method 1: This method works!
if not 9 in list: print "9 is not present in list"
Method 2: This method does not work.
if 9 in list == False: print "9 is not present in list"
Can someone please explain why method 2 does not work?
This is due to comparison operator chaining. From the documentation:
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).
You are assuming that the 9 in list == False expression is executed as (9 in list) == False but that is not the case.
Instead, python evaluates that as (9 in list) and (list == False) instead, and the latter part is never True.
You really want to use the not in operator, and avoid naming your variables list:
if 9 not in lst:
It should be:
if (9 in list) == False: print "9 is not present in list"

Categories

Resources