This is my Python code:
# 1)
if (x not in z for z in y):
# 2)
if (x not in y):
Where y could be a list like:
y = ['1','2','3']
Can somebody explain me the difference between these two sentences? Thank you!
This is my Python code:
# 1)
if (x not in z for z in y):
# 2)
if (x not in y):
Where y could be a list like:
y = ['1','2','3']
Can somebody explain me the difference between these two sentences? Thank you!
Let’s start with the simple one first:
if (x not in y):
The parentheses don’t carry any meaning there, so this is equivalent to this:
if x not in y:
The in
operator checks if something is contained within something else. In your case, you have a list y
, so you are checking if something (x
) is not contained within (not in
) that list y
. So '1' not in y
would be False
because '1'
is an element of y
, and '4' not in y
would be True
because '4'
is not an element of y
.
The other one is something completely different though:
if (x not in z for z in y)
Here we have a generator expression. Generator expressions are of the format (x for z in y)
and are equivalent to this code:
for z in y:
yield x
You might have heard about list comprehensions before; those are similar but use square brackets instead of parentheses: [x for z in y]
. As they return a list, they are a bit easier to understand. They are equivalent to this:
lst = []
for z in y:
lst.append(x)
return lst
Essentially, you are looping over the elements of y
, calling each element in an iteration
z
and return x
for that element. In your case, x
is an expression itself: x not in z
which is basically the same as above: You are checking if x
is not contained within z
.
Now, generator expressions are a bit complicated, because they are evaluated when an element is requested from it, so let’s assume for now that we have a list comprehension instead
if [x not in z for z in y]:
So what this does is calculate x not in z
for each element z
in y
. So for your y
, the resulting list would be this:
[x not in '1', x not in '2', x not in '3']
With a real x
, this would as such result in a list with three boolean values. Now a non-empty list is always trueish, so regardless of the result in this check, the if
-check would succeed.
The generator expression will return a generator though, which is a more complex object that a list. It is just as well true-ish though, so your check will also succeed regardless of the individual values.
Now imagine, we want to make sure, that for those three elements in the list, we want all checks to result in True
. For that, we can use the all()
function which essentially checks if a list—or the values in a generator—contains only true values.
if all(x not in z for z in y):
So this will succeed if x
is not contained within any element of the list y
. If on the other hand we wanted to check if at least one trueish value is in the list or generator, then we could instead use the any()
function.
To begin with, (x not in z for z in y)
is a generator statement, and if if
is in front of it, it will always return True.
if (x not in z for z in y): # Always returns True
This could be used to see if any or all of the nested iterables contain x
.
e.g.
if any(x in z for z in y): # Returns True if any of the z's contain x
if all(x in z for z in y): # Returns True only if all of the z's contain x
So if y
is this:
y = ['hello','how','are','you']
then if x
is, for example, 'e'
, then the any
comprehension above would return True
, but the all
comprehension would return False
.
So here's what going on inside that generator comprehension: if y is a list, and you test with:
(x not in z for z in y)
the z in y must be an iterable in order to test for inclusion, which strings are, but you're only seeing if something is in a string of length one in this case. A better example would be to use integers:
y = [1, 2, 3]
and
if (x not in z for z in y):
would fail, because integers are not iterable, but
if (x not in y):
would succeed because you can test for membership in the actual list.
When you have
y = ['1','2','3']
a similar level of nesting would be:
y = [(1,), (2,), (3,)]
and with
(x not in z for z in y)
you are testing if x is in one of those tuples.
Does that make sense?
x = 'h' > True
; x = 'p' > False
; x = 'hello' > False
–
Yellowthroat Let’s start with the simple one first:
if (x not in y):
The parentheses don’t carry any meaning there, so this is equivalent to this:
if x not in y:
The in
operator checks if something is contained within something else. In your case, you have a list y
, so you are checking if something (x
) is not contained within (not in
) that list y
. So '1' not in y
would be False
because '1'
is an element of y
, and '4' not in y
would be True
because '4'
is not an element of y
.
The other one is something completely different though:
if (x not in z for z in y)
Here we have a generator expression. Generator expressions are of the format (x for z in y)
and are equivalent to this code:
for z in y:
yield x
You might have heard about list comprehensions before; those are similar but use square brackets instead of parentheses: [x for z in y]
. As they return a list, they are a bit easier to understand. They are equivalent to this:
lst = []
for z in y:
lst.append(x)
return lst
Essentially, you are looping over the elements of y
, calling each element in an iteration
z
and return x
for that element. In your case, x
is an expression itself: x not in z
which is basically the same as above: You are checking if x
is not contained within z
.
Now, generator expressions are a bit complicated, because they are evaluated when an element is requested from it, so let’s assume for now that we have a list comprehension instead
if [x not in z for z in y]:
So what this does is calculate x not in z
for each element z
in y
. So for your y
, the resulting list would be this:
[x not in '1', x not in '2', x not in '3']
With a real x
, this would as such result in a list with three boolean values. Now a non-empty list is always trueish, so regardless of the result in this check, the if
-check would succeed.
The generator expression will return a generator though, which is a more complex object that a list. It is just as well true-ish though, so your check will also succeed regardless of the individual values.
Now imagine, we want to make sure, that for those three elements in the list, we want all checks to result in True
. For that, we can use the all()
function which essentially checks if a list—or the values in a generator—contains only true values.
if all(x not in z for z in y):
So this will succeed if x
is not contained within any element of the list y
. If on the other hand we wanted to check if at least one trueish value is in the list or generator, then we could instead use the any()
function.
This
if (x not in z for z in y):
is equivalent to
if True:
Because
>>> (x not in z for z in y)
<generator object <genexpr> at 0x000000E7AE26FB88>
>>> bool(_)
True
This
if (x not in y):
Is the same as
if x not in y:
Which resolves internally to
if not y.__contains__(x):
In the first case, you might have meant to write:
if any(x not in z for z in y):
# same as
if not all(x in z for z in y):
or:
if all(x not in z for z in y):
# same as
if not any(x in z for z in y):
I'll assume this is a general question, and the actual values in the list don't matter much.
For:
1) if (x not in z for z in y):
The for
in the statement means you have a "list comprehension" or "generator expression" (inside parens). It will generate a list. This one is a list comprehension with a filter (the x not in z
part). But the end result will be a list that may or may not be empty. Now the if
statement will evaluate this for "truthiness", where an empty list is considered false, and non-empty is true.
2) if (x not in y):
This is a straight "containment test" that tests directly if x
is contained (or not) in the iterable y
, and returns a Boolean value. This can be a fast test, depending on what kind of object y
is.
The first form is probably slower and unnecessary in most cases. The first one has to create and then destroy a temporary list.
© 2022 - 2024 — McMap. All rights reserved.