yield
is a keyword that is used like return
, except the function will return a generator. When you call the function, the code of the function body does not run. The function only returns the generator object, which you can iterate on! The first time you iterate the generator object created from your function, it will run the code from the beginning until it reaches yield
, and return the first value. Then the next call will continue running the code. This will continue until the function runs without hitting yield.
# A generator function that yields four values
def generator1():
yield 2
yield 3
yield 5
yield 7
# Iterate by the above generator function
for prime in generator1():
print(prime, end=" ")
2 3 5 7
def generator2():
for i in range(4):
yield i*i
print(generator2()) # does not give a value back
<generator object generator2 at 0x7f100838ba50>
for s in generator2():
print(s, end=" ")
0 1 4 9
gen3 = (i*i for i in range(4))
for s in gen3:
print(s, end=" ")
0 1 4 9
Let $X$ be a discrete random variable. The expected value of $X$ is $$ \mathbb{E}[X]=\sum\limits_{x\in X}{x\mathbb{P}(X=x)}. $$ Example: Calculate the expected value of the sum of the numbers on two dice!
ev = 0
for i in range(1,7):
for j in range(1,7):
ev = ev + i + j
ev = ev/36
print(ev)
7.0
Do experiments for the expected value by simulation!
from random import randint
ev = 0
n = 1000
for _ in range(n):
i, j = randint(1,6), randint(1,6)
ev = ev + i + j
ev = ev/n
print(ev)
6.989
attacker = [randint(1, 6) for _ in range(3)]
defender = [randint(1, 6) for _ in range(2)]
attacker
[4, 6, 4]
attacker.sort(reverse=True)
defender.sort(reverse=True)
attacker, defender
([6, 4, 4], [5, 4])
if attacker[0] > defender[0]:
# attacker wins
print("A")
else:
# defender wins
print("D")
A
# counting probablity
attackers = [[i, j, k] for i in range(1,7) for j in range(1,7) for k in range(1,7)]
defenders = [[i, j] for i in range(1,7) for j in range(1,7)]
# or another possibility
from itertools import product
dice = range(1, 7)
attackers = product(dice, dice, dice)
defenders = product(dice, dice)
from random import randint
def gen_rand(n):
'''
A generator for n battle.
'''
for _ in range(n):
attacker = [randint(1, 6) for _ in range(3)]
defender = [randint(1, 6) for _ in range(2)]
attacker.sort(reverse=True)
defender.sort(reverse=True)
yield attacker, defender
def gen_prob():
'''
A generator for all possible results of a battle.
'''
attackers = [[i, j, k] for i in range(1,7) for j in range(1,7) for k in range(1,7)]
defenders = [[i, j] for i in range(1,7) for j in range(1,7)]
for x in attackers:
for y in defenders:
x.sort(reverse=True)
y.sort(reverse=True)
yield x, y
def evaluate(a, d):
'''
Evaluate the number of winning of the attacker (2, 1, or 0)
a:: attacker
d:: defender
'''
att = 0
if a[0] > d[0]:
att += 1
if a[1] > d[1]:
att += 1
return att
def main():
'''
Calculate the relative frequences and the probabilities.
'''
n = [1000, 1000000, 6**5]
f = [gen_rand(n[0]), gen_rand(n[1]), gen_prob()]
t = [f"{n[0]} experiments", f"{n[1]} experiments", "probabilities"]
for c in range(3):
c_at, c_dr, c_de = 0, 0, 0
for i in f[c]:
e = evaluate(*i)
if e == 2:
c_at += 1
elif e == 1:
c_dr += 1
else:
c_de += 1
print(f"{t[c]:<20}{c_at/n[c]:.5f} {c_dr/n[c]:.5f} {c_de/n[c]:.5f}")
if __name__ == "__main__":
main()
1000 experiments 0.37200 0.33400 0.29400 1000000 experiments 0.37153 0.33607 0.29241 probabilities 0.37166 0.33578 0.29257