[Python, Программирование, Анализ и проектирование систем, Интерфейсы, Go] Порт GUI фреймворка с Python на Go. Анализ граблей и плюшек
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
С Python мне пришлось работать от безнадеги - ML, нейросетки, скриптинг, то-сё сподручнее было именно на нем. Но время идет и тревога за скорость своего кода толкает к чему то быстрому и более надежному. Задача портировать GUI framework наболела, потому что мой универсальный Unigui работал только из Python и универсальным был только в теории. В нем был наработан предельно лаконичный API, который должен был быть сохранен и в Go варианте. Кроме того масса автоматизма по генерации нужных данных портированию не подлежала, т.к. в Go отсутствует управление порядком компиляции, препроцессор,метапрограммирование, что гарантировало непростой спартанский трип.Первой сложностью, в которую я наступил, была невозможность напрямую присваивать promouted(вложенные) поля в инициализаторе структур и только в нем. Если структура имеет безымянную вложенную структуру, то к ее полям можно обращаться из корня внешней везде, кроме инициализатора. Из-за чего, в том числе, вся затея с вложенными полями как с заменой иерархии стала и сомнительной, и громоздкой в использовании. Требовать от юзера либы писать длинные вложенные с ненужными типами инициализаторы было бы верхом неприличия. Все GUI структуры стали абсолютно плоские, независимые, хотя в Python есть четкая иерархия.Словоблудие, которые Go требовал при сборке объектов, все равно оставалось. Пользователю библиотеки нужен краткий понятный вызов, а тут я должен заставить его помнить поля объекта и использовать в инициализаторе и каким-то образом указать, что некоторые должны быть обязательно заполнены, а дефолтные параметры низзя,они, как оказалось, “следствие плохого дизайна API”. Золотые слова, как обычно, с реальностью не коррелирующие. Было решено спрятать это с глаз и дать юзеру набор хэлперов с теми же именами, что должны быть у типов, которые будут делать всю нудную работу и возвращать сразу указатель. Что пользователю легко забыть хэлпер сделает сам. Типы объектов стали выглядеть как Type_ a хелпер Type(…) возвращает *Type_. По сути, это конструкторы из ООП, чтобы скрыть неприглядные моему и юзера либы взору кишки Go кода.Сериализация Go в Json не осталась в стороне и взбодрила порцией эзотерики в своих деталях. nil работает как пустой массив в вызовах функций слайсов (массивы переменной длины), однако при сериализации поля слайса с nil он продолжает быть nil a не как во всех других языках/библиотеках [ ] . То, что тип переменной слайс - по фигу. Оk, Google, возьмем стороннюю либу с фиксом на это дело или будем в хелперах проверять, если массив == nil, то надо ему написать = make(0, []Any). Если поле структуры имеет неинициализированный указатель на функцию, то напрямую он == nil, а если запросить его значение через reflect то он != nil. Однако если дописать бессмысленную на первый взгляд reflect.ValueOf(ptr).IsNil() то, о чудо, это true! Гениально, чо..Добить меня они решили отсутствием стандартной функции hash. Так мне тогда показалось. Это ж надо было умудриться. Проверил на всякий случай список арифметических операторов. Вроде все есть. Выдохнул и стал пробираться дальше.Почему можно выводить и не писать тип для простой переменной можно, но нельзя для массива или мапы?? Ведь итоговый тип либо равен типу первой переменной, если он совпадает с остальными в списке, либо Any - interface{}. Всё! А потому явно писать тип для мапов и слайсов, когда он 100% очевиден - это проявление внимания к работе компилятора. “Вам мелочь, а ему приятно!” Про ненормальное определение видимости переменных и функций через регистр первой буквы. Наверное, это не новость, однако же и ломка сознания (известные мне языки такую дичь не используют) и путаница, где тип, а где объект. Если кажется что к этому можно привыкнуть и перетерпеть, то дичь будет лезть везде, где пролезет. Вот хотим мы сделать сериализацию готового протокола, а имена в нижнем регистре использовать не можем (доступа не будет). Любезный Google предлагает нам костыль с блестками в виде добавок к описанию поля типа MyField int json:"myfield" и вроде бы ничего, с JSON мы выпутываемся. Подумаешь - пробежаться по сотне-другой полей и дописать эту фуфу. А если сериализация в другой протокол? Тогда, горемычные, - ваши проблемы, они и так вон чего тебе аж, а вам все мало. Пиндюрь к каждой структуре свою функцию кодирования и радуйся что ээ.. да просто радуйся! Тот же гугловый Dart имеет симпатичную декларацию видимости через _ впереди для ее ограничения. К слову сказать, ВСЕ печальки Go в Dart-е отсутствуют, и наоборот. Т. е. создается ощущение, что кривозубые решения в дизайне языков в Google решили между ними поделить, и ни один такой “прикол” не вошел одновременно в оба языка. Кто это, интересно, у них это раздает, и следит, чтоб всем поровну?Отсутствием на данный момент дженериков, функторов map/filter/.. , коротких лямбд и даже таких элементарных операций с массивами как RemoveAtIndex, возмущались и до меня, но с добавкой дженериков в 1.17 часть этого уйдет, но я готов поставить ящик мороженого, что в них докинут новой эпидерсии, чтоб не сильно радовались.Зачем вам интерполяции строк? Забейте! Вместо этого предлагается использовать разлапистый fmt.Sprintf. Что за необходимость писать допотопный С-код в современном языке - тайна великая, а их объяснение, что это сложно компилятору - “муть и компот”.Но есть же и приятные моменты.
- И главный - это скорость. Ощущение, когда пересядешь с допотопного ноута на фаршированный десктоп. Как то сразу хочется понять и простить, остаться, задумываешься как ML-ить на Go…
- Конкурентность/параллелизм. Почувствовав разницу, понимаешь, что использование для нагруженных задач Python-a вместо Go - нехорошо ни разу. Модель гоуроутин - ясная, простая, минимум усилий, максимум выхлопа. Python здесь сливает как бомж-алкоголик директору винзавода.
- Сборка/компиляция - здесь в плюс Go. Импорт либ из github (жирный лайк), мгновенная инкрементная компиляция это не кот накашлял. Правда, последнее уже было в Visual C++ ~20 лет назад, Edit & Continue называлось. Оно, Edit & Continue для Go в моем VS Code не работает, хотя при каждом редактировании при запущенной проге пугает, что изменения якобы внесены. Ни-фи-га. Ну то такое ..
- Объем кода. Примерно одинаково. Что весьма хорошо для Go. Плохо, что добиться этого сразу нельзя. Медитировать, переписывать, хэлперы, алиасы - тогда можно. -Дизайн кода. Довольно просто подсчитать, что если бы Go поддерживал элементарное наследование, то кода в моей либе стало бы на 20% меньше. И работала бы она минимум вдвое быстрее за счет исключения 70% reflect кода. И написал бы вдвое быстрее. Так что лично мне понятно, что вся эта типо инкапсулирующая модель создает больше проблем чем пользы. Причем существенно.
- Сравнение кода. Для создания вот этого экрана в браузере (сервера по умолчанию вешаются на 8000 порт) код на Python и Go.
Go
package main
import . "github.com/Claus1/unigui-go"
func screenTest(user* User)* Screen_{
table := Table("Videos",0, nil, []string{"Video", "Duration", "Links", "Mine"},
SeqSeq(Seq("opt_sync1_3_0.mp4", "30 seconds", "@Refer to signal1", true),
Seq("opt_sync1_3_0.mp4", "37 seconds", "@Refer to signal8", false)))
cleanButton := Button("Clean table", nil, "")
selector := Select("Select", "All", nil, []string{"All","Based","Group"})
block := Block("X Block", Seq(cleanButton, selector), table)
block.Icon = "api"
return Screen(block)
}
func main(){
//register screens
Register(screenTest, "Main", 0, "insights")
Start()
}
Python
from unigui import *
name = "Main" #name of screen to show
icon = 'blur_linear' #MD icon of screen to show
order = 0 #order in the program menu
table = Table('Videos', 0, headers = ['Video', 'Duration', 'Links', 'Mine'],rows = [
['opt_sync1_3_0.mp4', '30 seconds', '@Refer to signal1', True],
['opt_sync1_3_0.mp4', '37 seconds', '@Refer to signal8', False]
])
block = Block('X Block',
[
Button('Clean table'),
Select('Select', value='All', options=['All','Based','Group'])
], table, icon = 'api')
blocks = [block] #what to show on the screen
start('Test app')
Буду ли использовать Go дальше? Куда ж я денусь с подводной лодки.. и сильно хочу, чтоб Crystal, Nim, и прочие простые, развитые языки ворвались в продакшен и дали Go пендаля. Пока, к сожалению, альтернативы ему в нише легкой продакшен разработки производительного ПО не наблюдаю. Peace!Ссылки для любознательных:https://github.com/Claus1/unigui-go Go https://github.com/Claus1/unigui Python
===========
Источник:
habr.com
===========
Похожие новости:
- [Ненормальное программирование, Программирование, Машинное обучение] Бонус работы аналитиком данных: Как я нашел свой новый дом в Дублине (перевод)
- [Законодательство в IT, Социальные сети и сообщества] Австралия приняла закон о плате поисковиков за индексируемые новости
- [Go, DevOps, История IT] Почему язык Go стал стандартом для DevOps-инженеров
- [Разработка веб-сайтов, PHP, Программирование, Проектирование и рефакторинг] Run, config, run: как мы ускорили деплой конфигов в Badoo
- [Анализ и проектирование систем, IT-компании] Работа с дубликатами в системе управления данными «Юнидата»
- [Интерфейсы, Usability, Дизайн мобильных приложений, Монетизация мобильных приложений, Интернет-маркетинг] UX-исследование: какие решения помогают зарабатывать миллионы $ приложениям для стриминга видео в прямом эфире
- [Интерфейсы, Киберпанк, Научно-популярное, AR и VR, Мозг] О нейропротезах
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] Разрабатываем чат на React с использованием Socket.IO
- [Python, Программирование] Сохранение сюжетов matplotlib в pdf файл
- [Программирование, Управление персоналом, Карьера в IT-индустрии, Читальный зал] Компульсивная жизнь разработчиков ПО или Почему весь кодинг немного навязчивый? (перевод)
Теги для поиска: #_python, #_programmirovanie (Программирование), #_analiz_i_proektirovanie_sistem (Анализ и проектирование систем), #_interfejsy (Интерфейсы), #_go, #_portirovanie (портирование), #_gui, #_frontend, #_backend, #_razrabotka (разработка), #_python, #_programmirovanie (
Программирование
), #_analiz_i_proektirovanie_sistem (
Анализ и проектирование систем
), #_interfejsy (
Интерфейсы
), #_go
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 14-Ноя 11:33
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
С Python мне пришлось работать от безнадеги - ML, нейросетки, скриптинг, то-сё сподручнее было именно на нем. Но время идет и тревога за скорость своего кода толкает к чему то быстрому и более надежному. Задача портировать GUI framework наболела, потому что мой универсальный Unigui работал только из Python и универсальным был только в теории. В нем был наработан предельно лаконичный API, который должен был быть сохранен и в Go варианте. Кроме того масса автоматизма по генерации нужных данных портированию не подлежала, т.к. в Go отсутствует управление порядком компиляции, препроцессор,метапрограммирование, что гарантировало непростой спартанский трип.Первой сложностью, в которую я наступил, была невозможность напрямую присваивать promouted(вложенные) поля в инициализаторе структур и только в нем. Если структура имеет безымянную вложенную структуру, то к ее полям можно обращаться из корня внешней везде, кроме инициализатора. Из-за чего, в том числе, вся затея с вложенными полями как с заменой иерархии стала и сомнительной, и громоздкой в использовании. Требовать от юзера либы писать длинные вложенные с ненужными типами инициализаторы было бы верхом неприличия. Все GUI структуры стали абсолютно плоские, независимые, хотя в Python есть четкая иерархия.Словоблудие, которые Go требовал при сборке объектов, все равно оставалось. Пользователю библиотеки нужен краткий понятный вызов, а тут я должен заставить его помнить поля объекта и использовать в инициализаторе и каким-то образом указать, что некоторые должны быть обязательно заполнены, а дефолтные параметры низзя,они, как оказалось, “следствие плохого дизайна API”. Золотые слова, как обычно, с реальностью не коррелирующие. Было решено спрятать это с глаз и дать юзеру набор хэлперов с теми же именами, что должны быть у типов, которые будут делать всю нудную работу и возвращать сразу указатель. Что пользователю легко забыть хэлпер сделает сам. Типы объектов стали выглядеть как Type_ a хелпер Type(…) возвращает *Type_. По сути, это конструкторы из ООП, чтобы скрыть неприглядные моему и юзера либы взору кишки Go кода.Сериализация Go в Json не осталась в стороне и взбодрила порцией эзотерики в своих деталях. nil работает как пустой массив в вызовах функций слайсов (массивы переменной длины), однако при сериализации поля слайса с nil он продолжает быть nil a не как во всех других языках/библиотеках [ ] . То, что тип переменной слайс - по фигу. Оk, Google, возьмем стороннюю либу с фиксом на это дело или будем в хелперах проверять, если массив == nil, то надо ему написать = make(0, []Any). Если поле структуры имеет неинициализированный указатель на функцию, то напрямую он == nil, а если запросить его значение через reflect то он != nil. Однако если дописать бессмысленную на первый взгляд reflect.ValueOf(ptr).IsNil() то, о чудо, это true! Гениально, чо..Добить меня они решили отсутствием стандартной функции hash. Так мне тогда показалось. Это ж надо было умудриться. Проверил на всякий случай список арифметических операторов. Вроде все есть. Выдохнул и стал пробираться дальше.Почему можно выводить и не писать тип для простой переменной можно, но нельзя для массива или мапы?? Ведь итоговый тип либо равен типу первой переменной, если он совпадает с остальными в списке, либо Any - interface{}. Всё! А потому явно писать тип для мапов и слайсов, когда он 100% очевиден - это проявление внимания к работе компилятора. “Вам мелочь, а ему приятно!” Про ненормальное определение видимости переменных и функций через регистр первой буквы. Наверное, это не новость, однако же и ломка сознания (известные мне языки такую дичь не используют) и путаница, где тип, а где объект. Если кажется что к этому можно привыкнуть и перетерпеть, то дичь будет лезть везде, где пролезет. Вот хотим мы сделать сериализацию готового протокола, а имена в нижнем регистре использовать не можем (доступа не будет). Любезный Google предлагает нам костыль с блестками в виде добавок к описанию поля типа MyField int json:"myfield" и вроде бы ничего, с JSON мы выпутываемся. Подумаешь - пробежаться по сотне-другой полей и дописать эту фуфу. А если сериализация в другой протокол? Тогда, горемычные, - ваши проблемы, они и так вон чего тебе аж, а вам все мало. Пиндюрь к каждой структуре свою функцию кодирования и радуйся что ээ.. да просто радуйся! Тот же гугловый Dart имеет симпатичную декларацию видимости через _ впереди для ее ограничения. К слову сказать, ВСЕ печальки Go в Dart-е отсутствуют, и наоборот. Т. е. создается ощущение, что кривозубые решения в дизайне языков в Google решили между ними поделить, и ни один такой “прикол” не вошел одновременно в оба языка. Кто это, интересно, у них это раздает, и следит, чтоб всем поровну?Отсутствием на данный момент дженериков, функторов map/filter/.. , коротких лямбд и даже таких элементарных операций с массивами как RemoveAtIndex, возмущались и до меня, но с добавкой дженериков в 1.17 часть этого уйдет, но я готов поставить ящик мороженого, что в них докинут новой эпидерсии, чтоб не сильно радовались.Зачем вам интерполяции строк? Забейте! Вместо этого предлагается использовать разлапистый fmt.Sprintf. Что за необходимость писать допотопный С-код в современном языке - тайна великая, а их объяснение, что это сложно компилятору - “муть и компот”.Но есть же и приятные моменты.
Go package main
import . "github.com/Claus1/unigui-go" func screenTest(user* User)* Screen_{ table := Table("Videos",0, nil, []string{"Video", "Duration", "Links", "Mine"}, SeqSeq(Seq("opt_sync1_3_0.mp4", "30 seconds", "@Refer to signal1", true), Seq("opt_sync1_3_0.mp4", "37 seconds", "@Refer to signal8", false))) cleanButton := Button("Clean table", nil, "") selector := Select("Select", "All", nil, []string{"All","Based","Group"}) block := Block("X Block", Seq(cleanButton, selector), table) block.Icon = "api" return Screen(block) } func main(){ //register screens Register(screenTest, "Main", 0, "insights") Start() } from unigui import *
name = "Main" #name of screen to show icon = 'blur_linear' #MD icon of screen to show order = 0 #order in the program menu table = Table('Videos', 0, headers = ['Video', 'Duration', 'Links', 'Mine'],rows = [ ['opt_sync1_3_0.mp4', '30 seconds', '@Refer to signal1', True], ['opt_sync1_3_0.mp4', '37 seconds', '@Refer to signal8', False] ]) block = Block('X Block', [ Button('Clean table'), Select('Select', value='All', options=['All','Based','Group']) ], table, icon = 'api') blocks = [block] #what to show on the screen start('Test app') =========== Источник: habr.com =========== Похожие новости:
Программирование ), #_analiz_i_proektirovanie_sistem ( Анализ и проектирование систем ), #_interfejsy ( Интерфейсы ), #_go |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 14-Ноя 11:33
Часовой пояс: UTC + 5