ПОГРУЖЕНИЕ В ПИТОН
(С) Гаузер Э.Г., Баку, 25.05.25
website: www.erichware.com
Эта статья является продолжением прошлой статьи "Как я изучал Питон". Как я там и предполагал, при переходе с консоли на окна специфика Питона проявилась в еще большей степени. Попробую изложить основные моменты...
Я продолжил переводить на Питон программы из своего раздела "Исходники", но взялся за более сложные примеры. Сейчас это коснулось программ "gomoku", "geo2utm", "curdir", "codkey" и "testpc". Я не буду разбирать подробно все эти программы, я просто упомяну о важных моментах. Ну и о старых тоже говорить придется.
И начну с того, что работа в среде IDLE, как я уже раньше писал, не равна запуску программы в питоне из командной строки (и, соответственно, в виде скомпилированного exe-файла). Как я понял из форумов, сама среда IDLE выполняет некоторые функции по созданию окон, в итоге даже если ваша программа содержит какие-то ошибки или в ней чего-то не хватает, среда сама это дополнит и программа будет работать, хотя по идее работать не должна! Я так очень долго ломал голову, почему "тут идет, а там нет"...
Кроме того, мне вроде бы удалось понять логику локальных и глобальных переменных (о чем я писал в прошлой статье), при всей ее дикости. Так вот, даже если вы объявили переменную ДО описания всех процедур, внутри них она все равно не будет считаться глобальной, если вы пытаетесь присвоить ей значение. Читать можно, писать нельзя! Принцип странный, но работает так. Посему, от греха подальше, советую явно указывать глобальность нужных переменных внутри процедур. Кстати, при этом можно вообще не описывать переменную ДО списка процедур, если ей не требуется присваивать начальное значение. Достаточно в нужных процедурах написать "global имя".
Должен сказать, что эта логика лично для меня была непривычной и я постоянно забывал об этом требовании...
Еще один важный момент, из-за которого я потерял кучу времени, но не нашел упоминаний в интернете. Дело в том, что в Питоне нет понятия процедура, есть только функция! В чем разница? В других языках разница в том, что функция возвращает одно значение, а процедура нужна тогда, когда возвращать "по имени" ничего не нужно, но зато нужно в теле процедуры изменить несколько переменных. Я стал делать "как привык": "def PROC(vxod1, vxod2, vyxod1, vyxod2)" в расчете на то, что внутри я изменю значения vyxod1 и vyxod2, а в вызывающей процедуре их использую. Как бы не так!
Увы, но изменение значений формальных параметров никак не влияет на значения фактических. Видимо, все переменные передаются в функцию "по значению", а не "по ссылке" (очевидно, именно поэтому транслятор ругает фактическую переменную, которой ранее не было присвоено значение). Но я об этом нигде информацию не нашел... И еще: если в других известных мне языках имя функции является возвращаемым значением (причем никакой специальный "return" для этого не нужен), то тут блок "return имя" для возврата значения обязателен. А если надо вернуть несколько значений, то возврат оформляется так: "return vyxod1,vyxod2", а вызов указанной выше функции так: "vyxod1,vyxod2 = PROC(vxod1, vxod2)", а объявлять ее надо так: "def PROC(vxod1, vxod2)".
Конечно, это не страшно, но только надо об этом знать! Наверно, если выходные переменные нужны и на входе тоже, то их надо указывать в виде параметров. Это логично, но я не проверял, ибо не было нужды.
При написании программ я старался использовать только базовые модули, в частности, вся работа с окнами шла через "tkinter". Как я писал в прошлой статье, при появлении вопросов я прибегал к поиску. Однако замечу, что далеко не все ответы поисковика давали нужную информацию. Например, я чисто случайно узнал, что есть отдельно два виджета работы с текстом: один без скроллов, а другой с вертикальным скроллом. До этого все ответы были о том, что надо вручную создавать эти скроллы и подключать к виджету. Я так и сделал! А потом узнал, что "изобретаю велосипед" и просто взял другой виджет. Вопрос: зачем это нужно? Не проще сделать один виджет, а наличие скроллов оформить как параметр при его создании? Это же логичнее!
Замечу еще одну вещь. Знатоки питона наверняка найдут в моих программах кучу разных "велосипедов", ибо модулей в питоне много, сторонних в том числе. Но поскольку я все это затеял для изучения языка, а не создания коммерческих продуктов к дедлайну, то я вручную делал многое из того, что наверняка уже сделано. Это следует учесть.
Кстати, есть такой модуль - "graphics", про который в интернете много чего хорошего написано. Так вот, я так и не сумел заставить его работать, пришлось опять же через "tkinter". И тут есть важный момент!
Я очень долго не мог понять, почему простая заставка "hind" дико пожирает ресурсы ПК. Естественно, что я стал делать ее "по аналогии" с SB1, VB6 и т.д. (эти коды тоже есть в "Исходниках"). А именно, я спокойно рисовал эллипсы разными цветами в разной позиции. Но оказалось, что каждый эллипс - это объект! В цикле они плодятся сотнями, пожирая ресурсы. То есть, нельзя просто "нарисовать эллипс" и забыть о нем! Тогда я стал в каждом цикле удалять все уже нарисованные объекты. Но это и некрасиво, и создавало неожиданные сложности. Тогда мне пришлось изменить код так, чтобы созданные ЗАРАНЕЕ эллипсы просто перемещались по форме как надо. Это, конечно, правильное решение, но почему нельзя просто рисовать, пикселями?
Кстати, текстовый виджет имеет еще некоторые странности. Например, я привык по правой кнопке видеть стандартное меню работы с буфером обмена. Да, я понимаю, что я привык к Виндовс, а Питон к ней не привязан. Но вот какая заковыка: отметить блок мышью можно. И можно работать с ним без всякого меню, стандартными командами клавиш! А меню встроенного нет! Нужно ли оно? В программе "geo2utm" как раз это было актуально. Я сделал меню из двух пунктов (copy/paste), причем в итоге для 4 боксов конструкция вышла весьма большой (для каждого своя обработка правой кнопки, но зато единые функции для copy и paste по всем 4 виджетам). в общем, логика совершенно для меня новая, но вопрос в том, а нужно ли это все, если по клавишам все и так работает? Я не проверял...
Еще один вопрос с подвохом - это таймер. Точнее, вызов процедур через заданные промежутки времени. В том же Бейсике есть возможность прерывания работы программы по таймеру через заданный интервал. В процедуре прерывания от таймера можно менять какие-то общие переменные, флаги и т.д., а в других частях программы проверять их значение и принимать нужные меры. В "Исходниках" для той же программы "hind" это ясно видно. Естественно, что на Питоне я хотел пойти по той же дороге. Но нет.
По факту я так и не смог сделать нормальное прерывание по таймеру. Это нужно было в двух программах: "hind" и "testpc". Пришлось делать обходные маневры, потому что описанная везде конструкция "OKNO.after(millisek,namefunc)" нормально не работает. В частности, у меня то значение реальных интервалов не соответствовало значению millisek (причем по мере работы программы несоответствие усиливалось), то вообще каша получалась. Я понимаю, что "асы" Питона все это знают, что есть куча книг (хотя на русском материалов о питоне мало) и что если иметь цель выучить язык профессиоеально, то нужно сначала все это несколько месяцев читать, а потом уже писать программы. Но у меня не было ни времени, ни желания, ни потребности лезть в ЖКТ этой змеи по самое не могу... Понятно, что я какие-то основы сначала прочитал. Но как сказано в первой статье, я думал сделать Питон своим "карманным языком", а для этого он должен был быть максимально прост и интуитивно понятен! Вот я и применял "метод тыка" в сочетании с поиском подсказок...
Практика показала, что Питон не таков. Я не говорю, что он плох, хотя лично мне многое в нем кажется откровенно диким (ведь можно было сделать проще!). Тем более, что я его применял для тех задач, для которых он, возможно, и не предназначен. Ведь каждый язык, даже считающийся универсальным, все равно имеет свою нишу. А Питон не универсален отнюдь...
Последним пунктом изучения была работа с несколькими формами. Тут все довольно просто: во второй форме надо создать нужные функции, причем "mainloop" тоже должен быть внутри функции. Дело в том, что импортировать в основной модуль надо именно эту функцию. Да, есть в питоне возможность импорта просто всего модуля, но тогда придется указывать его имя при запуске в качестве префикса. А зачем? Проще импортировать саму функцию. В программе "geo2utm" второе окно - это помощь. Как раз сделано таким импортом...
В общем, я пока что с Питоном покончил. :) Да, я не освоил "стиль Питона", я нарушал все "приличия" (например, по именам переменных), я (о, ужас!) не оформлял все в виде гордых классов (ибо не вижу в том никакого практического смысла), ну и т.д. Моя база - это программирование на калькуляторах, где каждый байт (это не метафора!) - на вес золота. Да и в досовские времена компактность кода и его скорость работы были вопросом выживания. А все эти танцы с классами, свойствами и т.д. - конечно, отчасти сейчас необходимы, но я все это применяю только в самом крайнем случае. Потому что по опыту именно ООП является самым медленным и ресурсоемким элементом любой программы.
У каждого свои принципы. Главное - чтобы программа работала! И не дохла на слабой технике...