Путевые заметки в процессе познания Python и PyQt/PySide.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.
Помни - только тег CODE не портит код добавлением пробела в начало пустой строки.
К вопросу о глобальных переменных и инкапсуляции в приложениях PyQt.
Запись от iamvic размещена 14.11.2021 в 11:48
Обновил(-а) iamvic 15.11.2021 в 19:22 (поправил форматирование текста)
Обновил(-а) iamvic 15.11.2021 в 19:22 (поправил форматирование текста)
Как обычно, ничего нового не скажу (и не покажу ), а просто, пока не забылось, запишу в Памятку свои слегка причёсанные мысли по поводу, пересекающемуся с тем, что написано здесь https://www.cyberforum.ru/blog... g7326.html. Вот после прочтения этой статьи ни с того, ни с сего и озадачился я вопросом: А существуют ли в Qt/PyQt "глобальные переменные" достаточно близкие по смыслу к тому, который вкладывает в это понятие уважаемый Viktorrus? Не такие, как глобальные константы, перечисленные в пространстве имён Qt, а действительно настоящие глобальные переменные. Такие, чтобы в любой точке выполнения программы их можно было создать, получить или изменить их состояние или значение и, наконец, удалить. Или убедиться, что переменная уже существует или её ещё нет. И как-то долго подспудно всё свербило, что я уже делаю нечто подобное в своих поделках. Что-то такое в одном месте создаю, открываю в другом, пользую повсеместно, а закрываю только на выходе. И всё это делаю "по имени"... Но это же QSqlDatabase!!! Кликните здесь для просмотра всего текста
И если требуются дополнительные соединения, то поступаю точно также - создаю их по имени и получаю для работы тоже по имени, используя соответствующие Static Public Members класса QSqlDatabase. Ну и чем это отличается от "глобальной переменной"? Только механизмом доступа - не напрямую, а с помощью запросов "по имени", хотя, наверное, правильнее сказать "по псевдонимам". Cъобезьяничать это решение из QSqlDatabase оказалось до неприличия просто. У меня получился вот такой минималистичный вариант, который хранит так называемые "глобальные переменные" в свойстве класса, а доступ к ним обеспечивает методами класса, подобными Static Public Members. Наверняка что-то подобное где-то уже предлагалось, но что получилось, то получилось. Пусть будет... Файл global_vars.py: Кликните здесь для просмотра всего текста
Сюда уже можно накрутить чего попало - и журналирование "кто чего создавал, менял, удалял", и защиту какую-нибудь сочинить в стиле "не ты создавал - не тебе менять и удалять" и так далее. Простейший пример того, как всё это работает, представлен ниже. Там вроде бы всё понятно и без комментариев. Файл main.py: Кликните здесь для просмотра всего текста
Файл my_object.py: Кликните здесь для просмотра всего текста
Результаты выполнения: Кликните здесь для просмотра всего текста
Код:
user@linux:~/MyProjects/qtprobe/global_probe> python3 main.py 0: __main__ --> global vars list = [] 0: __main__ --> is global_kg found? = False 0: __main__ --> value of global_kg = None 0: object_x --> global vars list = [] 0: object_x --> is global_kg found? = False 0: object_x --> value of global_kg = None 1: __main__ --> global vars list = ['global_kg'] 1: __main__ --> is global_kg found? = True 1: __main__ --> value of global_kg = 1000 1: object_x --> global vars list = ['global_kg'] 1: object_x --> is global_kg found? = True 1: object_x --> value of global_kg = 1000 2: __main__ --> global vars list = [] 2: __main__ --> is global_kg found? = False 2: __main__ --> value of global_kg = None 2: object_x --> global vars list = [] 2: object_x --> is global_kg found? = False 2: object_x --> value of global_kg = None user@linux:~/MyProjects/qtprobe/global_probe> И нельзя не упомянуть про ограничения. Ведь послуживший примером для подражания класс QSqlDatabase порождает и хранит подобным образом только экземпляры своего класса. При этом сам класс QSqlDatabase не наследуется от класса QObject. Поэтому все порождаемые им соединения не вступают в родительские отношения с теми объектами, в которых были выполнены вызовы QSqlDatabase.addDatabase(), что позволяет этим соединениям спокойно существовать даже после удаления этих объектов. Предложенное здесь решение это никак не контролирует. И скорее всего следует ожидать неприятностей, если где-то в произвольном месте программы удалить родителя дочернего объекта, сохранённого в такой "глобальной переменной". Потому как этот дочерний объект будет удалён вместе с родительским. Впрочем и некий бонус появляется — в качестве псевдонима годится любая строка, в том числе и на родном — великом и могучем По крайней мере, некоторая часть комментариев становится не нужна. PS: поправил форматирование текста. Однако, спойлеры имеют значение На широких-то экранах это не ощущается, а на маломерках просто срам PPS: впрочем, помогло не очень Хотя в предпросмотре редактора записи смотрелось приемлемо. |
Всего комментариев 19
Комментарии
-
Запись от Avazart размещена 14.11.2021 в 14:56 -
iamvic к сожалению я не могу оценить Ваши наработки, так как не знаю и не работаю с PyQt. Но я поддерживаю Ваше стремление освободится от ограничений, там где они становятся тормозом.
Шаблоны хороши тем что они упрощают мышление, но если жестко следовать им, то они ограничивают мышление. Все прорывные открытия происходили тогда, когда вырывались за пределы шаблонов.
Удачи в Ваших изысканиях.Запись от Viktorrus размещена 15.11.2021 в 19:22 -
Viktorrus, как это? Там же из Qt только идея съобезьянена, а в реализации голый Python...
Запись от iamvic размещена 15.11.2021 в 19:40 -
Запись от Avazart размещена 15.11.2021 в 20:15 -
iamvic может у Вас использован только питон, но Вы ссылаетесь на Qt, и Ваши ссылки мне не понятны, и это усложняет понимание Вашего кода. Извините, но мне сейчас не хочется разбираться в Вашем коде, так как голова занята другим проектом. Может быть потом, когда будет свободное время, попробую разобраться. Но только если для этого не понадобится понимание работы Qt.
Запись от Viktorrus размещена 15.11.2021 в 20:43 -
Viktorrus, нет проблем! Обращайтесь, если что...
Запись от iamvic размещена 15.11.2021 в 20:57 -
Avazart, давайте на этом и остановимся.
Запись от iamvic размещена 15.11.2021 в 23:35 -
Похоже страсти ненужные улеглись, можно и продолжить.
Оставим в стороне обсуждение вопросов типа "хорошо архитектуре или плохо", поскольку там, по определению, главной направляющей и движущей силой является архитектурный стиль и выносить на публику эту глубоко интимную вещь смысла нет. Лучше зададимся вопросом: "А имеет ли право на жизнь послуживший примером для моей поделки способ получения соединения с базой данных, реализованный в QSqlDatabase?"
На мой непросвещённый взгляд, это решение Qt/PyQt вполне годно и для применения в многопоточных приложениях. Там ведь требуется создавать уникальное соединение прямо в дополнительном потоке. А это очень просто делается именно этим способом.
Скупиться на объяснения не буду - расскажу подробно. Надо всего лишь:
1. создать свой подкласс, унаследовав его от QThread;
2. реализовать в нём дополнительные методы, позволяющие через потоконезависимые переменные передавать в дополнительный поток параметры соединения: хост, порт, логин, пароль, имя БД и так далее;
3. в перегруженном методе run() предусмотреть последовательное выполнение следующих действий:
- сгенерировать уникальное имя соединения для использования в QSqlDatabase.addDatabase(),
- получить переданные извне параметры соединения,
- создать экземпляр соединения с помощью QSqlDatabase.addDatabase(), используя сгенерированное имя соединения,
- задать параметры соединения в полученном экземпляре и открыть его.
- выполнять свою работу, периодически отправляя сигналы, содержащие данные для обработки в основном потоке.
- по завершению работы - закрыть соединение,
- а затем удалить его с помощью QSqlDatabase.removeDatabase()
А при создании дополнительного потока требуется только передать ему параметры соединения до его запуска методом start().
Как мне представляется, в этом случае неплохим бонусом является также возможность контроля наличия соединений с помощью QSqlDatabase.connectionNames() из любой точки программы.Запись от iamvic размещена 18.11.2021 в 15:26 -
iamvic для меня всегда критерием истины была практика. Если у Вас это реально работает, то поздравляю. Не зависимо от того, существуют ли другие методы передачи данных между потоками, то что Вы имеете свой метод, позволяет вносить в него изменения, позволяющие Вам его приспосабливать под конкретные задачи, что не всегда легко с чужими программами.
Запись от Viktorrus размещена 18.11.2021 в 22:08 -
Цитата:На мой непросвещённый взгляд, это решение Qt/PyQt вполне годно и для применения в многопоточных приложениях.
Как еще шутят что в питоне нет "многопоточности" есть только "полупоточность".
Цитата:Оставим в стороне обсуждение вопросов типа "хорошо архитектуре или плохо", поскольку там, по определению, главной направляющей и движущей силой является архитектурный стиль и выносить на публику эту глубоко интимную вещь смысла нет.
Так как не стоит путать стиль и отсутствие такового.
Цитата:1. создать свой подкласс, унаследовав его от QThread;Запись от Avazart размещена 18.11.2021 в 22:43
Обновил(-а) Avazart 18.11.2021 в 22:48 -
Viktorrus, ну хватит уже этой демагогии. Ближе к делу. Вы же с кодом до сих пор не разобрались. На хрена мне эти Ваши благие рассуждения?
Запись от iamvic размещена 18.11.2021 в 23:13 -
Avazart,
Цитата:Как еще шутят что в питоне нет "многопоточности" есть только "полупоточность".
Цитата:Так как не стоит путать стиль и отсутствие такового.
Цитата:Сразу плохое начало
Цитата:Place the function in a reimplementation of QThread::run() and start the QThread. Emit signals to update progress.
Это ж питон, а не C++, где наверное уже без этого обходятся? Не так ли?Запись от iamvic размещена 18.11.2021 в 23:47 -
Цитата:Дыкть другой-то всё-равно нет. Пользуем то, что есть.
Так же в некоторых случая допустимо использовать процессы.
Цитата:Этт точно! Нежелание спорить о вкусах свидетельствует об отсутствии вкуса. (надо занести в мемориз)
Цитата:Это ж питон, а не C++, где наверное уже без этого обходятся? Не так ли?
Не то что бы наследовать неправильно, это скорее менее очевидно и как правило ведет к ошибкам в коде.
Что бы использовать наследование нужны какое-то обоснование.Запись от Avazart размещена 19.11.2021 в 14:13
Обновил(-а) Avazart 19.11.2021 в 14:16 -
Avazart,
Цитата:Есть С++ и другие языки.
Цитата:Стиль кода это не вкус это обязательна вещь для программиста.
А спорить чей стиль лучше, по моему мнению, это пустопорожняя болтовня. Чтоб получился какой-то полезный выхлоп с этих споров, надо же на что-то опираться. А для этого надо иметь какое-никакое формализованное описание своего стиля. Вот тогда можно будет провести хоть какое-то сравнение и сделать более-менее обоснованные выводы.
Но как-то не наблюдается в округе войн стилей, где кипели бы страсти и спорящие швыряли бы друг в друга UML-ки, поражающие своей крутизной. Все тихо. Отдельные выкрики "Плохой стиль! Плохо для архитектуры!" обычно пропускаются мимо ушей, поскольку не сопровождаются формализованным обоснованием.
Цитата:Смотрите примеры на С++ из той же документации там увидите пример использования Worker класса.
А вот "использование Worker класса" - это песня из другой оперы. Это QThread с временем жизни от пуска программы до её завершения (permanent), это специально обученный QObject и moveToThread(). Здесь мне это не требовалось.
И, кроме того, Вы прекрасно знаете, что у меня в блоге есть пара записей на эту тему, где я как раз и упражнялся с упомянутым Вами вариантом использования QThread, сочиняя свой "тренажёрчик" в попытке понять что можно делать, а что нельзя, какие там особенности, неожиданности и прочее (здесь Иллюстрация к вопросу о многопоточности в PyQt5. и здесь Обновление к вопросу многопоточности в PyQt5). Вы же там в комментариях отмечались. Да, там не идеальный код, жуткий стиль, куча других недостатков, которые надо бы устранить, что однако не мешает выполнению основной задачи и позволяет в какой-то степени понять происходящие процессы.Запись от iamvic размещена 19.11.2021 в 21:56 -
"Viktorrus, ну хватит уже этой демагогии. Ближе к делу. Вы же с кодом до сих пор не разобрались. На хрена мне эти Ваши благие рассуждения?"
Грубо. Я занимаюсь разработкой своей технологии и в Вашей технологии у меня на данный момент нет реальной необходимости. Но теперь, после Вашей грубости, боюсь у меня уже и не появится желание вникать в Ваш проект, что бы дать свою оценку.
Желаю удачи.Запись от Viktorrus размещена 19.11.2021 в 22:18 -
Цитата:Конечно, есть. Но к несчастью, этот блог посвящён питону и здесь будет только питон и про питон (вот такой каламбурчик получается).Цитата:Да, там не идеальный код, жуткий стиль, куча других недостатков, которые надо бы устранить, что однако не мешает выполнению основной задачи
Цитата:Вы меня удивляете! Здесь мне требовался как раз одноразовый QThread, чтобы "выстрелил и забыл". А отработавши, доложился и удалился.
А вот "использование Worker класса" - это песня из другой оперы. Это QThread с временем жизни от пуска программы до её завершения (permanent), это специально обученный QObject и moveToThread(). Здесь мне это не требовалось.
P.S: И освойте что ли git наконец.Запись от Avazart размещена 20.11.2021 в 00:12
Обновил(-а) Avazart 20.11.2021 в 00:16 -
Avazart,
Цитата:Как такой кАЛОмбурчик?
Цитата:Глупость. Сначала что ли посмотрите примеры из документации а если нет почитайте статьи на эту тему.
А если есть претензии к моему коду, то он лежит тут в открытом доступе. Не составляет труда ткнуть пальцем в проблемные места и доходчиво объяснить почему, даже матерно. И я Вас пойму. Все мы учимся чему-нибудь всю жизнь...
Начните хотя бы с этого (цитирую отсюда Многопоточные технологии в Qt раздел примеры использования):
Цитата:1. время жизни потока — постоянно,
2. функционирование — с помощью объекта, живущего в дополнительном потоке, который может выполнять различные задачи по запросу и/или получать новые данные для работы,
3. реализация — создать подкласс QObject для создания исполнителя работ, создать экземпляр исполнителя (объект Worker) на базе этого подкласса и экземпляр дополнительного потока QThread, переместить экземпляр исполнителя во вновь созданный поток, отправлять команды или данные объекту исполнителя через соединения сигнал-слот с постановкой в очередь.
Цитата:You can use worker objects by moving them to the thread using QObject::moveToThread().
Все эти мои претензии к Вашей манере вести беседу, как видите, весьма обоснованы.
Если же Вы не тянете взятую на себя роль цензора, то сдерживайте себя, сожмите в кулачок весь свой пыл к выставлению оценочек и помалкивайте. Обосновать их Вы всё равно не сможете, а Ваше личное необоснованное мнение никого не интересует - авторитетов здесь нет.
Напоминаю ещё раз, что в этом блоге Вы в гостях. Здесь можно послать куда угодно и высказать любое мнение в любой форме. Но это должно быть обосновано. Повторюсь, авторитетов нет, помощь приму с благодарностью, на слово не верю и быковать тут не стоит.Запись от iamvic размещена 20.11.2021 в 13:01 -
Цитата:Ну, блин, соблюдайте же элементарные правила вежливости в конце концов - обосновывайте своё мнение. И если уж посылаете, то посылайте адресно, указав ссылочки и своё толкование изложенного там, как этого требуют правила форума.
https://doc.qt.io/qt-5/qthread.html#details
Первый пример.
Касательно статей лень гуглить и перебирать что бы сейчас найти что-то действительно толковое.
Но если сходу и не придираясь:
https://habr.com/ru/post/150274/
Т.е. что за манера все попрошайничать и совершенно не пытаться нагуглить самому?
Цитата:А если есть претензии к моему коду, то он лежит тут в открытом доступе.Запись от Avazart размещена 21.11.2021 в 00:18
Обновил(-а) Avazart 21.11.2021 в 00:26 -
Ну, всё, Avazart, доигрались!
Чтобы воспринимать моё скромное законное требование обосновать Вашу личную позицию, подтвердив её ссылками и развёрнутым описанием Вашего личного понимания того, о чём там говорится (а без Вашего подробного объяснения Ваша личная позиция так и останется нераскрытой), как попытку выклянчить у Вас что-то - это ж надо обладать таким извращённым мышлением, что я просто теряюсь.
Считайте, что Вы своего добились - права голоса Вы отныне лишены.Запись от iamvic размещена 21.11.2021 в 10:21