Мне нужно сгенерировать кнопки в цикле и внутри этого цикла назначить каждой кнопке отдельную задачу.
Я знаю, что что-то подобное уже задавалось, и, выполнив поиск, я получил следующий код:
def pressed_0():
print(0)
def pressed_1():
print(1)
def pressed_2():
print(2)
for i in range(0,3):
setattr(self,f"pressed_{i}", qtw.QPushButton(f"button {i}"))
exec(f"self.pressed_{i}.clicked.connect(lambda:pressed_{i}())")
self.layout().addWidget(getattr(self, f"pressed_{i}"))
Что мне не очень нравится, так это использование функции exec() и setattr/getattr. Что я спрашиваю, есть ли лучший способ выполнить то, что мне нужно.
почему не список?
согласно комментарию @eyllanesc, см. stackoverflow.com/a/74320664/9877065 Добавьте динамически виджет в цикл и получите его имя, pyQt5
является ли self.layout.addWidget(button) решением? так что нет необходимости в otf dict или list ?? см. ответ ниже stackoverflow.com/a/78348030/9877065
Как написал Махкита в своем ответе, нет абсолютно ничего плохого в использовании getattr() и setattr(), а exec() всегда следует избегать. Кроме того, его использование в вашем коде совершенно ненужно. Соединения сигналов редко выполняются с помощью чистых функций (обычное использование основано на членах экземпляра), но если вам действительно нужен доступ к таким функциям (и если вы очень осторожны с именами), вам следует предпочесть использовать globals()['someFunction'] для глобальных функции или locals()['someFunction'] для локальных.
Также обратите внимание: если вам специально не нужен доступ к именам этих кнопок (из-за жестко закодированных ссылок или снова через getattr()) в другой части вашего кода, вам, вероятно, вообще не нужно использовать setattr(): просто создайте локальную переменную и работайте с этим, как только виджет добавляется к родительскому элементу (как вы делаете с макетом addWidget()), вам не нужно заботиться ни об атрибуте экземпляра, ни о возможной сборке мусора, потому что с этого момента родительский элемент имеет стал владельцем этого виджета (на стороне C++), и Python его точно не удалит.






Всегда следует избегать использования exec(). Хотя в getattr() нет ничего плохого.
Если вы хотите получать задачи для кнопок динамически, на основе индекса цикла, без использования getattr не обойтись.
Вот рабочий пример с альтернативой без getattr:
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
class Window(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout(self)
self.buttons = []
for i in range(3):
but = QPushButton(f'button {i}')
func = getattr(self, f'pressed_{i}')
but.clicked.connect(func)
layout.addWidget(but)
self.buttons.append(but)
# alternative without getattr:
self.button_tasks = (
self.pressed_0,
self.pressed_1,
self.pressed_2,
)
for i, func in enumerate(self.button_tasks):
but = QPushButton(f'button {i}')
but.clicked.connect(func)
layout.addWidget(but)
self.buttons.append(but)
@staticmethod
def pressed_0():
print(0)
@staticmethod
def pressed_1():
print(1)
@staticmethod
def pressed_2():
print(2)
app = QApplication([])
window = Window()
window.show()
app.exec_()
При использовании альтернативного метода задачам не обязательно иметь определенное имя и даже не обязательно быть методами класса.
Почему в обоих примерах вы используете строку self.buttons.append(but)? Кажется, это бесполезно
@Ferex, это на тот случай, если позже тебе понадобится доступ к кнопкам. Если вы этого не сделаете, вы можете опустить список кнопок.
Допустим, вы хотите отключить кнопку 1, вы можете это сделать self.buttons[1].setEnabled(False)
Используй словарь