Есть ли Pythonic способ пропустить операторы for в цикле, чтобы мой код работал быстрее? - PullRequest
0 голосов
/ 08 ноября 2019

Я пишу скрипт на Python, который по сути бросает кости и проверяет, превышает ли бросок кубика число x. Я хочу повторить этот процесс n раза и получить вероятность того, что бросок кубика превысит число x. например,

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

Я хочу изменить как бросок кубика, так и x на основе пользовательского ввода. Этот пользовательский ввод выберет различные подпрограммы для изменения скрипта, например, "Andy's_Routine" может изменить x на 4. В настоящее время я реализую это с помощью операторов if в цикле for, чтобы проверить, какие подпрограммы активны, а затем применяя их, например:

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

На практике подпрограммы не так просты, что их можно обобщить, они могут добавить дополнительныевывод к примеру. Подпрограммы могут быть и реализованы одновременно. Проблема в том, что могут быть тысячи различных подпрограмм, так что каждый цикл будет тратить большую часть своего времени на проверку операторов if, замедляя работу программы.

Есть ли лучший способ структурировать код, который проверяет, какие подпрограммы используются только один раз, а затем каким-то образом изменяет итерацию?

1 Ответ

1 голос
/ 08 ноября 2019

Вы просите две вещи здесь - вы хотите, чтобы ваш код был более Pythonic, и вы хотите, чтобы он работал быстрее.

Первый ответ проще: составьте Active_Routines список функцийвместо списка строк и вызова функций из списка. Поскольку этим функциям может потребоваться изменить локальное состояние (x и die_roll), вам необходимо будет передать им состояние в качестве параметров и разрешить им возвращать новое состояние. Реактор может выглядеть так:

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

Второй вопрос сложнее ответить. Этот рефакторинг теперь выполняет много вызовов функций вместо проверки условий if;таким образом, может быть меньше пропущенных предсказаний ветвления , но больше издержек вызова функции . Вы должны были бы сравнить его (например, используя timeit library ), чтобы быть уверенным. Однако, по крайней мере, этот код должен быть проще в обслуживании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...