Архив метки: Python

Python — сложение строк или конкатенация

В питоне складывать строки очень просто, вот примеры, из которых все понятно:
Пример №1

>>>print 'Привет! ' + 'Как дела?'
Привет! Как дела?

Пример №2

>>> a = 'Хорошо'
>>> b = ' А у тебя как?'
>>> c = a + b
>>> print c
Хорошо А у тебя как? 

Пример №3 (c преобразованием числа  в строку)

 >>> x = 12
>>> y = 6
>>> print '12 * 6 = '+str(x*y)
12 * 6 = 72

Автор: AlexWinner
Дата публикации: 2011-01-31T06:49:00.000-08:00

Текущие проекты

Давно я что-то сюда не писал. Замотался совсем. В частности, несколько неожиданно для себя стал техническим писателем 🙂

Пока что задокументирую несколько проектов, которые у меня сейчас в более-менее вялотекущей разработке. Пожалуй, в хронологическом порядке.

Framework

Это фреймворк (не очень высокого уровня, на настоящий момент) для создания web-приложений на Haskell. Страница проекта тут, haddock-документация тут. Проект в значительной мере исследовательский: насколько сложно/просто писать веб-приложения на Haskell? А фреймворки? Какие новые идеи способен привнести Haskell в эту область? Кроме того, изначально я задумывал фреймворк для разработки приложений высокой нагруженности (так что само собой предполагаются всякие кэширования, работа со многими СУБД и мн.др.). Во фреймворке в настоящий момент много чего не хватает (начиная с названия) — нет полноценной ORM, нет генерации произвольных диалектов SQL… Вероятно, как раз в этих областях что-нибудь интересное получится в результате. Кое что [на мой взгляд] оригинальное в фреймворке уже есть. Т.к. Haskell — компилируемый язык, то всё приложение — это один бинарник. Включая шаблоны. Шаблоны пишутся в синтаксисе, похожем на Django-вский (вообще, я многие идеи старался взять из django), при сборке приложения по ним генерируется haskell-исходник и компилируется вместе с приложением. Достоинства и недостатки, собственно, очевидны: нет затрат времени на парсинг шаблонов на каждый запрос (но и затрат сложности на кэширование шаблонов тоже нет), генерация html по шаблонам быстрее, но при изменении шаблонов надо пересобирать приложение (но если речь идёт о большой нагрузке, шаблоны будут меняться редко).

MyPaint

Как несложно догадаться из названия, MyPaint (http://mypaint.intilinux.com) — это программа для рисования (дословно — что-то вроде «моя живопись»; исторически, это название — ссылка на программу paint.exe от microsoft). Программ для рисования сейчас довольно много, в том числе и свободных, и под Linux (конечно, в первую очередь на ум приходит Gimp). Особенность MyPaint — это программа в первую очередь именно для рисования, а не для обработки готовых изображений (собственно, MyPaint даже не умеет таких вещей, как «кроп» или «уровни»; за такими функциями добро пожаловать в тот же Gimp). На самом деле, ближайшие конкуренты MyPaint — это Corel Painter и ArtRage (NB: это не означает, что они идут ноздря-в-ноздрю, просто это программы одного назначения).

Этим летом мои родные-художники дорвались до компьютера, а именно до mypaint, и засыпали меня багрепортами и фичреквестами. В связи с чем я начал разрабатывать свою ветку mypaint. Сейчас мои наработки будут постепенно вливаться в основную ветку.

Коротко изменения — i18n и перевод на русский (сейчас уже в основной ветке, вместе с переводами на французский, норвежский, шведский, упрощённый китайский и др.); палитра; что-то наподобие масок; диалог слоёв; группировка кистей; поддержка наклона пера. Подробнее на вики mypaint, там же рядом бурное обсуждение интерфейса.

Надеюсь в ближайшее время сделать отдельную статью про MyPaint. А пока, «с первого и по тринадцатое», собираюсь поплотнее заняться разработкой с целью сделать мои нововведения пригодными для вливания в основную ветку — релиз планируется сразу после этого мержа.

Todos

Ещё один проект без нормального названия 🙂 Это простецкий TODO-менеджер на Haskell. Собственно, сами TODO пишутся в любом текстовом редакторе в plain-text файлике (желательно, с названием TODO) в простецком формате:

[spaces]status [TAGS] title (depends) description

где [spaces] — отступ пробелами, status — состояние задачи, [TAGS] — список тегов в квадратных скобках через пробел, title — заголовок или описание, (depends) — список зависимостей (заголовков других записей) в скобках через запятую, description — описание. Все поля кроме статуса и заголовка необязательны. Отступами определяется подчинённость записей, благодаря зависимостям (которые в скобках) структура может быть не только деревом, но произвольным графом (даже циклическим). Собираюсь приделать поддержку дат (чтобы, например, можно б

Все форматы документа из одного исходника: asciidoc сотоварищи

Я уже давно использую asciidoc для написания сколько-нибудь больших текстов. Почти все статьи в этом блоге, включая эту, подготовлены с помощью Asciidoc.

Asciidoc — это транслятор простейшего языка разметки текста в любой другой язык разметки. Разметка asciidoc очень простая, практически вы пишете plain text, только выделяете заголовки знаками = в начале строки, полужирный текст — *звёздочками*, курсив — 'кавычками', итд. Абзацы разделяются пустой строкой. А на выходе может быть всё что угодно, это зависит от так называемого backend-a, поведение которого описывается в конфиге. В поставке доступны бэкенды для xhtml, html4 и docbook. Docbook, в свою очередь, теоретически можно отконвертировать во что угодно.

На днях я готовил доклад для одного семинара, и мне хотелось получить его сразу в нескольких форматах: html и pdf, как минимум. И ещё бы надо к нему презентацию… И хорошо бы план доклада. И, конечно, не хочется для каждого формата готовить текст.

HTML (точнее, xhtml 1.1) делается с помощью asciidoc. Все остальные форматы, теоретически, можно получить из docbook, который можно получить с помощью asciidoc. Только вот на практике мне так и не удалось за полдня заставить ни один из конверторов docbook нормально работать с русскими буквами. Также в комплекте asciidoc есть экспериментальный бэкенд latex, но он как-то странно работает с кусками кода, которые мне нужно поместить в tex-файл в неизменном виде (речь идёт о формулах): половина формул куда-то проглатываются.

Кроме всего прочего, мне нужно в доклад включать фрагменты диалога с консольными программами (в данном случае — с maxima и с R). Так как в ходе подготовки доклада что-то может меняться, неохота каждый раз делать copy-paste из консоли. Надо бы, чтобы в исходник вставлять только запросы к программам — а вызываются программы и вставляется вывод пусть автоматически.

В общем, в итоге я написал скрипт lmaxima.py, который делает следующее: читает входной файл, и копирует его в выходной. Если встречает строку вида «program>> команды», то по пайпу передаёт эти команды указанной программе, и её ответ вставляет в выходной файл. Если встречает строку вида «program|tex>> команды» — то указанные команды оборачивает в функцию tex(). Таким образом, lmaxima.py работает как препроцессор для asciidoc. Одна из тонкостей состоит в том, как вставлять в документ формулы, которые выдаёт maxima. Если выводить надо в html, то формулы пропускаются через tex, и в выходной файл вставляется картинка (строка image:chtoto.png[]). Если же выводить надо в pdf, то lmaxima указывается ключ -i, и в выходной файл вставляется непосредственно tex-код.

Т.к. latex-бэкенд к asciidoc работает странно, пришлось писать свой конвертер из подмножества asciidoc-разметки в tex (благо, основная часть разметки asciidoc очень простая). Называется он у меня vsml.py. Заодно vsml.py умеет следующее:

  • С ключом -c — добавляет в документ оглавление (latex-овская команда tableofcontents),

  • с ключом -p — «выдирает» из исходника только заголовки, и составляет содержание документа (план доклада, в моём случае),

  • с ключом -b — создаёт исходник для презентации (класс beamer); в презентацию попадают заголовки и картинки.

vsml понимает ещё и некоторые «надстройки» над синтаксисом asciidoc. Так, с помощью строчек «//{» и «//}» (asciidoc их воспринимает как комментарии) можно создавать вложенные куски текста. По умолчанию они выводятся как обычно, однако vsml.py можно задать ключ -l с числовым параметром, и он будет выводить только текст с «уровнем вложенности» не больше заданного; это позволяет оформлять более и менее необязательные части текста, и из одного исходника создавать документы разной степени подробности. А с помощью строчки вида «//.Тут заголовок» можно создавать (под)заголовки, которые не будут видны нигде, кроме презентации.

Конечно, вручную писать все эти команды с ключами каждый раз долго, поэтому я написал небольшой Makefile:

all: report.pdf report.html presentation.pdf plan.pdf

clean:
rm report.pdf report.html presentation.pdf
rm presentation.tex report.asciidoc report.vsml
rm plan.tex plan.pdf

plan.pdf: plan.tex
pdflatex $<

plan.tex: report.vsml
vsml.py -p < $< > $@

report.pdf: report.tex
pdflatex $<

presentation.pdf: presentation.tex
pdflatex $<

report.html: r
eport.asciidoc
asciidoc $<

report.asciidoc: math-report
lmaxima.py $< $@

presentation.tex: report.vsml
vsml.py -b < $< > $@

report.tex: report.vsml
vsml.py < $< > $@

report.vsml: math-report
lmaxima.py -i $< $@

PS: мне тут подсказывают: добавь ещё festival, оно за тебя и доклад прочитает 🙂

Автор: Portnov

Создание собственных виджетов в PyGTK с помощью cairo

Свободная библиотека Gtk, как известно, не отличается очень большим выбором виджетов. Но никто не мешает создавать свои собственные.

Gtk, как известно, построена на принципах ООП, что хорошо ложится на объектную модель Python. В данном случае это означает, что наследование виджетов естественным образом соответствует наследованию классов в Питоне. Так, создав класс-потомок gtk.VBox, мы получим виджет со всеми свойствами VBox, и сможем добавлять в него нужную функциональность.

Покажу простейший пример. Пусть мы хотим создать виджет, выглядящий как комбинация gtk.Label и gtk.Entry, т.е. поле для ввода сразу с подписью. Чтобы сделать такое непосредственно средствами gtk, нужно создать gtk.HBox, а в него поместить Label и Entry. Т.е. HBox окажется родительским виджетом для всей конструкции. Вот от него и будем наследоваться:

class LabeledEntry(gtk.HBox):

Но наш виджет довольно сильно отличается от простого HBox, поэтому нужно переопределить инициализатор:

  def __init__(self,label=None):
gtk.HBox.__init__(self) # Вызываем инициализатор родительского класса
self.label = gtk.Label(label) # Создаём текстовую метку с нужной подписью
self.entry = gtk.Entry() # И поле для ввода текста
self.pack_start(self.label, expand=False) # Добавляем label в создаваемый виджет
self.pack_start(self.entry, expand=True) # Поле для ввода - туда же

Теперь можно дописывать методы по собственному усмотрению. Например, логично было бы видеть методы set_text и get_text:

  def get_text(self):
return self.entry.get_text()

  def set_text(self,text):
self.entry.set_text(text)

При желании можно добавить, например, get_label и set_label. Пример использования нашего виджета:

...
entry = LabeledEntry("Enter some text")
...

Таким образом, наследуясь от HBox или VBox, можно создавать виджеты, состоящие из нескольких готовых. Но иногда нужны виджеты, внешне не похожие ни на один из стандартных. И вот тогда выручает то, что все виджеты gtk отрисовываются с помощью Cairo, который имеет весьма простой API.

API этот имеет много общего со многими другими рисовальными API. Прежде всего, нужно получить контекст Cairo — объект, содержащий состояние изображения. Далее для собственно рисования вызываются методы этого объекта. Наиболее часто используемые:

  • cr.move_to(x,y) — переместить графический указатель в нужную точку холста,

  • cr.line_to(x,y) — провести линию от положения указателя до данной точки (указатель сдвинется в указанную точку),

  • cr.path_close() — делает текущую линию замкнутой,

  • cr.rectangle(x,y,w,h) — рисует прямоугольник; задаются координаты левого верхнего угла и размеры,

  • cr.set_source_rgb(r,g,b) — выбрать цвет для рисования; компоненты r,g,b измеряются от 0 до 1,

  • cr.stroke() — нарисовать контур текущей линии (выбранным цветом),

  • cr.fill() — закрасить текущую линию.

Координаты измеряются как обычно — от левого верхнего угла вправо и вниз, в пикселах.

Пусть нам, скажем, нужен виджет, который будет отображать простейшие линейные диаграммы. Должна быть возможность добавлять в него данные, а он должен соответственно перерисовывать диаграмму. Такие виджеты удобнее всего наследовать от gtk.DrawingArea:

  class Diagram(gtk.DrawingArea):

Сам виджет DrawingArea выглядит как белый прямоугольник. И на нём, в соответствии с названием, можно рисовать. Пока сделаем инициализацию нашего виджета:

  def __init__(self,max=10,color=(0.8,0.8,0.6)):
gtk.DrawingArea.__init__(self)
self.data = [1] # Это будут данные, отображаемые виджетом
self.max = max # Сколько максимум данных будет рисовать виджет
self.color = color # Цвет диаграммы
# Вот это, можно сказать, самое главное: привязываем рисующую процедуру к событию перерисовки виджета
self.connect('expose-event', self.on_expose)

Определяем собственно метод, который будет отрисовывать виджет:

  def on_expose(self, widget, event):

В аргументе widget передаётся сам виджет. Первое, что нам от него нужно — это размеры и положение:

    x,y, width,height,_ = widget.window.get_geometry()

Кроме того, нам понадобится контекст Cairo:

    cr = widget.window.cairo_create()

Вычислим некоторые размеры:

    xpad = 0.03*self.width           # Поля по горизонтали
ypad = 0.07*self.height # И по вертикали
w = float(self.width-2*xpad) # Ширина 'рабочей' части виджета
h = float(self.height-2*ypad) # и высота
M = max(self.data) # Максимум данных - он нужен, чтобы выставить масштаб по оси Y
n = len(self.data) # Количество данных

    cr.rectangle(0,0,self.width,self.height)   # Обозначаем прямоугольник, закрывающий весь виджет
cr.set_source_rgb(1,1,1) # Выбираем белый цвет
cr.fill() # Закрашиваем наш прямоугольник - это будет фон

    cr.move_to(xpad, ypad+h-h*float(self.data[0])/M)  # Ставим указатель в верхний левый угол будущей диаграммы
for x,y in enumerate(self.data[1:]): # Пробегаемся по всем данным
cr.line_to(xpad+w*float(x+1)/(n-1), ypad+h-h*float(y)/M) # Проводим очередной отрезок ломанной
cr.line_to(xpad+w, ypad+h) # Проводим правую границу диаграммы
cr.line_to(xpad,ypad+h) # Теперь нижнюю границу
cr.close_path() # Замыкаем ломанную - это проведёт левую границу диаграммы
cr.set_source_rgb(*self.color) # Выбираем цвет
cr.fill() # Закрашиваем ломанную

Этот метод будет вызываться каждый раз, когда нужно перерисовать виджет. Конечно, стоит иметь ввиду, что если он будет выполняться долго — перерисовка виджета будет тормозить. Так что вычислений и циклов в нём должно быть минимум. Всё, что можно, следует вычислять заранее, или кэшировать.

Ну и допишем метод для добавления данных в диаграмму:

def accept(self,n):
if len(self.data) == self.max:
del self.data[0] # Если данных слишком много - забываем самое старое значение
self.data.append(float(n)) # Добавляем число в список
self.queue_draw() # Этот вызов заставит виджет перерисоваться, т.е. лишний раз вызовет on_expose().

Пример использования:

...
dg = Diagram(max=20)
...
dg.accept(10)
dg.accept(20)
...

Автор: Portnov