Как можно исправить проблему с использованием параметра `command` у кнопки в customtkinter внутри цикла for?

Как можно исправить код, чтобы вывод в консоль при нажатии на кнопку соответствовал номеру кнопки, исключая случай 19 вывода при нажатии на любую из кнопок?
  • 5 августа 2024 г. 17:13
Ответы на вопрос 2
Для исправления проблемы с использованием параметра `command` у кнопки в customtkinter внутри цикла for, можно воспользоваться замыканием с использованием lambda функции. 

Пример исправленного кода:

```python
from customtkinter import *

def button_click(num):
    if num != 19:
        print(f'Button {num} clicked')

root = Tk()

for i in range(20):
    btn = Button(root, text=f'Button {i}', command=lambda num=i: button_click(num))
    btn.pack()

root.mainloop()
```

В данном примере при нажатии на любую кнопку (кроме кнопки с номером 19) будет выводиться номер нажатой кнопки в консоль.
Ну классика же, lambda завязывается на саму переменную, а не на её текущее значение. Т.е. если ты изменишь i, то все лямбды это увидят. 
i = 10
f = lambda: print(i)
i = 20
f()  # выведет 20

Нужно сохранить искомое значение в самой лямбде. Самый простой способ - вот такой хак:
i = 10
# сохраняем глобальную i как значение по умолчанию параметра i
f = lambda i=i: print(i)  
i = 20
f()  # выведет 10
f(30)  # выведет 30

Как видишь последний вызов работает немножко не так, как мы ожидаем - а ожидаем мы ошибку из-за лишнего параметра. Но можно схитрить так:
i = 10
# сохраняем глобальную i как значение по умолчанию параметра i
# Параметр i может быть передан только по имени: i=30
f = lambda *,i=i: print(i)  
i = 20
f()  # выведет 10
f(i=30)  # выведет 30
f(30)  # TypeError: <lambda>() takes 0 positional arguments but 1 was given
Похожие вопросы