Передача логического значения от прослушивателя к включающей функции

#python

#python

Вопрос:

Вот простой фрагмент гораздо более крупной программы, над которой я работаю. decideByKeypress() Это функция, которая ожидает либо нажатия клавиши Esc, либо комбинации клавиш left Ctrl и left Shift . Первое взаимодействие с клавиатурой означает успех, следовательно return 0 , в то время как последнее означает, что что-то не так, следовательно return -1 . (Пользователь увидит на экране пары ввода-вывода классификации ML, и этот фрагмент поможет пользователю решить, правильная классификация или нет.)

Поскольку процесс прослушивания должен быть прерван первым, я, очевидно, не мог добавить вышеупомянутые операторы return непосредственно туда. Вот почему on_press возвращает False как в Esc , так и в Shift Ctrl случаях.

Я добавил логическую переменную escPressed , чтобы четко разделить два случая. Ему True присваивается значение A, если <Key.esc: <27>> оно найдено в текущем наборе, и a False присваивается в другом случае.

Теперь, получив escPressed , я надеялся, что смогу просто добавить условие if / else и вернуть 0 или -1 на основе истинности или ложности escPressed . Однако при запуске кода и нажатии Esc мне кажется, что True значение, установленное в escPressed , игнорируется, как будто внутреннее escPress не увидит уже определенное внешнее escPressed . Я очень удивлен таким поведением, поскольку переменная, объявленная внутри функции, может быть доступна функциям внутри этой функции, как объяснено здесь.

Вот полный код:

 from pynput import keyboard


COMBINATIONS = [
    { keyboard.Key.shift, keyboard.Key.ctrl_l },
    { keyboard.Key.esc }
]

def decideByKeypress():
    current = set()
    escPressed = bool()

    def on_press(key):
        if any([key in COMBO for COMBO in COMBINATIONS]):
            current.add(key)
            if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
                print(current)
                if keyboard.Key.esc in current:
                    escPressed = True
                    return False
                elif (keyboard.Key.shift_l in current) and (keyboard.Key.ctrl_l in current):
                    escPressed = False
                    return False
                else:
                    pass

    def on_release(key):
        try:
            current.remove(key)
        except KeyError:
            pass

    with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

    if escPressed:
        print("Esc has been pressed!")
        return -1
    else:
        print("Esc has not been pressed!")
        return 0

if __name__ == "__main__":
    decideByKeypress()
  

И вот мои выходные данные, которые я получил при нажатии Esc :

 {<Key.esc: <27>>}
escPressed is set to True
Esc has NOT been pressed!
  

Ответ №1:

Я не уверен в фактической реализации keyboard.Listener , но что-то в ней, по-видимому, заставляет escPressed быть видимой только on_press функцию (вероятно, она выполняется в отдельном потоке).

Быстрым способом решения этой проблемы будет отслеживание состояния в изменяемой / совместно используемой структуре данных, например, a dict .

 state = {'esc': False}

def decideByKeypress():
    current = set()

    def on_press(key):
        if any([key in COMBO for COMBO in COMBINATIONS]):
            current.add(key)
            if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
                print(current)
                if keyboard.Key.esc in current:
                    state['esc'] = True
                    return False
                elif (keyboard.Key.shift_l in current) and (keyboard.Key.ctrl_l in current):
                    state['esc'] = False
                    return False
                else:
                    pass

    def on_release(key):
        try:
            current.remove(key)
        except KeyError:
            pass

    with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()

    if state['esc']:
        print("Esc has been pressed!")
        return -1
    else:
        print("Esc has not been pressed!")
        return 0

if __name__ == "__main__":
    decideByKeypress()
  

запуск и нажатие esc:

 {<Key.esc: <27>>}
Esc has been pressed!
  

Комментарии:

1. Очень полезно! Огромное спасибо за вашу помощь, @DeepSpace!