December 27, 2011

Сопоставление объектов с образцом (pattern matching)

В функциональных языках есть интересная возможность, фактически являющаяся расширением идеи перегрузки функций - сопоставление с образцом. Для этого поддерживается специальный синтаксис шаблонов структур данных, позволяющий проверить что объект имеет определенный тип и/или поля, а также извлечь из него некоторые данные. Пример из haskell (частично взято тут wiki):

Без подсветки синтаксиса
-- f - функция от одного целого параметра
-- возвращающая целое
f :: Int -> Int
f 1 = 0
-- если ей передать 1, то она вернет 0
f _ -> 1
-- если что-либо другое - 1

-- map от чего угодно и пустого списка возвращает пустой список
map _ []     = []
-- рекурсия - map от функции и списка это конкатенация 
-- f от первого параметра и map от f и остатка списка
map f (x:xs) = f x : map f xs

-- разбор структуры
-- Foo это или Bar или Baz 
data Foo = Bar | Baz {bazNumber::Int, bazName::String}    
h :: Foo -> Int
-- Baz - это тип структуры, bazName - это имя поля
h Baz {bazName=name} = length name
h Bar {} = 0

Примерно тоже можно сделать во многих функциональных языках, но я никогда не видел подобных возможностей в императивных языках. Самое близкое что есть по интеллектуальности - перегрузка функций в C++. Такое положение связанно и с особенностями задач, обычно решаемыми в функциональных языках, и с их ориентированностью на рекурсивные структуры данных и с попытками уйти от if и других императивных особенностей.

December 24, 2011

libvirt & Co. Облако "на коленке". Часть 2 - Сети


Компоненты

Функционирование виртуальных сетей обеспечивается различными технологиями, которые я бегло опишу:

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

Без подсветки синтаксиса
$ brctl  show  # напечатать все бриджи с подключенными интерфейсами
bridge name     bridge id               STP enabled interfaces                                                                 
virbr0          8000.000000000000       yes                      

# brctl add <name>     - добавить бридж
# brctl addif <brname> <ifname>      - включить eth в бридж
# brctl delif <brname> <ifname>      - отключить интерфейс
# brctl delbr <brname>               - удалить бридж

Перед работой с бриджами лучше ознакомиться с документацией, они содержат некоторое количество нетривиальных моментов.

December 22, 2011

libvirt & Co. Облако "на коленке". Часть 1


Buzzword

Облако(cloud) это инфраструктура для управления виртуальными машинами. Агенты облака устанавливаются на железных серверах, превращая их единый мегасервер, которые используется для виртуализации. Облако должно уметь:

  • запускать группы виртуальных машин на базе загруженных в него образов
  • изменять образы виртуальных машин
  • управлять сетевой инфраструктурой - объединять виртуальные машины в ( возможно виртуальные ) локальные сети, настраивать правила доступа к этим сетям извне и доступ наружу из сетей
  • поддерживать остановку, приостановку и миграцию виртуалок
  • балансировать нагрузку на железные сервера
  • управлять местом на дисках
  • ..............

Предисловие

На сегодняшний день есть четыре основных облачных системы - перспективный и активно развиваемый openstack, рабочий но мало интересный из-за лицензии eucalyptus, совсем-совсем проприетарный VMware vCloud и очень-очень microsoft azure. Но это все "серьезные" облака, а как это часто бывает большие системы не удобно использовать на малых задачах. Я расскажу как управлять небольшими группами виртуальных машин "малой кровью". Впрочем openstack использует эти же утилиты, а все остальные узнают на чем основываются linux клауды.

Решение предыдущего поста

Если вы не читали предыдущий пост - начните с него.

December 20, 2011

Как это сделано?

Отсутствие перегрузки функций - это то что мне всегда не нравилось в python. Не то что бы без них невозможно было жить, да и виртуальные методы типа __len__ сглаживают проблему, но все-таки. И пусть есть PEAK.rules, но его синтаксис всегда раздражал. Ну вот как можно без боли смотреть на это:

Hightlited/Raw
from peak.rules import abstract, when

@abstract()
def pprint(ob):
    """A pretty-printing generic function"""

@when(pprint, (list,))
def pprint_list(ob):
    print "pretty-printing a list"    

@when(pprint, (int,))
def pprint_int(ob):
    print "pretty-printing an integer"

#......

Во-первых опять нужно придумывать для каждого типа свои имена функций, во-вторых не по-питоновски много лишних нажатий клавиш, даже в С++ это - лишнее: @when(pprint, ( :).

December 12, 2011

Интерфейсы в python или "Предъявите документы!"

При написании не тривиальных приложений возникает вопрос: над какими библиотеками делать еще один абстрактный слой, а над какими - нет? Какие абстракции делать?

Стоит ли делать прослойку над, например, SQLAlchemy? Это же и так прослойка над SQL и DBAPI. Имеет ли смысл делать уровни абстракций над такими достаточно хорошими и отточенными в смысле интерфейсов библиотеками?

Ответ очень простой - библиотеки представляют API который должен быть применим для широкого спектра приложений. Они отображают низкоуровневые (с точки зрения их API ) вызовы на более высокоуровневый, но абстрактный интерфейс. Характерный пример - библиотеки передачи сообщений. Они позволяют не думать о сокетах, упаковке/распаковке float/int и т.п., а просто передавать структуры данных.

December 11, 2011

Об уровнях абстракций - The Very Last API

При написании не тривиальных приложений возникает вопрос: над какими библиотеками делать еще один абстрактный слой, а над какими - нет? Какие абстракции делать?

Стоит ли делать прослойку над, например, SQLAlchemy? Это же и так прослойка над SQL и DBAPI. Имеет ли смысл делать уровни абстракций над такими достаточно хорошими и отточенными в смысле интерфейсов библиотеками?

Ответ очень простой - библиотеки представляют API который должен быть применим для широкого спектра приложений. Они отображают низкоуровневые (с точки зрения их API ) вызовы на более высокоуровневый, но абстрактный интерфейс. Характерный пример - библиотеки передачи сообщений. Они позволяют не думать о сокетах, упаковке/распаковке float/int и т.п., а просто передавать структуры данных.

December 9, 2011

Оператор with


Теория

Оператор with появился в python 2.5, но, не смотря на это, используется до сих пор недостаточно широко. Являясь упрощенной версией анонимных блоков кода with позволяет:

  • исполнить код до начала блока
  • исполнить код по выходу из блока, независимо от того это выход по исключению с помощью return или другим способом
  • обработать исключение, возникшее в блоке.

Синтаксически with выглядит следующим образом:

Hightlited/Raw
with operation:
    code

operation может быть объектом, выражением или конструкцией вида expression as var. Как и много других конструкций он является синтаксическим сахаром для более громоздкого выражения:

December 7, 2011

Динамические атрибуты в python. Часть 1, теоретическая - "в поисках атрибута"

Disclamer: рассмотрены только новые классы - все наследуемые от object. В "старых" классах все работает немного по-другому.

Во всей статье классы именуются с заглавной буквы, а экземпляры классов со строчной. A это класс экземпляра a.

Вопрос о том что происходит когда python исполняет конструкцию a.b очень важен для понимания многих других тем. Особенно учитывая что имитация атрибутов один из наиболее часто используемых приемов для написания библиотек в pythonic стиле.

December 6, 2011

Метаклассы в python 2.X с примерами и полным разоблачением


Теория, часть 1. Метаклассы

Все начинается с объявления класса:

Hightlited/Raw
class A(object):
    field = 12
    def method(self, param):
        return param + self.field

Имеющие опыт программирования на компилируемых языках могут увидеть здесь декларативную конструкцию, но это только обман зрения. В python всего две декларативные конструкции - объявление кодировки файла и импорт синтаксических конструкций "из будущего". Все остальное - исполняемое. Написанное объявление это синтаксический сахар для следующего:

Hightlited/Raw
txt_code = """
field = 12
def method(self, param):
    return param + self.field
"""

class_body = {}
compiled_code = compile(txt_code, __file__, "exec")
eval(compiled_code, globals(), class_body)
A = type("A", (object,), class_body)