Сигнал PySide/PyQt, который может передавать любое значение (включая None)

У меня проблема с использованием механизма Qt signal/slot в PySide, когда я хочу отправить None.

Предположим, у меня есть класс с именем Calculator (подкласс QObject), который может выполнять определенные вычисления, результатом которых может быть что угодно, то есть любой тип объекта Python или даже None. Мне нужны экземпляры класса Calculator, чтобы иметь возможность сигнализировать результат некоторым потребительским объектам (подклассам QObject).

Что у меня было:

class Calculator(QObject):
    finished = PySide.QtCore.Signal(object)  # object means it can transmit anything

    def calc(self):
        ... # calculation of the result
        self.finished.emit(result)

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)

    def consume(self, result):  # do something with the result
        ...

Это работает нормально, за исключением ситуации, когда результатом является None. Затем программа вылетает при отправке сигнала. Кажется, что None не является объектом Python (что может быть правдой, я не настолько хорошо разбираюсь в языковых стандартах).

Теперь у меня есть обходной путь, используя два сигнала:

    finished = PySide.QtCore.Signal((),(object,))

и:

    def calc(self):
        ... # calculation of the result
        if result is None:
            self.finished.emit()
        else:
            self.finished[object].emit(result)

Это решение работает, но оно сложное, поскольку требует, чтобы объекты-потребители дважды связывали сигнал. Либо на два слота, либо на один слот с одним аргументом по умолчанию, равным None.

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)
        calculator.finished[object].connect(self.consume)

    def consume(self, result=None):  # do something with the result
        ...

Это сложно и чревато ошибками при создании множества различных потребительских классов. Я думаю, что эта проблема аналогична PyQt, с той разницей, что альтернативные сигналы определяются с использованием списков [], [object], а не кортежей (),(object,).

Мой вопрос: есть ли какое-нибудь простое решение этой проблемы? В идеале с одним сигналом?


person V.K.    schedule 13.01.2014    source источник
comment
Это было бы ошибкой, если бы PySide каким-то образом не смог выдать None (что, безусловно, является добросовестным объектом Python). Однако я тестировал с помощью PySide-1.2.1 и не смог воспроизвести вашу проблему. Я также никогда не видел такой проблемы в PyQt. Так что либо вы делаете что-то не так где-то в своем коде, либо это ошибка в версии PySide, которую вы используете.   -  person ekhumoro    schedule 14.01.2014
comment
@ekhumoro Хорошо, я должен подтвердить, что когда я тестировал другие версии PySide и PyQt, ошибка исчезла. Я еще раз проверю остальную часть своего кода и, вероятно, удалю вопрос. Очевидно, что проблема в другом. Я голосую за ваш ответ за исправление моего утверждения.   -  person V.K.    schedule 14.01.2014


Ответы (2)


Кроме того, эта ошибка все еще существует в PySide, где она дает сбой при передаче сигнала None начиная с версии 1.2.1 (существует с версии 1.1.0). Отчет об ошибке находится по адресу:

https://bugreports.qt-project.org/browse/PYSIDE-17

Очевидно, что решение VK по инкапсуляции None в отдельный класс все еще работает, как и выбор другого типа для передачи (я переключил свой None на float('nan')). Я просто хотел обновить это, так как столкнулся с той же проблемой и нашел это, а затем отчет об ошибке, объясняющий segfault.

person user2438899    schedule 24.04.2014

Сразу после публикации моей проблемы я нашел ответ. Поэтому я прошу прощения за ответ на свой вопрос - я знаю, что это не так, как должно быть в StackOverflow. Я создал класс с именем ResultHolder, который инкапсулирует реальный результат (результат является переменной-членом этого класса). Затем я передаю экземпляры этого класса ResultHolder. Остальная часть решения тогда просто проста.

person V.K.    schedule 13.01.2014
comment
Нет ничего плохого в том, чтобы ответить на свой вопрос. Наоборот, на самом деле, потому что это позволяет людям не тратить время на ответы на вопросы, которые больше не актуальны. Сказав это, пожалуйста, посмотрите мои комментарии к вашему вопросу. - person ekhumoro; 14.01.2014
comment
@ekhumoro: проблема обычно возникает, когда есть лучшие ответы, а ОП не признают этого и будут придерживаться своих собственных ответов. - person lpapp; 14.01.2014
comment
@ЛаслоПапп. Не уверен, что вы имели в виду, но я бы не стал тратить время на ответ на вопрос, если бы из собственного ответа ОП я увидел, что он действительно решил свою проблему. С другой стороны, если его ответ в чем-то неверен или неадекватен, то я могу либо предложить лучший ответ, либо указать на недостатки с некоторыми комментариями. руководство по SO явно призывает пользователей отвечать на свои вопросы. - person ekhumoro; 14.01.2014
comment
@ekhumoro: например. stackoverflow.com/questions/21083277/ или stackoverflow.com/questions/21077767/ - person lpapp; 14.01.2014
comment
@ЛаслоПапп. Ну, конечно, вы можете привести лошадь к воде и т. Д. Но если бы ОП не опубликовал этот неправильный ответ, как бы вы узнали, как его исправить? - person ekhumoro; 14.01.2014
comment
@ekhumoro: я никого не исправляю, когда отвечаю. Я просто даю лучшее из своих знаний. Проблема возникает, когда ОП не принимают, что их ответы не так хороши, как альтернативы... - person lpapp; 14.01.2014