Программист — это звучит гордо
Захотелось тут на днях написать небольшую утилиту на python, дабы пользу себе нанести и язык заодно вспомнить. И оказалось, что требует она для своей работы конфиг. В мозгу сразу возникли слова: json, ini, xml, yaml и т.п. Но вот незадача — кто-то из них в стандартной библиотеке python отсутствует, где-то комментарии не поддерживаются, что-то имеет ужасный интерфейс работы из под python, опять же произвольную вложенность не везде можно использовать. И в добавок абсолютно все не поддерживают типизацию. Я уж было совсем приуныл, но в этот момент постучалась в мою голову одна светлая мысль: а python ведь скриптовый язык.
Действительно, что может быть проще — пишем конфиг на python, с его прекрасным синтаксисом, который решает все вышеперечисленные проблемы, а загрузить и распарсить его потом — проще, чем ini файл.
Вот допустим есть у нас вот такой конфиг:
Наиболее подходящие для Python способ обеспечить глобальные переменные конфигурации в config.py?
в моих бесконечных поисках в чрезмерно усложняющих простых вещах я исследую самый «Питонный» способ предоставления глобальных переменных конфигурации внутри типичного»config.py ‘ найдено в пакетах с яйцами питона.
традиционный способ (ААА, добрый старина #define!) заключается в следующем:
поэтому глобальные переменные импортируются одним из следующих способов:
имеет смысл, но иногда может быть немного грязно, особенно когда вы пытаетесь вспомнить имена определенных переменных. Кроме того, обеспечивая ‘конфигурация’ С переменные в качестве атрибутов, может быть более гибким. Итак, взяв на себя инициативу bpython config.py файл, который я придумал:
и a ‘config.py’ это импортирует класс и читает следующим образом:
и используется таким образом:
, который кажется более четкий, выразительный и гибкий способ хранения и извлечения глобальных переменных внутри пакета.
самая дурацкая идея когда-либо? Что является лучшей практики для того, чтобы справляться с этими ситуациями? Что такое код способ хранения и извлечения глобальных имен и переменных внутри вашего пакета?
7 ответов:
Я сделал это один раз. В конечном итоге я нашел свой упрощенный basicconfig.py достаточно для моих нужд. Вы можете передать пространство имен с другими объектами для его ссылки, если вам нужно. Вы также можете передать дополнительные значения по умолчанию из вашего кода. Он также сопоставляет атрибут и синтаксис стиля сопоставления с одним и тем же объектом конфигурации.
как насчет просто с помощью встроенных типов вроде этого:
вы хотели получить доступ к значениям следующим образом:
Если вы готовы пожертвовать потенциалом для вычисления выражений внутри вашего дерева конфигурации, вы можете использовать в YAML и в конечном итоге с более читаемым файлом конфигурации, как это:
и использовать библиотеку, как PyYAML для обычного разбора и доступа к конфигурационному файлу
как ответить blubb по. Я предлагаю построить их с помощью лямбда-функций, чтобы уменьшить код. Вот так:
Это пахнет, как вы можете сделать класс, хотя.
или, как отметил Маркм, вы могли бы использовать namedtuple
- использует переменные класса (нет объекта для передачи / не требуется синглтон),
- использует инкапсулированные встроенные типы и выглядит как (is) вызов метода на App ,
- имеет контроль над индивидуальной конфигурацией неизменяемости, изменчивые глобалы-это худший вид глобалов.
- способствует обычным и хорошо им доступа / чтения в исходном коде
- это простой класс, но обеспечивает структурированный доступ, альтернативой является использование @property , но это требует больше кода обработки переменных для каждого элемента и является объектно-ориентированным.
- требует минимальных изменений чтобы добавить новые элементы конфигурации и установить его изменчивость.
Как насчет использования классов?
небольшая вариация на идею Хаски, которую я использую. Создайте файл под названием «глобалы» (или что вам нравится), а затем определите в нем несколько классов:
затем, если у вас есть два файла кода c1.py и c2.py, оба могут иметь в верхней части
Теперь весь код может получить доступ и установить значения, как таковые:
люди забывают, что классы существуют, даже если ни один объект никогда не создается, который является членом этого класса. И переменные в классе не предшествуют «я». являются общими для всех экземпляров класса, даже если их нет. Как только «отладка» изменяется любым кодом, весь другой код видит изменение.
импортируя его как gl, вы можете иметь несколько таких файлов и переменных, которые позволяют вам получать доступ и устанавливать значения в файлах кода, функциях и т. д., но без опасности столкновения пространства.
Это не хватает некоторых умных ошибок проверки других подходов, но это просто и легко следовать.
пожалуйста, проверьте систему конфигурации IPython, реализованную с помощью traitlets для принудительного применения типа, которое вы делаете вручную.
вырезать и вставлять здесь, чтобы соответствовать таким рекомендациям, а не просто удалять ссылки, поскольку содержание ссылок меняется с течением времени.
traitlets documentation
вот основные требования, которые мы хотели, чтобы наша система конфигурации имела:
поддержка иерархической конфигурации информация.
полная интеграция с парсерами параметров командной строки. Часто требуется прочитать файл конфигурации, но затем переопределить некоторые значения с помощью параметров командной строки. Наша система конфигурации автоматизирует этот процесс и позволяет каждому параметру командной строки быть связанным с определенным атрибутом в иерархии конфигурации, который он переопределит.
файлы конфигурации, которые сами являются допустимым кодом Python. Это многое решает. Во-первых, это становится возможным поместить логику в ваши файлы конфигурации, которая устанавливает атрибуты на основе вашей операционной системы, настройки сети, версии Python и т. д. Во-вторых, Python имеет супер простой синтаксис для доступа к иерархическим структурам данных, а именно регулярный доступ к атрибутам (Foo.Bar.Bam.name в-третьих, использование Python позволяет пользователям легко импортировать атрибуты конфигурации из одного файла конфигурации в другой. В-четвертых, хотя Python динамически типизирован, у него есть типы, которые можно проверить по адресу во время выполнения. Таким образом, 1 в файле конфигурации является целым числом ‘1’, а ‘1’ — строкой.
полностью автоматизированный метод для получения информации о конфигурации для классов, которые нуждаются в нем во время выполнения. Написание кода, который проходит иерархию конфигурации для извлечения определенного атрибута, является болезненным. Когда у вас есть сложная информация о конфигурации с сотнями атрибутов, это заставляет вас плакать.
тип проверки и проверки, которая не требует всего иерархия конфигурации должна быть задана статически перед началом выполнения. Python — очень динамичный язык, и вы не всегда знаете все, что нужно настроить при запуске программы.
чтобы достичь этого, они в основном определяют 3 класса объектов и их отношения друг к другу:
1) конфигурация-в основном ChainMap / basic dict с некоторыми улучшениями для слияния.
2) конфигурируемый-базовый класс для подкласса всех вещей, которые вы хотели бы конфигурировать.
3) Application-объект, экземпляр которого создается для выполнения определенной функции приложения или вашего основного приложения для программного обеспечения с одной целью.
Приложения:
приложение-это процесс, который выполняет определенную работу. Наиболее очевидным приложением является программа командной строки ipython. Каждое приложение считывает один или несколько файлов конфигурации и один набор параметров командной строки. затем создает главный объект конфигурации для приложения. Затем этот объект конфигурации передается в настраиваемые объекты, создаваемые приложением. Эти настраиваемые объекты реализуют фактическую логику приложения и знают, как настроить себя с учетом объекта конфигурации.
приложения всегда имеют атрибут журнала, который настроен логгер. Это позволяет централизованно регистрировать конфигурацию для каждого приложения. Настраивается: Настраиваемые!—1—>
конфигурируемый-это обычный класс Python, который служит базовым классом для всех основных классов в приложении. Настраиваемый базовый класс является легким и делает только одну вещь.
Это настраиваемый подкласс HasTraits, который знает, как настроить себя. Признаки уровня класса с метаданными config=True становятся значениями, которые можно настроить из командной строки и файлов конфигурации.
разработчики создают настраиваемые подклассы, которые реализовать всю логику в приложении. Каждый из этих подклассов имеет свою собственную информацию о конфигурации, которая управляет тем, как создаются экземпляры.
Меню консольных команд на python
Приветствую Вас, коллеги. Меня зовут Рустам, я работаю в небольшой компании, которая занимается web-разработкой и продвижением сайтов.
Очень часто во время работы над каким-либо проектом возникают задачи решение которых требует ввода в консоль нескольких команд, такие как, например, пересборка фронтенда, запуск/остановка нескольких docker-контейнеров, развертывание окружения на новом девелоперском компе и тому подобные вещи.
Это вообщем то не сложно, но зачастую подобные задачи возникают весьма регулярно, требуют повторения, превращаясь в рутину.
И вот, собственно, однажды возникла идея как сократить время на это вот все, максимально упростив процесс, реализовав небольшую утилиту, позволяющую обернуть наборы часто производимых действий в пункты удобного меню выводимого в консоль.
Реализовать решил на Python т.к. из коробки он установлен на большинстве дистрибутивах линукс, и для использования не потребуется установки дополнительных пакетов.
Получилось нечто весьма удобное доступное для клонирования c гитхаб.
Все настройки (а именно что по какому пункту должно выполняться) хранятся в файле menu.yml.
Файл настроек приведенный в качестве примера в репозитории снабжен всеми необходимыми коментариями, но для того, чтобы все стало еще понятней есть рабочий пример на гитхабе (https://github.com/hrustbb2/env-example).
В качестве примера приведено приложение состоящее из трех docker-контейнеров (php, mysql, nginx) с отдельными конфигами для девелоп и продакшен окружений и двумя отдельными сценариями деплоя в этих окружениях.
Итак, клонируем, запускаем ./env и видим меню из трех пунктов:
Развернем наше приложение в девелоп-режиме, для этого выбираем пункт 1, проваливаемся в подменю:
Здесь вначале создадим наши контейнеры выбрав 1, после чего необходимо придумать и ввести имя приложения. Здесь хочу обратить Ваше внимание на то, что параметры необходимые для выполнения тех или иных команд требуются ввести лишь один раз, далее они сохраняются в env.ini файл и при повторном запуске вводить их не требуется. Затем, немного подождав пока завершится создание контейнеров, запустим скрипт для деплоя самого приложения, выбрав 2.
В данном примере скрипт клонирует в ./app стартовое приложение Laravel, установит необходимые composer-пакеты, накатит миграции и создаст файл конфигурации .env. Делается это только один раз в самом начале, в последствии окружение запускается выбором пункта 3. Пункт 5 служит для удаления созданных контейнеров после того как они стали больше не нужны, например когда работа над проектом окончена.
Вот пожалуй все, теперь открываем в браузере localhost и продолжаем работу.
Иногда на продакшене возникает необходимость запускать некоторые команды автоматически по крону, например обновление SSL сертификатов, backup и т.п. В этом случае запускаем, например ./env -e 1-2-3, где 1-2-3 путь до нужной команды в меню.
Мне и моим коллегам принес немало пользы, немного облегчив им труд, надеюсь инструмент будет полезен и вам.
How to Build a GUI in Python 3.5
Looking around the community, at other people products and such I get the feeling that Python is being used more for services and scientific applications rather than desktop applications. That being said, python desktop applications are by no means dead and lots of people want to create them (me included).
In order to create a desktop application we need to use a GUI library to help us build it. Now, if you are a Python 2.7, or even 3.3 and below user then your choices are plentiful. With Python 3.5 and above however, at the time of writing this post, we are quite limited.
THE CURRENT STATE OF PYTHON 3.5 GUI LIBRARIES
After doing some research into what is available to me I was quite disappointed if I’m quite honest. A lot of popular libraries just haven’t been ported forward to 3.5 yet, especially the 64 bit version.
I was looking for a native-looking, cross-platform option and neither wxPython-Phoenix (Python’s wx binding) nor PySide (a Python QT binding) seemed to work with Python 3.5 64 bit version and these seemed to be the popular choices with the most relaxed licenses. They seemed to work with Python 3.3 and I believe wxPython works with 32 bit Python 3.5 from what people have been saying online, but has problems compiling with Python 3.5 64 bit version.
UPDATE: According to
, you can actually get wxPython-Phoenix working using the following method:
So what do we do? Well, we go for Tkinter. Tkinter is a GUI library built on top of tcl/Tk, it also happens to be included in Python’s standard library and so very convenient.
Where possible, we will be using tkinter.ttk widgets. The different between vanilla tkinter and tkinter.ttk widgets is that tkinter.ttk widgets use style to define their appearance. They are less customisable than the plain tkinter widgets, but give a more ‘native’ look.
THE BASIC STRUCTURE OF A TK GUI
During this post we will be creating a very simple program that adds two numbers to outline the basics of GUI programmings with tkinter and ttk in Python 3.5.
This is an object orientated approach to GUI building and seems as Tkinter is an object orientated GUI framework, it works well. It’s simple enough, first of all we import tkinter and ttk so we can access the GUI tools we need.
We then create our own class which extends the ttk.Frame class. This is where the GUI building will go on. Pretty much everything to do with our GUI will be handled in here.
The init_gui() method is where the definition of our GUI will be, for now we will just set the title of the window. We do this by accessing the root of our application and setting its title.
Then, down in the if __name__ == ‘__main__’ section we create our top level widget; the main window of the application and then create an instance of our class and start it’s mainloop.
Our GUI now looks like this:
One thing you should note here, is that we don’t do this:
Most tutorials and documentation online, including the official
tell you to do this. Don’t, from x import * is the devil. Keep your code concise, easy to follow and avoid naming clashes.
BASIC WIDGETS
You will notice that widget creation is simply instantiating a new object. The first argument you need to enter when creating a new widget is its parent. Its parent is the widget that will contain the new one you are making, in this case we are putting all our widgets inside the main all encompassing frame; our custom class that we made, and we reference it via ‘self’.
You may be wondering what the parent of the topmost widget it. Well, if you take a look at the code we wrote in the previous section you will see.
That is our top level widget and so clearly doesn’t have a parent.
If you run this code you will notice that nothing appears. The GUI is hasn’t changed at all. That’s because although we have created new widgets, we haven’t placed them anywhere in our GUI, they are just floating about somewhere. In the next two sections we will see two ways of making them appear.
With Tkinter there are lots of widgets at our disposal and we only use a few here, for a full list of tkinter widgets
, and for a full list of tkinter.ttk widgets
The first way we can make our widgets appear is by using pack(). This is the quickest and easiest way, but gives you less freedom when defining the way your GUI is layed out.
Using pack() without any arguments will arrange your widgets in a column, you can change this behaviour with the optional argument ‘side’ where you can define ‘top’, ‘bottom’, ‘left’ or ‘right’. The default is ‘top’, which will align widgets vertically. To align things horizontally, use ‘left’.
You can also make a widget fill it’s parent element along the x or y axis using the optional argument ‘fill’. You can make it fill the x or y axis by specifying ‘x’ or ‘y’ and can make it fill both by specifying ‘both’.
The padding for a widget can be set via the ‘padx’, ‘pady’, ‘ipadx’ and ‘ipady’ where padx and pady are the external padding and ipadx and ipady is internal padding.
Our GUI should now look like this:
Using pack() however, is only practical for very simple GUIs, for more complicated ones, it’s best to use the grid layout.
UNDERSTANDING THE GRID LAYOUT
The grid layout is a powerful tool for defining the layout of your GUI, much more so than pack and is the method that I have come to favour. Obviously, the grid layout is, well, a grid. A collection of rows and columns that you can insert widgets into to structure your GUI.
When using the grid layout you should first have a good idea of what you want your GUI to look like. Then using a combination of placing widgets in specified rows and columns, making them span across multiple rows and columns and setting sides for them to stick to we can create complex GUIs.
Using the grid manager is incredibly easy, simply use the grid() method to place your widget in the desired row and column on the grid. Note that the grid starts at 0 and not entering a row or column will result in them defaulting to this value.
When you place your widget on the grid, by default it will be centred within the cell. To change this you can enter a ‘sticky’ argument in the grid() method. You can pass it in a string containing any of ‘n’, ‘e’, ‘s’, ‘w’ and can combine them together too.
Another useful feature of the grid layout it the ability to make widgets span across multiple rows and columns using the optional arguments ‘rowspan’ and ‘columnspan’. Remember that if your last column is ‘4’ then you actually have five columns, so if you want something to span across the whole grid, that is something to remember.
Our GUI now looks like this:
An important point to note here is that grid.() returns None, so when you need to access the widget at a later date, first create the widget and assign it to a variable, then call the grid method on that variable.
CREATING A MENU BAR
I feel creating a menu bar in Tkinter is not as simple as it could be, that being said, it’s not difficult either.
First what we do is turn off tearing off. What this does is prevent you from being able to detach the menu bar from the main window. When it is turned on you can drag the menu bar off the main application window into a window of its own. We don’t want this behaviour, so we will turn it off.
We then create the main menu bar itself and set it’s parent to the root element. On the menu bar we will have ‘File’ and ‘Edit’ menus, so we create those exactly as before, except we set their parents to the main menu bar.
Now, under the ‘File’ menu we will create an item that exits the application when you click it as an example of how to add things to menus. We can do this via the
method. We will see later how to make this do something.
Now we have three separate menu bars, but we want to add the file menu and the edit menu to the main menu. We do this using the
method, which will add the two menus to the menu bar as cascading menus, ie. drop downs. You can also add cascades to the file and edit menus.
The final thing we need to do is set the root’s menu to our newly created menu bar and we are done.
Our GUI should now have a menu bar:
BINDING FUNCTIONS
In our example program we have ‘Exit’ in the file menu and the calculate button, but neither of them do anything. We need to give them functionality, which in Tkinter is laughably simple.
First what we need to do is create methods inside our Adder class (our Frame class) to take care of the functionality that we need.
Then all we do is add the ‘command’ argument to our exit button in the file menu and our calculate button and point them to the methods we created. Simple.
A FULL EXAMPLE
The above code should produce this GUI that calculates the sum of the two input numbers and exits when you press the exit button in the file menu:
With this we can now create complex GUIs in python 3.5 using tkinter. Hopefully in the near future other GUI tool kits will be ported forward, giving us more choice.
That’s it for this post, I hope now you feel a little more confident producing GUIs for your applications written in Python 3.5. Make sure you give this post a share so others can read it too. Also don’t forget to subscribe to my