Использование словарей в Python вместо оператора Case/Switch

Я хочу рандомизировать кубик Рубика, который инициализируется как завершенный (все цвета на правильных сторонах). У меня есть функции перемещения, которые вращают куб. Я хочу случайным образом выбрать 50 функций подряд, чтобы правильно их рандомизировать.

Я делаю этот проект, чтобы узнать немного больше о Python, так как в основном я делаю C++ и вижу, что для Python нет регистра / переключателя, поэтому я пробую словарь. Когда я создаю словарь, кажется, что код выполняется по какой-то причине:

def random_cube(self):
    scramble = {    0 : self.up_turn(),
                    1 : self.down_turn(),
                    2 : self.left_turn(),
                    3 : self.right_turn(),
                    4 : self.front_turn(),
                    5 : self.back_turn(),
                    6 : self.up_turn("inverted"),
                    7 : self.down_turn("inverted"),
                    8 : self.left_turn("inverted"),
                    9 : self.right_turn("inverted"),
                    10: self.front_turn("inverted"),
                    11: self.back_turn("inverted")
                }
    for x in range(50):
        i = random.randint(0,11)
        scramble[i]

Поэтому, когда я делаю этот словарь, он почему-то просматривает и выполняет все 11 записей (я думаю). Кажется, я не могу найти лучшего способа, по крайней мере, более элегантного, чем длинная строка утверждений if/elif.

! РЕДАКТИРОВАТЬ: При реализации обоих предложений флаг ("инвертированный") для функций не устанавливается ни одним предложением. Например, вызовы 1 и 7 дают мне down_turn, но вывод показывает, что флаг не был установлен, когда он должен был быть на номер 7.

Есть идеи?

2 ответа

Решение

Когда вы определяете dict, он фактически вызывает функции и сохраняет возвращаемое значение в словаре. Чтобы в словаре хранилась ссылка на функции, вам нужно удалить завершающие скобки. Так что-то вроде:

scramble = {  0: self.up_turn,
              1: self.down_turn,
              etc.

Затем в нижней части позвоните scramble[i](),

Это вызовет функцию без аргументов. Чтобы обработать случай, когда вы передаете "инвертированный" в качестве аргумента, вы можете либо определить отдельные функции, такие как up_turn_inverted() и т. Д., Либо вы можете иметь словарь для хранения 2-х элементов, состоящих из функции и аргумента, а затем вызвать что-то нравится scramble[i][0](scramble[i][1])

Обновление от предложения в комментариях: Вы также можете использовать лямбда-выражения для определения функций, особенно тех, которые требуют аргумента. Это в основном эквивалентно определению функции up_turn_inverted, но выполняется на месте как анонимная функция. Это будет выглядеть так:

6: lambda: self.up_turn("inverted")
7: lambda: self.down_turn("inverted")

и т.п.

Я полагаю, что это называется "функции как первоклассные значения", подразумевая, что самое важное, вы можете передавать идентификаторы, относящиеся к функциям, в качестве параметров другим функциям.

Когда вы определяете свой словарь, интерпретатор Python оценивает функции и сохраняет значения в словаре. Чтобы отложить это до тех пор, пока вы не сгенерируете свои случайные числа, попробуйте вместо этого сохранить ссылки на сами функции в вашем словаре, оставив скобки:

def random_cube(self):
    scramble = {    0 : self.up_turn,
                    1 : self.down_turn,
                    2 : self.left_turn,
                    3 : self.right_turn,
                    4 : self.front_turn,
                    5 : self.back_turn,
                    6 : self.up_turn,
                    7 : self.down_turn,
                    8 : self.left_turn,
                    9 : self.right_turn,
                    10: self.front_turn,
                    11: self.back_turn
                }

Затем при вызове ваших функций в цикле for вам нужно будет различать ваши обычные и инвертированные случаи, по которым передаются параметры:

    for x in range(50):
        i = random.randint(0,11)
        if i <= 5:
            scramble[i]()
        else:
            scramble[i]("inverted")

или проще:

    for x in range(50):
        i = random.randint(0,11)
        scramble[i]( () if i < 6 else ("inverted"))
Другие вопросы по тегам