Почему этот код только переключает синий цвет? (Python, PyQt)

По какой-то причине запуск этого кода только переключает цвет синий, когда он должен переключать каждый из цветов по отдельности.

Этот код является моей версией кода примера в http://eli.thegreenplace.net/2011/04/25/passing-extra-arguments-to-pyqt-slot , который является учебным пособием для PyQt, который я только что начал обучение.

import sys from PyQt5.QtWidgets import (QWidget, QPushButton, QFrame, QApplication) from PyQt5.QtGui import QColor class Example(QWidget): red = False blue = False green = False buttons = [] def __init__(self): super().__init__() self.init_UI() def init_UI(self): self.col = QColor(0, 0, 0) for x in range(0, 3): self.buttons.append(QPushButton('Red' if x == 0 else ('Green' if x == 1 else 'Blue'), self)) self.buttons[x].setCheckable(True) self.buttons[x].move(10, 10 + 50 * x) self.buttons[x].clicked[bool].connect(lambda: self.set_color(x)) self.square = QFrame(self) self.square.setGeometry(150, 20, 100, 100) self.square.setStyleSheet("QWidget { background-color: %s }" % self.col.name()) self.setGeometry(300, 300, 280, 170) self.setWindowTitle('Toggle button') self.show() def set_color(self, button): if button == 0: if self.red == False: self.red = True self.col.setRed(255) else: self.red = False self.col.setRed(0) elif button == 1: if self.green == False: self.green = True self.col.setGreen(255) else: self.green = False self.col.setGreen(0) else: if self.blue == False: self.blue = True self.col.setBlue(255) else: self.blue = False self.col.setBlue(0) self.square.setStyleSheet("QFrame { background-color: %s }" % self.col.name()) print(self.col.name()) if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) 

Причина, по которой connect(lambda: self.set_color(x)) не работает, заключается в том, что x будет оцениваться только при вызове лямбда, т. connect(lambda: self.set_color(x)) сигнал, который будет намного позже, после завершения цикла. Таким образом, set_color() получит значение x во время выхода сигнала. В вашем коде это будет последнее значение, которое x имеет в цикле, т. Е. 2.

Хотя ответ @ Hi верен, я нахожу решение Achayan (упомянутое в комментарии) более явным и работает просто отлично (вопреки некоторым комментариям – я проверил его с кодом):

 for x in range(0, 3): ... self.buttons[x].clicked[bool].connect(partial(self.set_color, x)) 

Причина этого в том, что x является аргументом вызова функции (функция functools.partial ), поэтому x оценивается немедленно . Функция, возвращаемая partial(f, a) когда f является функцией одного arg, является функцией g() которая не принимает аргументов и будет вызывать f(a) .