Sid
Sid

Reputation: 33

Weird behaviour of loops in python

So I was trying to do some basic stuff list stuff in a different way, and I came across weird behaviour in this code. I'm not sure if its a compiler/machine dependent result and I can't even google this because I'm just so lost.

Edit: In response to some people, I get that my code is incorrect in its semantics, but the behaviour of the code after the mistake is what I wanted to understand. Thanks for the corrections though!

Here is the code:

import random

L = (int(input("For List 1, enter a number: ")) for i in range(random.randint(2, 5)))
L1 = (int(input("For List 2, enter a number: ")) for i in range(random.randint(2, 6)))

common = []

for i in L:
  if i in L1:
    common.append(i)

print(common)

From my limited understanding, line 3 and 5 should have just resulted in L and L1 having the last entered integer stored in them, but when I execute the program it just flits between line 3 and 5. Furthermore, if I try to print L and L1 it just prints its object type (genexpr) and location in memory, before the prompts for inputs. Why is the code behaving that way?

Upvotes: 1

Views: 457

Answers (2)

timgeb
timgeb

Reputation: 78780

The unexpected bahavior is caused by the generator expressions, which are evaluated lazily.

This means that the values for L and L1 will be generated as needed, one value at a time.

The loop

for i in L:

can be executed by creating a single value for L in each iteration. This is why you will see one prompt "For List 1, enter a number: " for each iteration of the outer for loop!

However, the if statement

if i in L1:

requires values to be created for L1 until i is found or until there are no more values to generate for L1.

Example:

>>> L1 = (x for x in (1, 2, 3, 4))
>>> 3 in L1
True
>>> next(L1)
4
>>> next(L1)
Traceback (most recent call last):
[...]
StopIteration

To avoid the lazy evaluation, use lists instead of generator expressions, i.e.

L = [int(input("For List 1, enter a number: ")) for i in range(random.randint(2, 5))]
L1 = [int(input("For List 2, enter a number: ")) for i in range(random.randint(2, 6))]

Upvotes: 1

Hiibb
Hiibb

Reputation: 383

I think what you want to do is to use a list comprehension with square brackets instead of curved brackets.

import random

L = [int(input("For List 1, enter a number: ")) for i in range(random.randint(2, 5))]
L1 = [int(input("For List 2, enter a number: ")) for i in range(random.randint(2, 6))]
common = []

for i in L:
  if i in L1:
    common.append(i)

print(common)

If you instead want to do a tuple comprehension, you could do it as follows:

import random

L = tuple(int(input("For List 1, enter a number: ")) for i in range(random.randint(2, 5)))
L1 = tuple(int(input("For List 2, enter a number: ")) for i in range(random.randint(2, 6)))
common = []

for i in L:
  if i in L1:
    common.append(i)

print(common)

Upvotes: 0

Related Questions