List comprehension, generator expression¶
A list comprehension executes immediately and returns a list, which is an iterable object.
A generator expression is an iterator object. It does almost the same as list comprehension but does it lazily.
Iterable is an object, which one can iterate over. It generates an Iterator when passed to iter()
method. Iterator is an object, which is used to iterate over an iterable object using __next__()
method. Iterators have __next__()
method, which returns the next item of the object.
Note that every iterator is also an iterable, but not every iterable is an iterator.
for num in [2, 3, 5, 7]:
print(num, end=' ')
2 3 5 7
numbs = [2, 3, 5, 7]
iterator_obj = iter(numbs)
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj))
2 3 5 7
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) Cell In[2], line 7 5 print(next(iterator_obj), end=' ') 6 print(next(iterator_obj), end=' ') ----> 7 print(next(iterator_obj)) StopIteration:
iterator_obj = iter(numbs)
try:
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj), end=' ')
print(next(iterator_obj)) #StopIteration error
except:
pass
2 3 5 7
Let's see the differences between list comprehension and generator expression again:
lst = [n for n in range(10000)]
gen = (n for n in range(10000))
print(type(lst), type(gen))
<class 'list'> <class 'generator'>
from sys import getsizeof
print(getsizeof(lst), getsizeof(gen))
85176 192
for i in lst:
if i == 100:
print(i)
100
for i in gen:
if i == 100:
print(i)
100
lst[100]
100
gen[100] # we can iterate through the items
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[10], line 1 ----> 1 gen[100] # we can iterate through the items TypeError: 'generator' object is not subscriptable
A 'generator' object is not subscriptable, and we can iterate over it only once. So in embedded loops, we can not use two generator expression:
g1=(i for i in range(3))
g2=(j for j in range(3))
for i in g1:
for j in g2:
print(i,j)
0 0 0 1 0 2
# we have to generate g2 at every cicle
g1=(i for i in range(3))
for i in g1:
g2=(j for j in range(3))
for j in g2:
print(i,j)
0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2
Conditional relative frequency¶
Let us throw two dice, a red and a blue one, and let s denotes the sum. What is the relative frequency (relative frequency of a conditional event) of 1 on the red die if s is given? What is the relative frequency of any other number on the red die if s is given? For which value of s will be this frequency close to 1/6?
from random import randint
two = [red, _] = [randint(1,6), randint(1,6)]
two, red
([1, 5], 1)
two = [randint(1,6), randint(1,6)]
red = two[0]
two, red
([1, 6], 1)
s = sum(two)
two, s, red
([1, 6], 7, 1)
sum2 = 5 # sum of the two numbers (2..12)
die = 1 # the number on the die we are waiting for (1..6)
count = 0 # counter of the cases with sum == <sum2>
count_red = 0 # counter when the red die == <die>
for i in range(10000):
two = [randint(1,6), randint(1,6)]
red = two[0]
s = sum(two)
if s == sum2:
count += 1
if red == die:
count_red += 1
print(count_red/count, 1/6)
0.26824817518248173 0.16666666666666666
Conditional probability¶
Let us throw two dice, a red and a blue one, and let s denotes the sum. What is the probability that the number r is on the red die if s is given? For which value of s will be this frequency equal to 1/6?
sum2 = 7 # sum of the two numbers
die = 4 # the number on the die we are waiting for
count = 0 # counter of the cases with sum == <sum2>
count_red = 0 # counter when the red die == <die>
for red in range(1, 7):
for blue in range(1, 7):
s = red + blue
if s == sum2:
count += 1
if red == die:
count_red += 1
print(count_red/count, 1/6)
0.16666666666666666 0.16666666666666666