Попробовал библиотеку @asolovyov для разбора аргументов командной строки в
Python, которая называется opster (вот доки, исходники). Это ещё
одна библиотека, решающая те же задачи, что и стандартные getopt, optparse и
argparse.
Впечатления приятные. Кода действительно надо писать меньше. Самая главная идея — отделить код обработки опций от кода функции, которой они нужны как аргументы. То есть если у меня есть функция:
def test(arg1, arg2, include=[], exclude=[], verbose=False):
'''A test command.'''
...
то для превращения её в утилиту командной строки мне не надо её менять, только
снабдить декоратором @command или обернуть её в этот декоратор непосредственно
в main:
@command(usage='%name [hIXv] arg1 arg2',
options=[
('I', 'include', [], 'include names'),
('X', 'exclude', [], 'exclude names'),
('v', 'verbose', False, 'be more verbose')])
def test(arg1, arg2, include=[], exclude=[], verbose=False):
'''A test command.'''
...
Получилось 5 строк. Этот же пример на getopt занимает где-то 30 строк.
Затем можно вызвать функцию, передав аргументы командной строки:
if __name__ == '__main__':
test(argv=sys.argv[1:])
либо вызывать как обычную функцию:
test('foo', 'bar', include=['path1', 'path2'], verbose=True)
При этом у программы появится автоматическая справка по -h:
$ ./test -h
test [hIXv] arg1 arg2
A test command.
options:
-I --include include names
-X --exclude exclude names
-v --verbose be more verbose
-h --help show help
Ещё несколько слов об особенностях. Есть поддержка подкоманд (в духе Mercurial,
Git). Нет обязательных опций, но это даже хорошо. Какой смысл в обязательных
опциях? Есть поддержка задания одной опции несколько раз (значений типа
[str]), а также значений bool, str, int и интересных значений str ->
a, то есть функций по преобразованию значения во что угодно.
Из минусов можно назвать не всегда корректную работу с Unicode, stack trace при указании неверных значений опций вместо красивых сообщений об ошибках, невозможность задать только короткое имя опции и ещё несколько мелочей.
Библиотека opster определённо заслуживает внимания.
См. также:
f x = x. I don’t do very much but at least I’m unique."James Chapman (via annayudi)
Есть известные правила программирования в Unix. Мы решили обратить внимание на схожие правила, помогающие создавать краткий программный код:
2010-05-17 в Москве прошла конференция DevConf. Я на ней выступал с докладом Внешние языки DSL на funcparserlib (см. интервью со мной).
Я хочу поделиться впечатлениями о потоке Python этой конференции. Я также собрал немного ссылок по конференции, привожу их в конце поста.
Мы ехали в Москву из Петербурга в компании с @andreypopp, @hdima и @dimasmz. Приехали вечером в воскресенье, остановились у @barbuza. Он с @semenov и @andreypopp продолжили готовить свои доклады, обсуждая при этом Django. Мне, как и @otkds, поэтому казалось, что выступление @barbuza на конфе должно было быть более резким :)
Мне, слава богу, проблемы Django были достаточно далеки. Мой доклад о funcparserlib был готов за неделю до конфы и я мог просто повеселиться и отдохнуть :)
Организация конференции была на весьма среднем уровне. Не буду подробно на этом останавливаться.
Теперь о самих докладах. Многие темы докладов были интересными. Но сами доклады отличались, к сожалению, значительной монотонностью. Так что когда я ниже говорю, что доклад был интересный, я оставляю монотонность за скобками ;)
@andreypopp выступал с двумя докладами. Первый доклад о gevent был для меня более интересным. Есть разные решения для IO-bound parallelism на Python. gevent — одно из них. Я бы хотел узнать более подробно о том, насколько gevent применима для actor-based concurrency. Разработчик одной из альтернатив, eventlet, показал, как можно создавать акторов на основе его библиотеки. Про gevent пока не ясно. Хотелось бы ещё узнать подробнее о различиях между Stackless Python, gevent и eventlet.
Доклад Андрея Светлова про import hooks также затронул интересную тему. Я как раз какое-то время назад жаловался, что Python грузится слишком долго, импортируя слишком много модулей при начальной загрузке. Так что узнать подробнее о том, как работают механизмы импорта, было хорошей идеей. К сожалению, Андрей включил в доклад слишком много деталей, из-за которых потерялись ключевые моменты. Думаю, что доклад выполнил свою задачу в том смысле, что теперь мне интересно почитать об импорте подробнее.
Дальше были два более коротких доклада, один мой про funcparserlib и создание DSL на Python и ещё один доклад @intelliyole об IDE PyCharm для Python от JetBrains. Про свой доклад я рассказывать не буду :) Про IDE лучше смотреть, чем рассказывать. Для поклонников Eclipse, NetBeans и IntelliJ IDEA эта новая IDE PyCharm наверняка будет хорошим выбором. Я использую vim, так что для меня это не очень актуально.
Александр Шигин рассказывал в своём докладе о Cython, расширении языка Python для более удобного создания расширений на C для Python. Опять же интересная вещь, но у меня до неё ещё не доходили руки. Я обычно взаимодействую с C из Python при помощи Unix IPC: запуска процессов, обмена через неименованные каналы, сокеты. Более тесная интеграция независимых программ — обычно плохая идея. Когда это всё же нужно, то я использовал модуль стандартной библиотеки ctypes для вызова функций на C из разделяемых библиотек. Cython — это ещё один возможный вариант. Более того, если нужно ускорить код на Python, а не взаимодействовать с кодом на C, то он, видимо, должен хорошо решать эту задачу. Возможно, на нём можно намного быстрее делать различные рекурсивные обходы. На Python это часто слишком медленно.
@isagalaev проводил мастер-класс, а не читал доклад. Его мастер-класс был посвящён созданию библиотеки потоковой генерации XML. Было любопытно понаблюдать за процессом создания библиотеки (опять же не принимая в расчёт монотонность изложения). О чём хотелось бы услышать подробнее — об альтернативах разных решений и о том, почему было выбрано то или иное решение.
На мой взгляд, для подобных задач (генерация больших списков записей в XML) лучше подошёл бы другой подход, очень частный, но простой. Нужен генератор XML-деревьев отдельных небольших записей списка и функция сериализации этого списка внутри тэгов-контейнеров. Так проще работать с XML, не надо везде подстраивать свой код под потоковость. Только на уровне одного очень большого списка тэгов. Вот на уровне псевдокода:
def get_entries(...) -> Iterable(etree.Element):
'Вернуть итератор по XML-документам всех записей в БД.'
return (to_xml_etree(e) for e in get_db_entries(...))
def dump_entries(entries: Iterable(etree.Element)) -> Iterable(str):
'Вернуть сериализованный поток записей.'
return itertools.chain(['<feed>'],
(etree.tostring(e) for e in entries),
['</feed>'])
Второй доклад @andreypopp был посвящён веб-фреймворку repoze.bfg. У меня создалось впечатление, что это очередная Java. Проблемы, которые он решает, выглядят надуманными, а решения — слишком unpythonic, в стиле Java. Может быть, для каких-нибудь крупных enterprise приложений это и имеет смысл, но я вообще-то сомневаюсь :) Simple is better than complex. Complex is better than complicated. Фреймворк repoze.bfg показался как раз complicated. Если нельзя даже объяснить кратко, зачем нужны какие-то решения, значит вряд ли они по-настоящему нужны.
Совместный доклад @barbuza и @semenov был о минусах Django, из-за которых временами бывает очень неудобно с ней работать. Со многими из перечисленных минусов я сталкивался сам, некоторые ещё не встречал. Доклад был очень полезный. В некоторых областях, например в ORM, стоит явно посмотреть на альтернативы Django. Одна из плохих вещей про Django, о которой упомянули докладчики, это снижение среднего уровня программистов на Python. Сейчас многие начинают использовать Django, даже не зная толком сам язык. Это грозит сообществу PHP-культурой кодирования. С этой точки зрения Django — это зло.
@asolovyov рассказал как раз об одной из альтернатив Django, которую он создаёт вместе с несколькими open-source разработчиками. Их фреймворк называется Svarga. Команда у них очень маленькая и они уделяют проекту довольно мало времени. Зато и кода там на порядок меньше, чем в Django. Надеюсь, меньше за счёт лишнего и ненужного кода в Django :)
Это вообще настоящая беда — раздувать код проектов. Это объясняется, как мне кажется, неумением всех нас программировать. Насколько я знаю, ни в каком другом виде деятельности не создаётся таких огромных текстов, как в программировании. С этим точно надо что-то делать. Один из подходов к этой проблеме — работы Viewpoints Research Institute. У них есть несколько интересных публикаций и видео докладов, стоит посмотреть.
Вот такие доклады были в потоке Python. В перерывах между докладами удалось немного пообщаться с друзьями-питонистами, познакомиться с новыми людьми и увидеться с теми, с кем общался раньше только в Инете. @otkds уже отмечал, что общались достаточно дружно, во время обеда и по окончании конференции все садились вместе, продолжали обсуждение.
У меня получилось побывать только на первом дне конференции, вечером надо было торопиться на поезд в Петербург. В целом впечатления от конференции положительные. Спасибо всем, с кем удалось пообщаться и кого удалось послушать :)
Ниже приведено несколько собранных мной ссылок по потоку Python.
Фотки:
Отчёты:
Другое:
Я выступлю с докладом об использовании внешних языков DSL и моей библиотеке funcparserlib на DevConf в секции Python. Конференция пройдёт в Москве 2010-05-17.
Перед конференцией организаторы взяли у меня небольшое интервью. В нём я упоминаю мои текущие проекты, рассказываю о теме предстоящего доклада.
Импортирование нововведений из модуля будущего __future__ — интересная
особенность языка Python. Языковые нововведения, которые появятся только в будущих
версиях, уже можно импортировать и использовать. Какие нововведения вы можете
использовать в вашей версии интерпретатора?
# -*- coding: utf-8 -*-
from __future__ import print_function, unicode_literals
import sys
def future_features():
import __future__
return dict((x, getattr(__future__, x))
for x in __future__.all_feature_names)
def version_str(v):
return '{0}.{1}.{2} {3} {4}'.format(*v)
print('running {0}\n'.format(version_str(sys.version_info)))
msg = '{0} {1}\t... {2}'
print('\n'.join(msg.format(k.ljust(20),
version_str(v.optional),
version_str(v.mandatory))
for k, v in future_features().items()))
Нововведения будущего в моём интерпретаторе:
running 2.6.5 final 0
division 2.2.0 alpha 2 ... 3.0.0 alpha 0
nested_scopes 2.1.0 beta 1 ... 2.2.0 alpha 0
unicode_literals 2.6.0 alpha 2 ... 3.0.0 alpha 0
with_statement 2.5.0 alpha 1 ... 2.6.0 alpha 0
absolute_import 2.5.0 alpha 1 ... 2.7.0 alpha 0
generators 2.2.0 alpha 1 ... 2.3.0 final 0
print_function 2.6.0 alpha 2 ... 3.0.0 alpha 0
Программа выше специально была написана совместимой с Python 3. Вот результаты на новом интерпретаторе:
running 3.1.2 final 0
division 2.2.0 alpha 2 ... 3.0.0 alpha 0
nested_scopes 2.1.0 beta 1 ... 2.2.0 alpha 0
unicode_literals 2.6.0 alpha 2 ... 3.0.0 alpha 0
barry_as_FLUFL 3.1.0 alpha 2 ... 3.9.0 alpha 0
with_statement 2.5.0 alpha 1 ... 2.6.0 alpha 0
absolute_import 2.5.0 alpha 1 ... 2.7.0 alpha 0
generators 2.2.0 alpha 1 ... 2.3.0 final 0
print_function 2.6.0 alpha 2 ... 3.0.0 alpha 0
Тем, кому интересно, советую попробовать импортировать из будущего
символы braces и barry_as_FLUFL. Подробнее см. Google :)
В Unix приветствуется создание небольших взаимодействующих программ, каждая из которых решает одну задачу. В частности, именно за счёт процессов ОС решаются проблемы параллелизации и многозадачности. Поэтому важно, чтобы программа стартовала быстро и не выполняла того, о чём её не просит программист.
Недавно я заинтересовался языком Clojure, который исповедует монолитный подход к параллельности. Я решил провести небольшое сравнение скорости выполнения крошечных программ “Hello World” на разных языках. Вот результаты сравнения:
Недавно натолкнулся на пост Actor Thinking об использовании акторов в стиле Erlang для «естественной» реализации параллельности. В посте поясняются уже знакомые слова Joe Armstrong об аналогии между акторами и объектами ООП.
Мне кажется, в этих рассуждениях в очередной раз допускается ошибка классического объектно-ориентированного подхода, будто почти все задачи естественно решать в стиле взаимодействующих объектов с локальным изменяемым состоянием. Наиболее ярко преимущества ООП выражаются как раз на системах без общей памяти, т. е. на взаимодействующих процессах. Тогда действительно люди при разработке думают об интерфейсах, инкапсуляции и пр.
При решении задач не нужно придумывать объекты. Сама задача уже говорит о том, какие есть объекты, если они вообще есть. Мелкие многочисленные объекты, как и мелкие параллельные процессы — это скорее недостаток, от которого следует избавляться, а не расхваливать.
Ken Thompson
Я выпустил библиотеку iterpipes 0.3 для запуска конвейеров команд в Python с использованием синтаксиса shell. С её помощью может стать удобнее писать многие скрипты на Python, чем на bash.
Несколько дней назад я писал об автомонтировании накопителей USB в Linux. В том посте был приведён простой скрипт на shell для определения текущего пользователя:
#!/bin/bash
uids () {
users | tr " " "\n" | uniq
}
if [ `uids | wc -l` == 1 ]; then
uid=`uids`
else
uid="0"
fi
echo ACTIVE_UID="$uid"
Вот как этот скрипт будет выглядеть на Python с использованием iterpipes:
#!/usr/bin/env python
from iterpipes import cmd, run, join
users = set(run(cmd('users') | join).split())
uid = list(users)[0] if len(users) == 1 else 'root'
print 'ACTIVE_UID=%s' % uid
Here you can find markdown vim syntax file made by Ben Williams. Put it to the ~/vim/syntax/ folder.
To add syntax...
“This image was taken on September 15, 2006 and received on Earth September 20, 2006. The camera was pointing toward Saturn at approximately 2M...
Well, it looks like GCC 4.3.2 does not comply to C99 specification. It clearly states that:
6.8.6.4.1 ... A...