개요
PyQt5로 GUI 애플리케이션을 개발하다 보면, 시그널과 슬롯(signal & slot)은 반드시 이해하고 넘어가야 할 핵심 개념입니다.
특히 다음과 같은 오류를 한 번쯤은 접해 보셨을 수 있습니다.
AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
본 글에서는 이 오류가 발생하는 이유와 함께, "pyqtSignal"을 올바르게 이용하는 방법을 정리해 보겠습니다.
오류 메시지의 의미
다음과 같은 코드에서 오류가 발생했다고 가정해 보겠습니다.
bridge.external_process_terminate_signal.connect(self.do_show_ui)
위 코드에서 발생하는 오류 내용은 다음과 같습니다.
'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
이 메시지가 의미하는 핵심은, "connect()"를 호출한 대상이 “시그널 인스턴스”가 아니라 “시그널 정의 객체(pyqtSignal)”라는 뜻입니다.
pyqtSignal의 올바른 역할 이해하기
"pyqtSignal"은 시그널을 정의하기 위한 클래스 속성용 객체 입니다.
즉, 다음과 같은 용도로만 이용됩니다.
class Bridge(QObject):
external_process_terminate_signal = pyqtSignal()
이 시점에서 "external_process_terminate_signal"은 아직 실제로 연결(connect)할 수 있는 시그널 객체가 아닙니다.
connect()는 언제 이용할 수 있을까?
"connect()"는 객체 인스턴스에 바인딩된 시그널에서만 이용할 수 있습니다.
잘못된 예
Bridge.external_process_terminate_signal.connect(self.do_show_ui)
또는
bridge = Bridge
bridge.external_process_terminate_signal.connect(self.do_show_ui)
위 코드들은 모두 클래스 또는 정의 객체에 접근하고 있기 때문에 위와 같은 "connect" 관련 오류가 발생합니다.
올바른 이용 방법
반드시 QObject를 상속한 클래스의 객체 를 생성한 뒤 시그널을 이용해야 합니다.
from PyQt5.QtCore import QObject, pyqtSignal
class Bridge(QObject):
external_process_terminate_signal = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
bridge = Bridge()
bridge.external_process_terminate_signal.connect(self.do_show_ui)
이때 "bridge.external_process_terminate_signal"은 내부적으로 "pyqtBoundSignal" 객체가 되며, "connect()" 호출이 가능합니다.
시그널에 인자가 있는 경우도 동일합니다
class Bridge(QObject):
external_process_terminate_signal = pyqtSignal(int, str)
bridge = Bridge()
bridge.external_process_terminate_signal.connect(self.on_terminated)
시그널에 전달되는 인자의 유무와 관계없이 “인스턴스에서 접근해야 한다”는 원칙은 동일합니다.
맺는말
다음 항목에 해당한다면, 위와 같은 "connect" 관련 오류가 다시 발생할 가능성이 큽니다.
- "Bridge()" 인스턴스를 생성하지 않고 이용한 경우
- 싱글톤 패턴에서 클래스 자체를 반환하고 있는 경우
- 전역 변수에 "pyqtSignal"을 직접 이용한 경우
- Qt 객체가 아닌 일반 클래스에 시그널을 정의한 경우
다시 정리하면, "pyqtSignal"은 정의용 객체이며 "connect()"를 직접 호출할 수 없습니다. "connect()"는 반드시 QObject 인스턴스에 바인딩된 시그널에서 이용해야 합니다.
오류 메시지가 발생한다면, “지금 내가 클래스에 접근하고 있는가, 인스턴스에 접근하고 있는가”를 먼저 확인해 보시기 바랍니다.
PyQt의 시그널 구조를 정확히 이해해 두면, 멀티스레드, asyncio 연동, 외부 프로세스 제어와 같은 복잡한 구조에서도 안정적인 이벤트 처리가 가능해집니다.
'프로그래밍 > Python' 카테고리의 다른 글
| [python] PyQt5 - 메인 윈도우 생성 후, 실행의 문제점 (0) | 2025.12.15 |
|---|---|
| [python] 클래스 변수와 멤버 변수의 차이 (0) | 2025.12.06 |
| [python] 3.8부터 3.14까지 주요 변경사항 정리 (0) | 2025.10.24 |
| [Python] "struct.calcsize()" 함수 사용 시 유의 사항 (0) | 2025.10.21 |
| [python] 단위시험을 위한 모의 클래스 작성 방법: 직접 상속 / 위임 (0) | 2025.10.17 |