Reputation: 3
I'm writing a script in Python that essentially rolls a dice and checks whether the die roll exceeds a number x
. I want to repeat this process n
times and get the probability that the die roll exceeds the number x
. e.g.
Count = 0
for _ in itertools.repeat(None, Iterations):
x = 3
die_roll = rnd.randint(1,6)
if die_roll > x:
Count += 1
Probability_of_exceed = Count / Iterations
I want to modify both the die roll and x based on user input. This user input will select different routines to modify the script e.g. "Andy's_Routine"
might change x
to 4
. Currently I implement this using if statements in the for loop to check which routines are active, then applying them e.g.
Count = 0
for _ in itertools.repeat(None, Iterations):
x = 3
if "Andy's_Routine" in Active_Routines:
x = 4
die_roll = rnd.randint(1,6)
if "Bill's_Routine" in Active_Routines:
die_roll += 1
if "Chloe's_Routine" in Active_Routines:
# do something
pass
if "Person_10^5's_Routine" in Active_Routines:
# do something else
pass
if die_roll > x:
Count += 1
Probability_of_exceed = Count / Iterations
In practice the routines are not so simple that they can be generalised, they might add an extra output for example. The routines can be and are concurrently implemented. The problem is that there could be thousands of different routines, such that each loop will spend the majority of its time checking the if statements, slowing down the program.
Is there a better way of structuring the code that checks which routines are in use only once, and then modifies the iteration somehow?
Upvotes: 0
Views: 100
Reputation: 51043
You're asking two things here - you want your code to be more Pythonic, and you want it to run faster.
The first one is easier to answer: make Active_Routines
a list of functions instead of a list of strings, and call the functions from the list. Since these functions may need to change the local state (x
and die_roll
), you will need to pass them the state as parameters, and let them return a new state. The refactor might look like this:
def Andy(x, die_roll):
return (4, die_roll)
def Bill(x, die_roll):
return (x, die_roll + 1)
def Chloe(x, die_roll):
# do something
return (x, die_roll)
Active_Routines = [Andy, Bill, Chloe]
Count = 0
for i in range(Iterations):
x = 3
die_roll = rnd.randint(1,6)
for routine in Active_Routines:
x, die_roll = routine(x, die_roll)
if die_roll > x:
Count += 1
Probability_of_exceed = Count / Iterations
The second one is harder to answer. This refactoring now makes a lot of function calls instead of checking if
conditions; so there could be fewer missed branch predictions, but more function call overhead. You would have to benchmark it (e.g. using the timeit library) to be sure. However, at least this code should be easier to maintain.
Upvotes: 1