Python: как задать горячие клавиши в цикле?
Я пытаюсь написать скрипт, который будет читать текстовый файл с соответствием горячая клавиша:символ и задавать горячие клавиши для этих символов:
import keyboard
import tkinter.messagebox as mb
with open('hotkeys.txt', 'r', encoding='utf8') as hotkeys:
hotkeys = hotkeys.readlines()
c = 0
for hotkey in hotkeys:
c += 1
hotkey = hotkey.replace('\n', '')
hotkey = hotkey.split(':')
try:
keyboard.add_hotkey(hotkey[0], lambda: keyboard.write(hotkey[1]))
except:
mb.showerror('Ошибка', f'Неверный формат записи в конфигурационном файле: строка {c}.')
exit()
keyboard.wait('ctrl+alt+x')
Содержимое hotkeys.txt:
alt+1:!
alt+2:@
alt+3:#
alt+4:$
Но при запуске такого скрипта всем горячим клавишам почему-то назначается то, что написано в последний строке. То есть я ожидаю, что при нажатии alt+1 будет напечатан !, при нажатии alt+2 - @ и так далее.
На практике при нажатии любой комбинации alt+1 - 4 печатается $ (то есть то, что прописано только для alt+4).
Пробовал задавать горячие клавиши без цикла, вручную - всё работает. Похоже, проблема именно в цикле.
Есть ли у кого-нибудь идеи, почему такое странное поведение?
Ответы (2 шт):
У меня есть предположение, но думаю что оно верное
Для понимания, надо представить себе участок памяти, размером в 4 байта
При первом выполнении метода add_hotkey в ячейку памяти с адресом 1 записывается функция lambda которая выводит !
Если мы уменьшим файл hotkeys.txt до одной строки то мы увидим, что это именно так и всё работает !
Но проблема в том, что при следующем шаге в ячейку памяти с адресом 1 записывается уже другая lambda которая выводит @
Если мы оставим в файле hotkeys.txt две строки, то мы увидим, что alt+1 и alt+2 выводят одно и тоже, а именно - символ @
Это произошло потому что первый хоткей у нас указывает на адрес 1 и второй хоткей тоже указывает на адрес 1, вот только в адресе 1 уже записана вторая lambda, а первая - потерялась ( была перезаписана ).
Таким образом, после выполнения всего кода все хоткеи alt+1,2,3,4 указывают на последнюю лямбду и поэтому все выводят $
А вот как сделать так, чтобы лямбды не перезаписывали друг друга, а размещались в разных областях памяти - я не знаю, пусть эксперты подскажут
Попробуйте так:
import keyboard
import tkinter.messagebox as mb
with open('hotkeys.txt', 'r', encoding='utf8') as hotkeys:
hotkeys = hotkeys.readlines()
#print(f'{hotkeys}')
c = 0
for hotkey in hotkeys:
c += 1
hotkey = hotkey.replace('\n', '')
hotkey = hotkey.split(':')
#print(f'hotkey = {hotkey}') #
try:
z = keyboard.add_hotkey(
hotkey[0],
# lambda: keyboard.write(hotkey[1])
lambda h1=hotkey[1]: keyboard.write(h1) # !!! <----
)
except:
mb.showerror(
'Ошибка',
f'Неверный формат записи в конфигурационном файле: строка {c}.')
exit()
keyboard.wait('ctrl+alt+x')
