Архив автора: admin

Контейнеры внедрения зависимостей для python

Начнем издалека — создание объекта инстанцированием класса плохо совместимо с идеями ООП. Они гласят, что код должен зависеть от интерфейсов, а не от реализаций. До тех пор пока на вход нашему коду приходят готовые объекты — все хорошо. Он будет с готовностью принимать любые типы, реализующие требуемый интерфейс, но как только мы начинаем создавать новые объекты ситуация меняется. Теперь код зависит от конкретного класса, что усложняет следующие задачи:

  • Изменение класса на другой, хоть и реализующий тот же интерфейс. Приходится вручную менять все точки инстанцирования, и, возможно, перекомпилировать код;
  • Выбор конкретного класса на основе внешних условий или точки инстанцирования;
  • Использование уже готового объекта — взятого из пула или какого то конкретного (синглетон);
  • Построение объекта с большим количеством зависимостей — приходиться передавать в точку конструирования все данные для построения множества взаимосвязанных объектов;
  • Не классическая проблема для ICC, но из той-же области:

Без подсветки синтаксиса

class A(object):
def __init__(self, val):
self.val = val

def __add__(self, val):
return A(self.val + val)

class B(A):
pass

print B(1) + 1 # <__main__.A object at 0x18877d0>

class A(object):
def __init__(self, val):
self.val = val

def __add__(self, val):
return A(self.val + val)

class B(A):
pass

print B(1) + 1 # <__main__.A object at 0x18877d0>

А хотелось бы получить экземпляр В.

Все эти проблемы связаны общей причиной — код делает работу, которую он делать не должен — инстанцирование конкретных классов. На самом деле чаще всего нам не нужен фиксированный класс. Нам нужен класс, предоставляющий определенный интерфейс. Нужно отвязаться от явного указания класса и передать его создание стороннему коду. Фактически мы хотим «виртуализовать» инстанцирование.

В самом простом случае можно воспользоваться фабричной функцией(ФФ). Если же мы хотим конфигурировать поведение ФФ, или сохранять состояние между вызовами (синглетон, пул объектов, etc), то логично сделать ФФ методом класса, в экземпляре которого будут храниться настройки. Такой класс может быть синглетоном(если конфигурация глобальная), или передаваться образом по цепочке вызовов во все точки, где нужно инстанцирование. Этот класс как раз и называется Inversion of Control Container (ICC дальше).

Для его использования нужно заменить прямое инстанцирование классов на вызов метода ICC. Параметрами метода будут требуемый интерфейс, и, возможно, контекст вызова и часть параметров для конструктора (последнее применяется редко). ICC возвращает готовый экземпляр. Конкретный класс для инстанцирования и параметры конструктора настраиваются програмно или берутся из конфигурационного файла.

Типичный пример — создание виртуальной машины в libvirt. Основная функция API принимает xml строку, описывающую виртуальную машину. Эта строка чаще всего берется вызывающим кодом из внешнего источника, потому как в большинстве случаев ему не важны подробности конфигурации для работы с VM соответственно и код создания можно унифицировать, а строку с конфигурацией использовать как черный ящик.

ICC также можно рассматривать как шаблон проектирования, объединяющий и унифицирующий другие порождающие шаблоны — ФФ, синглетон, и прочее.

Java и C# имеет различные реализации ICC (java spring, dagger) которые используются очень широко. Для питона же они практически не применяются. Сначала я покажу как написать pythonic ICC, а потом рассмотрю почему он не нужен. Написание своего связанно с тем, что по уже готовые пишутся людьми только что пришедшими с Java/C# и не отличаются питонистичностью.

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

Итак был такой код:

Без подсветки синтаксиса

class Bee(object):
def __init__(self, x):
pass

class Cee(object):
def __init__(self, x):
pass

assert isinstance(Bee(1), Bee)

class Bee(object):
def __init__(self, x):
pass

class Cee(object):
def __init__(self, x):
pass

assert isinstance(Bee(1), Bee)

Мы хотим иметь возможность не меняя код инстанцирования Bee выбирать что именно будет получаться — экземпляр Bee или Cee. С позиции duck typing классы Bee и Cee реализуют один и тот-же интерфейс и взаимозаменяемы, хоть мы это и не декларируем явным наследованием.

В принципе инстанцирование можно и не менять, но тогда его поведение будет не совсем очевидным. С первого взгляда кажется, что мы инстанцируем обычный класс Bee, а в итоге получаем экземпляр другого класса, который к классу Bee никакого отношения не имеет. Т.е. isinstance(Bee(), Bee) == False. Поэтому немного изменим пример. Bee и Cee будут наследовать общий интерфейс IBee и именно этот интерфейс мы и будем инстанцировать.

Без подсветки синтаксиса

class IBee(IOCInterface):
def __init__(self, x):
pass

class Bee(IBee):
def __init__(self, x):
print "Bee.__init__ called"

class Cee(IBee):
def __init__(self, x):
print "Cee.__init__ called"

IBee.register(Bee)
assert isinstance(IBee(1), Bee)

IBee.register(Cee)
assert isinstance(IBee(1), Cee)

class IBee(IOCInterface):
def __init__(self, x):
pass

class Bee(IBee):
def __init__(self, x):
print "Bee.__init__ called"

class Cee(IBee):
def __init__(self, x):
print "Cee.__init__ called"

IBee.register(Bee)
assert isinstance(IBee(1), Bee)

IBee.register(Cee)
assert isinstance(IBee(1), Cee)

Что бы это работало нужно перехватить конструирование объекта типа IBee и вернуть что-мы-там-хотим. Для этого вспоминаем, что конструирование объекта в python выражается следующим псевдокодом:

Без подсветки синтаксиса

# obj = Cls(x, y) ==>

obj = Cls.__new__(Cls, x, y)
if isinstance(obj, Cls):
Cls.__init__(obj, x, y)

# obj = Cls(x, y) ==>

obj = Cls.__new__(Cls, x, y)
if isinstance(obj, Cls):
Cls.__init__(obj, x, y)

Т.е. Cls.__new__ возвращает пустой экземпляр типа Cls, Cls.__init__ наполняет его реальными данными. Очень похоже на operator new + конструктор в С++. Итак нам нужно перегрузить IBee.__new__ и возвращать из него наш объект.

Без подсветки синтаксиса

ioc = {}

class IOCInterface(object):
def __new__(cls, *args, **kwargs):
return ioc[cls](cls, *args, **kwargs)

@classmethod
def register(cls, impl):
factory = lambda ccls, *args, **kwargs:
super(IOCInterface, ccls).__new__(impl, *args, **kwargs)
cls.register_factory(factory)

@classmethod
def register_instance(cls, obj):
cls.register_factory(lambda *args, **kwargs: obj)

@classmethod
def register_factory(cls, func):
ioc[cls] = func

ioc = {}

class IOCInterface(object):
def __new__(cls, *args, **kwargs):
return ioc[cls](cls, *args, **kwargs)

@classmethod
def register(cls, impl):
factory = lambda ccls, *args, **kwargs:
super(IOCInterface, ccls).__new__(impl, *args, **kwargs)
cls.register_factory(factory)

@classmethod
def register_instance(cls, obj):
cls.register_factory(lambda *args, **kwargs: obj)

@classmethod
def register_factory(cls, func):
ioc[cls] = func

Немного пояснений. Класс IOCInterface будет базовым для всех интерфейсов. Переменная ioc будет хранить текущую конфигурацию — отображение интерфейса на фабричную функцию для этого интерфейса. Для простоты примера мы будем хранить конфигурацию в глобальной переменной. Перегруженный метод __new__ получает инстанцируемый класс первым параметром, а дальше идут параметры конструктора. Он берет зарегистрированную для этого класса фабричную функцию и создает новый объект с ее помощью. IOCInterface.register позволяет зарегистрировать класс для данного интерфейса. IOCInterface.register_instance — зарегистрировать синглетон. Для унификации они создают специальные фабричные функции.

Замечания:

  • Нельзя использовать cls.__new__ как фабричную функцию в IOCInterface.register, так как мы получим вечный цикл. Нужно «проскочить» IOCInterface в иерархии сcls;
  • Для классов с перегруженным __new__ нужно смотреть по ситуации;
  • Есть соблазн просто сохранять класс/синглетон в словарь и потом в __new__

делать что-то вида;

Без подсветки синтаксиса

def __new__(cls, *args, **kwargs):
obj = ioc[cls]
if isinstance(obj, type):
return obj(cls, *args, **kwargs)
elif type(obj, (types.FunctionType, types.LambdaType)):
return obj(cls, *args, **kwargs)
else:
return obj

def __new__(cls, *args, **kwargs):
obj = ioc[cls]
if isinstance(obj, type):
return obj(cls, *args, **kwargs)
elif type(obj, (types.FunctionType, types.LambdaType)):
return obj(cls, *args, **kwargs)
else:
return obj

Делать этого не стоит, хотя бы потому что так мы не сможем зареги

Новогодние украшения

Наклейки превращаются в новогодние украшения

Впереди нас ждут чудесные новогодние праздники. Как креативно украсить елку дома или создать праздничную атмосферу в офисе? Нетривиальный подход к новогодним елочным игрушкам – необычные материалы, из которых можно легко своими руками сделать украшения для себя или в подарок. Мастерить любят все, превратим это занятие в увлечение для всей семьи. Елочные украшения своими руками — тема сегодняшней статьи.

Елочные украшения

Елочные украшения

Читать

deb-пакеты php5.5 и php5.3 под Debian Wheezy

Для одного клиента потребовалось обеспечить возможность переключения версии PHP для различных сайтов в панельке ISPConfig. На сервере установлен Debian Wheezy, в котором есть только PHP5.4.
Поэтому я скачал исходники PHP5.3 и PHP5.5 с сайта PHP: http://php.net/downloads.php, скомпилировал их и собрал из них простенькие deb-пакеты. Они включают в себя стандартный набор расширений и предоставляют бинарники для командной строки, cgi и php-fpm.
Выложил на github, вдруг кому-нибудь надо, чтоб быстро и работало:
https://github.com/scukonick/phpdeb

Можно спокойно устанавливать паралелльно дефолтному PHP, т.к. используются разные директории для установки.

Автор: AlexWinner

Устанавливаем дрова на сетевую карту Atheros AR9485

Прикупил себе сегодня новый бук взамен доблестно умершего. Моделька новая. Lenovo G500. Почитать о ней можно тут. Соответственно и железки новые. Не исключение и наша сетевуха. По умолчанию заработал тока Wi-Fi и локальная петля. Ethernet`а не было и в помине.

Открываем терминал и смотрим, что у нас внутри:
electrichp@electrichp-Lenovo-G500 ~ $ lspci -vv | grep Atheros
01:00.0 Ethernet controller: Atheros Communications Inc. Device 10a0 (rev 10)
02:00.0 Network controller: Atheros Communications Inc. AR9485 Wireless Network Adapter (rev 01)
После более чем трехчасовых поисков необходимого драйвера, последний был благополучно найден и прикручен. 
Нам необходимо скачать архив с названием compat-drivers-2013-03-26-u.tar.bz2 вот с этой странички https://www.kernel.org/pub/linux/kernel/projects/backports/2013/03/26/.
Далее открываем терминал, переходим в папку с загруженным и выполняем следующие команды:

tar -xvf compat-drivers-2013-03-26-u.tar.bz2
cd compat-drivers-2013-03-26-u
scripts/driver-select alx
make
sudo make install
sudo modprobe alx
После вышеперечисленных манипуляций все встает на свои места и пашет как надо.Это видно по выводу ifconfig:
electrichp@electrichp-Lenovo-G500 ~/Загрузки/compat-drivers-2013-03-26-u $ ifconfig
eth0 Link encap:Ethernet HWaddr 20:89:84:f6:ba:25
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:16

lo Link encap:Локальная петля (Loopback)
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:3534 errors:0 dropped:0 overruns:0 frame:0
TX packets:3534 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:222967 (222.9 KB) TX bytes:222967 (222.9 KB)

wlan0 Link encap:Ethernet HWaddr 48:d2:24:a9:16:fd
inet addr:192.168.0.79 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::4ad2:24ff:fea9:16fd/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18608 errors:0 dropped:0 overruns:0 frame:0
TX packets:11166 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:24376233 (24.3 MB) TX bytes:1306372 (1.3 MB)
Ну вот и все))) Кстати, имя драйвера, если кому пригодится: ath9k. Радуемся)))

Автор: Роман Дмитриевич

Рецепт Кальмары с чесноком и лимонным соком («Calamari all’aglio e profumo di limone»), пошаговый с фото»

Кальмары с чесноком и лимонным соком («Calamari all’aglio e profumo di limone»), пошаговый с фото»

Рецепт кальмаров с чесноком и лимонным соком очень прост в исполнении, это второе блюдо, приятное на вкус, лёгкое и несомненно удачное для тех, кому нравится этот вид морепродуктов и кто желает отведать его не только жареным, но и приправленным ароматным и вкусным соусом. Мы рекомендуем приготовить такие кальмары на женский праздник 8 марта, потому что их цвет в сочетании с жёлтым лимонным соком похож на мимозу.

Ингредиенты

  • Сливочное масло — 80 гр.
  • Оливковое масло — 1 ст. ложка
  • Чеснок — 4 зубчика
  • Петрушка — 3 ст. ложки
  • Сок и кожура одного лимона
  • Белое вино — 1 стакан
  • Перец чёрный молотый — по вкусу
  • Кальмары — 1,200 кг.
Длительность приготовления:
10Минут
Сложность приготовления:
Очень легко
Количество проций:
4

Процесс приготовления:


DariaL

Рецепт Говядина по-строгановски, бефстроганов («Manzo alla Stroganoff»), пошаговый с фото

Говядина по-строгановски, бефстроганов («Manzo alla Stroganoff»), пошаговый с фото

Говядина по-строгановски, бефстроганов — это вкуснейшее блюдо русской кухни, приготовленное из мелко нарезанных кусочков говядины, обжаренного лука и шампиньонов. Особенность этого блюда состоит в том, что мясо заливается сметанным соусом, который придаёт блюду неповторимый вкус и аромат. Существует две легенды о происхождении мяса по-строгановски: некоторые полагают, что впервые оно было приготовлено служившим у графа Строганова французским поваром, который добавил сметану в классический рецепт французского мясного рагу, чтобы быть ближе к предпочтениям русского графа. Блюдо имело успех и его назвали, по традиции той эпохи, в честь графа Строганова. Другие же полагают, что Строганов — это имя врача, который вылечил отравление сельдью у царицы Марии с помощью диеты на основе говядины, репчатого лука и сметаны. Говядина по-строгановски — это вкусное, насыщенное блюдо, идеально подходящее для богатого зимнего застолья.

Ингредиенты

  • Лук репчатый — 500 гр.
  • Шампиньоны — 500 гр.
  • Сливочное масло — 50 гр.
  • Сметана — 80 гр.
  • Оливковое масло — по вкусу
  • Измельчённая петрушка — 2 ст.ложки
  • Соль — по вкусу
  • Перец — по вкусу
  • Водка — 45 мл
  • Томатная паста / пюре — 50 гр.
  • Вода — по вкусу
  • Мука — по вкусу
  • Говяжья вырезка — 1 кг
Сложность приготовления:
Легко
Количество проций:
4

DariaL