Получение pyqtSignal от Singleton

В python есть одноэлементный класс:

from PyQt5.QtCore import QObject, pyqtSignal
import logging

class Singleton(QObject):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not isinstance(cls._instance, cls):
            cls._instance = QObject.__new__(cls, *args, **kwargs)
        return cls._instance


class DataStatus(Singleton, QObject):
    '''
    '''
    dataChanged = pyqtSignal(str)
    __val = 'init'

    def __init__(self):
        super().__init__()

    def setVal(self, val):
        self.dataChanged.emit('emit: ' + val)
        logging.debug('emit: ' + val)
        self.__val = val

    def getVal(self):
        return self.__val

Идея состоит в том, чтобы иметь одно хранилище данных, доступное из всей программы. Каждый раз, когда вызывается set Method, должен быть послан сигнал, сообщающий всем экземплярам, ​​что откуда-то данные были изменены и должны быть перечитаны.

Классный план, но если посмотреть тестовый код

def test(self):     
    self.ds1 = DataStatus()
    self.ds1.dataChanged.connect(self.windowaction)
    print(self.ds1)
    print(self.ds1.getVal())

    self.ds1.setVal('ds1.first')

    self.ds2 = DataStatus()
    #self.ds2.dataChanged.connect(self.windowaction)
    print(self.ds2)
    print(self.ds2.getVal())

    self.ds2.setVal('ds2.second')

    print(self.ds1.getVal())

def windowaction(self, q):
    print(q)

И вывод на консоль получается странным (по крайней мере, для меня):

<DataStatus.DataStatus.DataStatus object at 0x03207580>
init
emit: ds1.first
<DataStatus.DataStatus.DataStatus object at 0x03207580>
ds1.first
ds2.second

У обоих экземпляров один и тот же адрес, круто, синглтон выполняет свою работу. К ds1, если подключили сигнал "dataChange", который работает правильно, если данные из ds1 обновляются. НО сигнал не будет получен ds1, если я изменю данные с помощью ds2.set......

У кого-нибудь есть объяснение того, что здесь происходит. Данные правильно распределяются между экземплярами, но не сигналы:-/

1 ответ

Решение

Хотя ваш класс Singleton соответствует тому, что один и тот же объект всегда возвращается, но это не означает, что он правильно реализован, в вашем случае в новом создается новый объект, но вы возвращаете первый созданный объект (выполняя то, что вы, по-видимому, хотите), но сигнал dataChanged принадлежит новому объекту, а не первому объекту, вызвавшему проблему. Решение в этом случае - использовать метаклассы, как указывает эта библиотека:

class Singleton(type(QObject), type):
    def __init__(cls, name, bases, dict):
        super().__init__(name, bases, dict)
        cls._instance = None

    def __call__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance


class DataStatus(QObject, metaclass=Singleton):
    dataChanged = pyqtSignal(str)
    __val = "init"

    def __init__(self):
        super().__init__()

    def setVal(self, val):
        self.dataChanged.emit("emit: " + val)
        logging.debug("emit: " + val)
        self.__val = val

    def getVal(self):
        return self.__val
Другие вопросы по тегам