¿Mejor manera de manejar el enlace de dos vías en PyQt?

Actualmente estoy usando PyQT, que me gusta mucho hasta ahora. Sin embargo, necesito tener enlaces de dos vías y, a partir de la escasa información que pude encontrar en Internet, esta es la forma de hacerlo. Cree una propiedad PyQTP, adjunte un captador, un configurador y una señal (que debe llamarse siempre que el valor haya cambiado para notificar a la GUI).

from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject class Test(QObject): signal = pyqtSignal() def getName(self): print("name gotten") return self._name def setName(self, name): print("name changed to " + name) self.signal.emit() self._name = name name = pyqtProperty('QString', fget= getName, fset= setName, notify= signal) def __init__(self, parent=None): super().__init__(parent) # Initialise the value of the properties. self._name = 'asdf' 

Esto funciona como se esperaba. Sin embargo, no estoy seguro de si lo estoy usando correctamente, pero esto me parece absolutamente horrible. De hecho, huele tan mal que me siento inclinado a abrir una ventana. En lugar de poder simplemente declarar un atributo, ahora tengo que crear un setter y un getter (antes de la statement incluso, lo que significa que habrá declaraciones en la mitad del archivo de origen) y una señal para cada atributo. Esto conduce a una gran cantidad de código duplicado y archivos fuente ilegibles.

¿Cuál sería la mejor manera de cambiar esto a una o dos líneas? Por ejemplo, a través de la generación automática de código, metaprogtwigción o macros (he buscado en MacroPy, pero no estaba seguro de si este sería el camino a seguir). Así que algo como esto:

 name = # magic Python voodoo, automatically handling setters, getters and the signal 

Gracias de antemano, y avíseme si necesito proporcionar información adicional.

Edit: Gracias a BrenBarn, noté que olvidé mencionar cómo se solicita este código. La GUI se implementa en QML (Qt Markup Language), y este objeto se da a conocer a QML registrándolo (como aquí , qmlRegisterType), después de lo cual QML puede instanciar y manipular instancias de este. Decidí no incluir el ejemplo del código fuente completo por brevedad, y porque estoy interesado principalmente en una mejor manera de manejar el captador / definidor y la creación de instancias de la señal, sin centrarme en QML.

Puede usar un decorador pyqtProperty () como se menciona en la documentación . Al menos elimina la definición separada.

 signal = pyqtSignal @name.setter def name(self, name): self._name = name self.signal.emit() @pyqtProperty('QString', notifiy=signal) def name(self): return self._name