Архив рубрики: Без рубрики

Функциональный стиль в питоне

Пост чисто философский

Периодическое чтение кусков кода, написанных при обострении хаскеля головного мозга, выработало у меня четкую ассоциацию: функциональный стиль — это нечитаемо. Точнее стиль с множеством map/filter/zip. Вот немного облагороженный пример такого кода (автор считает, что с кодом все ок):

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

some_res = ", ".join(
map(str,
filter(None,
map(lambda x: getattr(obj.zip, x, None),
['a', 'b', 'c', 'd']))))

some_res = ", ".join(
map(str,
filter(None,
map(lambda x: getattr(obj.zip, x, None),
['a', 'b', 'c', 'd']))))

Без переписывания в многострочный вариант ориентироваться в нем вообще сложно:

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

attrs = ['a', 'b', 'c', 'd']
attr_vals = map(lambda x: getattr(obj.zip, x, None), attrs)
non_none_attrs = filter(None, attr_vals)
some_res = ", ".join(map(str, non_none_attrs))

attrs = ['a', 'b', 'c', 'd']
attr_vals = map(lambda x: getattr(obj.zip, x, None), attrs)
non_none_attrs = filter(None, attr_vals)
some_res = ", ".join(map(str, non_none_attrs))

Этот вариант читается лучше уже потому, что понизилась концентрация логики, и добавились переменные, имена которых служат документацией промежуточным результатам. Но, IMO, это не главные причины.

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

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

x = some_func1(a, b, some_func2(c, d), e)

x = some_func1(a, b, some_func2(c, d), e)

Понятно, что со временем это прошло, но осадок остался — в выражения где много вложенных вызовов и скобок сложно быстро соотнести параметры, функции и удерживать это в голове, пока его анализируешь. Если код не форматирован построчно, как пример выше, то совсем тяжело.

Следующий случай — это функциональный стиль в скале. Его чтение у меня не вызывает того чувства трясины, какое вызывал аналогичный код в python/haskell. Тот же пример на 'скалапитоне' выглядел бы так:

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

some_res = ['a', 'b', 'c', 'd'].map(getattr(obj.zip, _, None))
.filter(Non e).map(str).join(",")

some_res = ['a', 'b', 'c', 'd'].map(getattr(obj.zip, _, None))
.filter(None).map(str).join(",")

Если отвлечься от более удобной формы записи лямбды, то он все равно читается гораздо проще. Мне кажется дело в том, что он читается линейно слева направо, а не «вообще изнутри наружу, но местами слева направо», как читается код в питоне.

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

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

a(x, b(c(), 1, 4), 'd')
# vs
c().b(1, 4).a(x, 'd')

a(x, b(c(), 1, 4), 'd')
# vs
c().b(1, 4).a(x, 'd')

К сожалению питон чаще всего не позволяет писать сцепленными методами, поскольку бОльщая часть методов возвращает None вместо self (а именно все, которые модифицируют объект на месте), а map/filter — функции, а не методы.

Итого я для себя сменил идею с «функциональный код нечитаем» на «функциональный код, написанный в процедурном стиле, нечитаем».

Ссылки:
          ananthakumaran.in/2010/03/29/scala-underscore-magic.html

Исходники этого и других постов со скриптами лежат тут — github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.

Автор: konstantin danilov

Контейнеры внедрения зависимостей для 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

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

Устанавливаем дрова на сетевую карту 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. Радуемся)))

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

Дружим Linux Mint и Samsung Smart TV



Недавно приобрел в домашнее пользование Samsung Smart TV 5-ой серии. Так как смартфон был прикручен моментально через AllShare самсунговский и весьма успешно работает, было решено еще и нубук прикрутить. Путем выкуривания форумов и мануалов было решено ставить приложение MiniDLNA. Есть конечно еще несколько подобных софтин, но у всех свои затыки. Какая тупит, а какая русскую локаль не понимает. Хотя возможно все это из-за кривости моих рук. 
Итак, начнем-с пожалуй.




1. Установка

Как обычно, три варианта. Первый вариант через преславутый Менеджер программ. Второй — с терминала командой:
sudo apt-get install minidlna
Третий — через PPA следующей командой:
sudo add-apt-repository ppa:stedy6/stedy-minidna
sudo apt-get update
sudo apt-get install minidlna

2. Конфигурирование
Ну а тут уже веселее. Сам конфиг лежит тут: /etc/minidlna.conf.
Открываем из под рута любым методом, или как я через gedit:
sudo gedit /etc/minidlna.conf
Cмотрим, что там есть. Базовый файл с настройками имеет комментарии ко всем параметрам. Все довольно просто и понятно. Вносим лишь кастом-поправки, такие как пути до каталогов с медиаконтентом, имя сервера и так далее. Вот пример моего конфига (комменты переведены):

# порт для HTTP (подписи, SOAP, передача мультимедиа) траффика
port=8200

# сетевые интерфейсы для работы сервера, разделяйте запятыми
network_interface=wlan0

# укажите директории для сканирования.
# * можете у

RetroShare. Описание вкладки "Друзья"

Начиная с этой статьи, мы будем рассматривать интерфейс программы более подробно. Кому-то это покажется ненужным и неинтересным, ибо сам разобрался, кому-то вообще не нужно, а кому может и пригодится.
Первую вкладку под названием «Новостная лента» я рассматривать не буду в силу ее простоты. Там всего две кнопки. Первая — «Параметры», которая запускает раздел настроек «Notify» (Всплывающих сообщений). Вторая — «Remove all», которая удаляет все сообщения в этой вкладке. Маленький совет лично от меня — отключите новые сообщения в настройках новостной ленты. После часового общения в чате найти в ленте необходимое сообщение, например, об окончании загрузки файла, становится весьма проблематичным.

Теперь мы поговорим о второй и основной по своей сути вкладке «Друзья«. Скриншот я уже выкладывал в предыдущих статьях. Выложу еще раз. Вот так она выглядит:


Поговорим о том, что есть на этой вкладке. Во-первых, это окно под названием «Друзья», в котором отображаются все ваши друзья, а так же группы. Все просто. По правой кнопке мыши на нике товарища  появляется контекстное меню:
Это меню полностью локализовано и какой-либо сложности для самостоятельного разбора и понимания не представляет.
Едем дальше. На картинке слева мы видим пару раскрывающихся списков, о которых поговорим чуть ниже, строку поиска, и, соответственно, само окно с друзьями, которых можно сортировать по имени. Теперь разберемся с выпадающими меню. 
Вот первое:
Про сортировку списка друзей говорить ничего не буду — все более чем понятно. 
В Columns  выбираем дополнительные колонки, отображаемые у друзей. Это: аватар, последний контакт и по умолчанию выбранный статус.
В  Sort by — выбираем метод сортировки списка: имя, состояние, последний контакт.
Set root is Decorated — включение украшений окна.

Теперь поговорим о зеленом плюсике))) 
С первыми тремя вопросов возникать не должно, потому переведем то, что на буржуйском.

Friend Recommendations — рекомендовать друга;
Service permissions — сервисные разрешения;
Set your status message — установить статусное сообщение.

Теперь рассмотрим три вкладки в правой стороне окна. Первая вкладка «Broadcast» — это ни что иное, как общественный чат программы. Общаемся, добавляем файлы для друзей.  
Вторая вкладка «Local network«. На этой вкладке в графическом виде показано взаимодействие Вас и Ваших друзей с Вами и друг с другом. Пример:
Кнопка «Redraw» перерисовывает схему подключений. «Friendship level» — уровень дружбы. «Edge length» — длина линий.

Третья вкладка «Known people» (Известные люди) — список известных Вам людей и некоторые данные о них.
Желтым цветом выделены люди, у которых уровень доверия неизвестен. Соответственно зеленым — люди, имеющие максимальный уровень доверия. Разберем по колонкам.
С  колонкой «Имя» все понятно. Имя Вашего друга. В колонке «Did I authenticated peer» (Утверждение мною подлинности пира) показывается уровень доверия, выставленный Вами своим друзьям. Колонка «Did peer authenticated me» (Утвержденная подлинность пира для меня) — это уровень доверия, выставленный Вам вашими друзьями. В колонке «Cert Id» — выводится идентификационный номер сертификата товарища. Колонка «Last used» (последнее использование) — это время последнего использования программы.
Также присутствует поиск по имени и ID друга. Если поставить галочку напротив «Show all accesible keys» (показать все доступные ключи) — то в нижней части экрана вы увидите все доступные ключи Вас и Ваших друзей.
Если на имени друга нажать правую кнопку мыши — появится следующее контекстное меню:
— отказать другу в доступе.
— детали пира.
-копирование ссылки RetroShare.

— удаление неиспользуемых ключей (друзей)

Вот и все, что есть в этой вкладке. В следующей статье рассмотрим вкладку «File sharing» и научимся качать файлы из расшаренных папок друзей и выкладывать к общему доступу Ваши файлы и папки.

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

Уникальное ценовое предложение на шлифовку и покраску деревянных домов и бань

[singlepic id=851 w=640 h=480 float=right] Компания Royal Wood предлагает услуги по шлифовке, грунтовке и покраске деревянных фасадов снаружи и внутри деревянных домов и бань профессиональными продуктами Tikkurila по очень выгодной цене!

Стоимость — от 25$/1м2.

За эту цену вы получаете:

— Помощь при подборе цветового решения для фасадов деревянного дома или бани от профессионального архитектора;

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

— Шлифовку деревянной поверхности стен.

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

— Защита деревянной поверхности стен с помощью нанесения грунтующего состава Pinja Oil — Tikkurila в 1 слой;

Используем Pinja Oil – пропиточный состав из профессиональной линейки Tikkurila для дерева на основе натурального масла. Защищает древесину, антисептирует и подготавливает ее для дальнейшего тонирования или окрашивания.

— Покраска деревянных фасадов с помощью нанесения на стены лессирующего антисептика Tikkurila в 2 слоя. Цвет на выбор.

Мы используем продукт Pinjasol Color – лессирующий анти-септик для наружных деревянных поверхностей. Колеруется по карте Valtti Color.

ИНТЕРЕСНО:

Фото домов, покрашенных красками и антисептиками Тиккурила ( Tikkurila)

Продукция Тиккурила с ценами,  в наличии в Минске!

Прайс- лист Тиккурила.

Другие новости:

Стильный каркасный дом площадью 130м2 для молодой семьи.

Каркасное домостроение в лучших традициях!

[gview file=»http://royalwood.by/wp-content/uploads/2013/06/Tikkurila_valtti.pdf» profile=»4″ save=»1″]