Это просто, как область видимости, поиск имени и замыкания определены в Python.
Python вводит новые привязки в пространство имен только через присваивание и списки параметров функций. Следовательно, i
фактически не определяется в пространстве имен lambda
, а в пространстве имен __init__()
. Следовательно, поиск имени для i
в лямбде заканчивается в пространстве имен __init__()
, где i
в конечном итоге связывается с 9
. Это называется "закрытием".
Вы можете обойти эти предположительно не очень интуитивные (но четко определенные) семантики, передав i
в качестве аргумента ключевого слова со значением по умолчанию. Как уже говорилось, имена в списках параметров вводят новые привязки в локальное пространство имен, поэтому i
внутри lambda
становится независимым от i
в .__init__()
:
self._numberButtons[i].clicked.connect(lambda i=i: self._number(i))
Более читабельная, менее волшебная альтернатива functools.partial
:
self._numberButtons[i].clicked.connect(partial(self._number, i))
Здесь я просто для удобства использую синтаксис сигналов и слотов нового стиля, синтаксис старого стиля работает точно так же.