Python - What's the difference between "in" and "in x for x in"
Asked Answered
M

4

5

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!

Mcclean answered 28/2, 2014 at 1:12 Comment(0)
H
4

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.

Hautemarne answered 28/2, 2014 at 1:27 Comment(0)
N
6

Generator

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.

Conditional

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?

Nies answered 28/2, 2014 at 1:15 Comment(2)
Thank you very much! What if y = ['hello','how','are','you']? What is x then?Mcclean
@Krishath it would check if x is a letter in any of those words. e.g., x = 'h' > True; x = 'p' > False; x = 'hello' > FalseYellowthroat
H
4

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.

Hautemarne answered 28/2, 2014 at 1:27 Comment(0)
G
2
  1. 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
    
  2. 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):
Graniela answered 28/2, 2014 at 1:27 Comment(0)
K
2

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.

Kei answered 28/2, 2014 at 1:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.