Tuesday, June 7th, 2011
Многим очень нравится дизайн гитхаба, один из элементов, на который стоит обратить внимание отдельно это – кнопки (сининькие такие). Такие динамические кнопки смотрятся очень круто и с легкостью впишутся в интерьер любого сайта. Вообщем ближе к делу: в основе github buttons лежат 3и технологии – CSS, HTML и jQuery. Архив с ксс стилями и js можно скачать CSS3 Buttons, посмотреть как это выглядит – github style кнопки.
Posted in Code, html & css, OpenSource | No Comments »
Sunday, May 8th, 2011
Решил потратить свободное воскресенье на написание чего-нибудь интересного, размять мозги, освоить какие-нибудь новые приемы, короче говоря разбавить рутину повседневных дел. Задача достаточно тривиальна – написать аналог Hello World используя генетические алгоритмы.
Выложил код на github – Hello World генетическими алгоритмами. Там же лог где можно посмотреть как происходит решение задачи.

Что представляют собой эти генетические алгоритмы? Они решают задачи точно так же как это делает природа, т.е. через “естественный отбор”, соответственно критерии этого отбора должны быть достаточно просто вычисляемы – в моём случае это так называемая fitness функция которая посимвольно сравнивает решение с оригинальной строкой, чем лучше решение – тем ближе выход функции к нулю.
def fitness(dnk, goal):
f = 0
for index, gene in enumerate(dnk):
if gene != goal[index]:
f -= 1
return f
Решение задачи представляется в виде вектора значений [a, b, c, d, ..., x] (в нашем случае это строка) длина которого известна, я обернул это в класс методы которого предоставляют интерфейс для взаимодейтсвия (class GeneticCode), на начальном этапе создаётся “популяция” (скажем 100) этих векторов инициализируемых случайными значениями.
self.pool = [GeneticCode(goal=goal) for item in range(self.pool_size)]
Затем fitness функция делает оценку каждого вектора популяции в коде, и далее лучшие образцы (скажем 10% от всей популяции) переходят на следующий круг. Существуют разные вариации генетических алгоритмов, кто хоть немножко разбирается в биологии и знает как происходит естественный отбор без труда могут придумать различные улучшения. Напоминаю, на данный момент у нас, после “естественного отбора” осталось 10% от популяции, где-то нужно взять остальные 90%, я решил на этом этапе провести “скрещивание”, т.е. различные простейшие рекомбинации исходных векторов данных (одна часть берется от одного вектора, другая от второго и в результате получается, что-то новое). Детали этого этапа реализованы в методе def darvin(self, winners=0.1) класса GenePool.
Далее происходит “эволюция”, т.е. кажый вектор испытывает какие-то случайные мутации (не затрагивая те элементы которые уже совпадают с оригинальной строкой). Затем опять приходит старик Дарвин, выбирает лучшие решений и процесс начинается заново. И так до тех пор пока решение не будет найдено. Если строка достаточно длинная + популяция мала и слишком много решений проходит отбор – генетический алгоритм может работать очень долго, поэтому неплохо будет ограничить кол-во итераций, скажем 1000 будет вполне достаточно.
Собственно классический “Hello world” получился примерно так (каждая строчка – лучший результат на каждом шаге) :
s(_soclbi!P*
{k&soclbil^!
oiYloC>otPC!
Evlso$>oil^!
EvlmoC>oild!
oil!oC>orld!
?vlloC>orld!
?elloCqorld!
GelloCqorld!
GelloCqorld!
Tello qorld!
oello qorld!
Tello world!
Tello world!
Tello world!
Hello world!
Естественно я только немного коснулся этой темы, спектр применений генетических алгоритмов достаточно широк, в том числе их используют совместно с нейросетями.
- Оптимизация функций
- Оптимизация запросов в базах данных
- Разнообразные задачи на графах (задача коммивояжера, раскраска, нахождение паросочетаний)
- Настройка и обучение искусственной нейронной сети
- Задачи компоновки
- Составление расписаний
- Игровые стратегии
- Теория приближений
- Искусственная жизнь, проекты типа EvoGrid
- Биоинформатика (свертка белков)
Для тех кто хочет попробовать, есть уже готовые библиотеки для python которые избавят вас от рутины написания лишнего кода.
http://www.freenet.org.nz/python/pygene/
http://pyevolve.sourceforge.net/
Posted in Code | No Comments »
Thursday, November 25th, 2010
Первая пачка ответов на вопросы из этого поста. Тут все элементарно, если знать немножко про функциональное программирование и ориентироваться в стандартных функциях.
1. Как получить список всех атрибутов объекта?
Очень просто, используя стандартную функцию dir. В качестве аргумента передаем тот самый объект, в данном случае (ради примера) объект string.
import string
print dir(string)
# Или так
import inspect
print [name for name,thing in inspect.getmembers(string)]
Модуль inspect предоставляет несколько очень классных методов которые позволяют собирать информацию о объектах Python.
Используя inspect можно получить содержимое класса. получить исходный код метода, выделить формат и список аргументов функции и т.д.
2. Как получить список всех публичных атрибутов объекта?
Private методы в Python начинаются с “__” поэтому все что нужно сделать чтобы получить список публичных это отфильтровать все что начинается с “__”. Тут будут очень к месту элементы функционального программирования – функция filter(f, lst) которая формирует новый список элементов последовательности – lst руководствуясь функцией f.
import sting
# так проще для понимания
def f(x):
if x[:2] == "__":
return False
else:
return True
print filter(f, [atr for atr in dir(string)])
# а это то же самое в одну строчку
print filter(lambda x : False if not cmp(x[:2], "__") else True, [atr for atr in dir(string)])
3. Как получить список методов объекта?
Используя функцию callable() которая как бы говорит реально ли вызвать объект или нет. если вызвать реально – то это метод, если нет – то свойство
print filter(lambda x : callable(getattr(string, x)), [atr for atr in dir(string)])
4. В какой “магической” переменной хранится содержимое help?
В __doc__
print string.__doc_
5. Есть два кортежа, получить третий как конкатенацию первых двух.
Элементарно.
a = (1,2)
b = (3,4)
print a + b
6. Есть два кортежа, получить третий как объединение уникальных элементов первых двух кортежей.
Сначала преобразуем конкатенацию (операция склеивания объектов линейной структуры, обычно строк) в объект – множество (элементы которого уникальны, т.е. не могут повторятся, это свойство объекта) а затем преобразуем обратно в кортеж.
a = (1,2,3)
b = (5,3,6)
print tuple(set(a + b))
7. Почему если в цикле меняется список, то используется for x in lst[:], что означает [:]?
[:] означает, что берется копия списка и далее делается цикл по его элементам, таким образом получаем возможность работать с оригинальным списком, без опасений что изменения в нем повлияют на работу цикла.
a = [1,2,3,4]
print a
for i,elem in enumerate(a[:]):
a[i] = elem * elem
print a
8. Есть два списка одинаковой длины, в одном ключи, в другом значения. Составить словарь.
Преобразуем в пары (a,1) и т.д. c помощью zip и далее преобразование в тип данных – словарь с помощью функции dict()
a = ['a','b','c']
b = [1,2,3]
print dict(zip(a,b))
9. Есть два списка разной длины, в одном ключи, в другом значения. Составить словарь. Для ключей, для которых нет значений использовать None в качестве значения. Значения, для которых нет ключей игнорировать.
Посидел, полумал, записал в одну строчку. Все просто если немножко понимать основы функционального программирования. Наверняка можно записать короче.
# можно так но тогда не выполняется 2ая часть условия. игнорирование значений для которых нет ключей.
a = ['a','b','c','d']
b = [1,2,3]
print dict(map(None, a, b))
a = ['a','b','c']
b = [1,2,3,4]
# выполняет все требования задания.
print dict(filter(lambda x : False if x is False else True, map(lambda x, y : (x, y) if x is not None else False, a, b)))
10. Есть словарь. Инвертировать его. Т.е. пары ключ: значение поменять местами — значение: ключ.
На помощь приходит метод items() который возвращает элементы словаря в виде кортежа (в виде пар) – (key, value)
a = {'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4}
print dict([(y,x) for (x,y) in a.items()])
11. Есть строка в юникоде, получить 8-битную строку в кодировке utf-8 и cp1251.
str = u'unicode sting'
print str.encode('utf-8')
print str.encode('cp1251')
12. Есть строка в кодировке cp1251, получить юникод строку.
str = 'cp1251 string'
print str.decode('cp1251')
Чтобы более детально осознать о чем идет речь :
http://docs.python.org/library/inspect.htm
http://docs.python.org/reference/datamodel.html
http://docs.python.org/tutorial/datastructures.html
http://docs.python.org/library/stdtypes.html
http://docs.python.org/library/functions.html
http://docs.python.org/howto/unicode.html
Posted in Code, Python | 1 Comment »
Thursday, November 25th, 2010
Рыская по просторам интернетов, натолкнулся на “Вопросы и задания по Python”. Польза этих вопросов очевидна – подобные задания могут предлагать вам в качестве теста на человека который более менее разбирается в вопросе. + ответы на эти несложные вопросы помогут вам систематизировать свои знания.
Полностью список можно найти тут http://pyobject.ru/blog/2010/02/04/python-quiz/
Вопросы и задания по Python
- Типы данных, основные конструкции
- Функции
- Итераторы
- Модули
- Классы
- Метаклассы и дескрипторы
Posted in Code, Notes, Python | 1 Comment »
Saturday, November 20th, 2010
Для тех кто ранее изучал php и привык к тому, что код как бы встраивается в страницу при переходе на Python становится актуальным вопрос : а как сделать подобное на Pyhton? Тут сделано немного не так, но тоже достаточно удобно. Дело в том, что Python изначально проектировался как полнофункциональный язык программирования, в отличии от PHP забацаного чтобы студенты могли по быстрому написать Home Page (aka хомяк). Существует несколько подходов к тому как отображать контент в веб :
- Модель статических страниц (static page model). В первой половине 90х годов все страницы веба были статическими, то есть содержали в себе готовый документ в формате HTML. Соответственно, страницы не требовали предварительной обработки и не зависели от аргументов.
- CGI — сценарии. Исполняемые на сервере программы используют для вывода результата библиотечные функции записи в стандартный вывод(print для языков С/C++, write для языка Pascal и т.п.). Код представления данных разбросан среди кода программы в аргументах вызовов этих функций.
- Модель динамических страниц (dynamic page model). Не зависящая от аргументов часть страницы пишется в HTML-коде, а функциональная часть встраивается в код страницы с помощью специальных тегов — скриптлетов.
- Модель MVC. Реализация шаблона проектирования модель-представление-контроллер (Model-View-Controller), для разделения зависимости кода представления и кода программного обеспечения, работающего с ресурсами сервера.
Последний подход все больше входит в моду и становится популярным среди web-девелоперов. Впрочем, в PHP так же есть средства (фрэймворки) позволяющие использовать эту модель по полной программе, в частности Zend Framwork.
Питон в свою очередь может похвастаться большим количеством грамотно построенных фрэймворков пользоваться которыми одно удовольсвие. Местная звезда – фрэймворк Django, на основе которого собирается сайт практически любой сложности, от форумов до блогов. И все же в чем преимущества MVC? Их несколько, одно из самых существенных – разделение кода/данных/дизайна
Ближе к делу. MVC.
Как это работает? Очень просто как следует из названия у системы 3и компонента Model, View и Controller. Каждый компонент отвечает за свою область, поэтому достаточно легко разделить усилия программистов и дизейнеров между этими частями, пусть каждый занимается своим делом.
MVC определяет способ разработки программного обеспечения при котором код для определения и доступа к данным (модель – model) отделён от логики приложения (управление – controller), которая в свою очередь отделена от интерфейса пользователя (представление – view).
Model – отвечает за представление и обработку данных. Часто используется ORM что значительно упрощает разработку.
View – отвечает за отображение информации, за представление её пользователю в удобном виде.
Controller – связывает модель и представление. Передает данные, введённые пользователем в модель другими словами является средством, при помощи которого пользователи взаимодействуют с системой.

Рассмотрим View подробнее, ведь это именно то, что визуализирует сухие данные. Для представления используют так называемые Template Engines. Выглядит это примерно так :
<title>{% block title %}{% endblock %}</title>
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
Их достаточно много, отдельно можно выделить Jinja2 и Mako. В чистом виде движки шаблонов позволяют вам генерировать статические страницы (html код). Т.е. используя движек шаблонов можно располагая какими-то данными написать код который будет собирать готовый сайт. Нужно было сгенерировать несколько сайтов используя каталог товаров, получилось примерно так :
env = Environment(loader=FileSystemLoader(TEMPLATE_FOLDER))
sitemap_list = []
# render index pages
for page, items in zip(index_pages, grouper(shop_items, ITEMS_PER_PAGE)):
page_data = form_nav_panel(page, index_pages)
template = env.get_template('index_pages.html')
random_5 = random.sample(shop_items, 5)
html = template.render(
index_page=True,
page_data=page_data,
index_pages=index_pages,
items_in_store=len(shop_items),
current_page = page,
items=items,
random_5=random_5,
current_date=datetime.now().strftime("%d. %B %Y")
)
with open("./sites/mystaticsite/%s" % str(page['fname']), "w") as f:
f.write(html.encode("utf-8"))
sm = {
'url' : page["fname"],
'title' : "Item list : " + str(page['id'])
}
sitemap_list.append(sm)
Т.е. берется шаблон (html + тэги движка шаблонов) загружается с помощью Jinja2, далее в функцию рендера передаются нужные данные, на выходе имеем готовый html код. Получать уникальные шаблоны несложно, используя плагины вроде ScrapBook. Грабим понравившуюся страницу, меняем дизайн по вкусу, расставляем тэги. Зачастую типовые страницы отличаются друг от друга в строении, но не на много (header + content + sidebar + footer). Чтобы не копировать полностью html код, переписывая тэги, Jinja2 предоставляет такую мощную фичу как наследование.
{% extends "index.html" %}
{% block title %}Fuck you spomoni{% endblock %}
{% block page_title %}(^_^){% endblock %}
{% block navigation_bar_top %}
<div id="navigation_bar">
<h1>Items in store : {{ items_in_store }}</h1>
<span>{% if page_data['prev_page_id'] is defined %}<a href="{{ page_data['prev_page_fname'] }}" rel="prev">« Previous </a>{% else %}« Previous {% endif %}</span>
{% for item in index_pages %}
{% if item['id'] == current_page['id'] %}
<span>{{ item['id'] + 1 }}</span>
{% else %}
<span><a href="{{ item['fname'] }}">{{ item['id'] + 1 }}</a></span>
{% endif %}
{% endfor %}
<span>{% if page_data['next_page_id'] is defined %}<a href="{{ page_data['next_page_fname'] }}" rel="next"> Next »</a>{% else %}Next »{% endif %}</span>
</div>
{% endblock %}
К предыдущему примеру. Это файл представляет собой шаблон “как он есть”, невооруженным глазом можно заметить что он наследуется от index.html переопределяя некоторые блоки, об этом явно говорит строчка : {% extends “index.html” %}
Вот таким образом и происходит построение сайта используя Template Engine. Если к этому добавить еще работу с БД и контроллер получится как раз таки этот самый MVC. Однако если нет необходимости часто менять контент на сайте, лучше генерировать его на стороне сервера за раз вытягивая данные из текстовых файлов или базы данных. Генерация статических сайтов, которые порадуют гугл и юзера своей скоростью загрузки, помимо этого существенно снижая скриптовую нагрузку на сервер.
Posted in Code, Python | No Comments »
Friday, November 19th, 2010
Как правило, если вы берете VDS или Dedicated сервер, в комплект идет несколько дополнительных IP адресов, обычно 2 или 4, зависит от дата центра. Вы межете без проблем развешивать сайты на разные айпи, управляя записями DNS домена. А как запустить скрипт на не основном ip адресе сервера? Один из вариантов предложил Lorien – использовать прокси сервер – Squid. О том, как установить Squid я писал ранее. Короче говоря часто на одном ипе висит куча скриптов которые дрочат какие-то сервисы время от времени, и чтобы не натыкаться на бан или превышение лимитов API лучше всего распределить нагрузку между доступными ip адресами. Это потребует небольшой модификации скриптов, нужно будет направлять запросы через прокси. “Прозрачно” это можно сделать используя библиотеку socksipy-branch.
Чтобы перенаправлять запросы на другой ип адрес используется следующая хитрая схема : мы направляем запрос на ip:port откуда squid роутит его на айпи используя директиву tcp_outgoing_address.

Allows you to map requests to different outgoing IP addresses based on the username or source address of the user making the request.
Позволяет вам назначать запрос на другие исходящие IP адреса, основываясь на имени или адресе источника откуда юзер сделал запрос.
Осталось только настроить конфиг Squid’а нужным образом, естественно если ипов больше чем 2а лучше всего потратить 5 минут и написать скрипт который будет генерировать нужную последовательность директив :
# Говорим squid слушать нужные порты
# http_port 20000
# http_port 20001
# Создаём ACL правила
# acl p20000 myport 20000
# acl p20001 myport 20001
# С помощью созданных ACL правил выбираем нужный исходящий IP
# tcp_outgoing_address 78.109.20.226 p20000
# tcp_outgoing_address 78.109.20.227 p20001
Взял отсюда. Немного переделал приблизив скрипт к “боевым” условиям. Список айпи берет из файла ips.txt. Начальный порт задаем в start_port.
Внимание, лучше лишний раз проверить, чтобы на ипах ничего не висело. Делается это с помощью команды : netstat -tulnap
start_port = 2000
ips_list = [ item.strip() for item in open("ips.txt", "r").readlines()]
chunks = ([], [], [])
for num, ip in enumerate(ips_list):
port = start_port + num
chunks[0].append('http_port %d' % port)
chunks[1].append('acl p%d myport %d' % (port, port))
chunks[2].append('tcp_outgoing_address %s p%d' % (ip, port))
for group in chunks:
for line in group:
print line
print
print "-------------------------------\n"
Если кто знает более простой способ welcome в комменты. Я задавал это вопрос на freenode #linux (IRC канал), но практичного решения с ходу никто не предложил. Пока что единственный рабочий вариант предложил Lorien.
Posted in Code, Proxy, Python, Server | No Comments »
Thursday, November 18th, 2010
Регулярные выражения (они же регулярки, они же регэкспы) совершили настоящую революцию в обработке текстов, позволяя вести поиск и вставку текста используя так называемые паттерны – описывающие требуемый формат операции. Само по себе описание регекспов достаточно объемно, для повседневных задач можно даже изучить тему вполне поверхностно. Использовать регулярки, крайне удобно и быстро, несмотря на то что по скорости они проигрывают строковым и DOM функциям – тем не менее часто проще написать регулярку чем разрабатывать функцию. Само собой каждый уважающий себя язык программирования имеет реализацию регэкспов и Python не исключение. В качества классического примера :
def parse_proxy(page):
"""Parse proxies from webpage"""
reg = re.compile("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}")
proxy_list = reg.findall(page)
return proxy_list
вытащить все прокси из кода вебстраницы. Простейшие регулярки несколько раз используются в прокси чекере.
Полезные сайты :
http://www.pcre.ru/ – типичные примеры, описание и конструктор который сильно облегчает процесс конструирования регулярных выражений.
http://www.regexlib.com/ – библиотека готовых регулярных выражений, сортировака по разделам. Очень полезный ресурс.
http://www.gskinner.com/RegExr/ – еще один конструктор регулярных выражений. Составь и проверь.
http://regexlib.ru/ – еще одна библиотека регулярок. на русском.

Использование регулярных выражений на Python.
Питон естественно предоставляет инструменты для работы с регулярными выражениям
http://docs.python.org/library/re.html
http://docs.python.org/dev/howto/regex.html – есть неплохой HOWTO
Библиотека регулярных выражений называется – re. Немаловажный момент – для строк с регулярным выражением нужно использовать префикс “r“, чтобы символы \ не преобразовывались в строковые специальные символы вроде \t, \n и т.д.
Использовать так :
match = re.search(ur"text", u"sometext and text")
print "Re.seach : ", match.group()
exp = re.compile(ur"text")
match = re.finditer(exp, u"sometext and text")
print "Re.finditer : "
for item in match:
print item.group(), item.span()
re.compile – компилирует регулярное выражение в regular expression object который может быть использован методами match() и search() и т.д. К выражению могут быть добавлены специальные флаги-модификаторы (вроде re.IGNORECASE).
Важно помнить что функции вычисляющие регулярное выражение возвращают объект у которого есть свойства и метода.
group() возвращеает строку удовлетворяющую условию регэкспа.
start() Возвращает начальную позицию совпадения
end() Возвращает конечную позицию совпадения
span() Возвращает кортеж (tuple) – (start, end) в котором заданы позиции совпадения.
Следующий пример возвращает все числа из произвольной строки :
p = re.compile('\d+')
result = p.findall('1 2 3 yolochka gori, 23 yellow popugais')
print result
Целесообразность применения регулярных выражений.
Однако не стоит чересчур увлекаться регулярными выражениями (об этом говорят даже в официальном туториале python’а), зачастую бывает проще воспользоваться строковыми функциями – они быстрее (т.к. реализованы в виде небольших, хорошо оптимизированных C циклов). В моей практике бывали случаи когда самый простой путь был – через DOM вырезать нужный кусок и уже там работать регулярками (парсинг google images, например). Представим что вам нужно заменить слово “милиция” на “полиция”, для этого вполне подойдет функция re.sub, однако в РАЗЫ проще использовать replace() :
text = "Наша милиция нас бережет."
result = text.replace("милиция", "полиция")
print result
Разница между match() и search()
Функция match() только проверяет – есть ли совпадения с начала строки, в то время как search() будет сканировать на совпадения с паттерном всю строку целиком.
print(re.match('super', 'superstition').span())
print(re.match('super', 'insuperable'))
print
print(re.search('super', 'superstition').span())
print(re.search('super', 'insuperable').span())
(0, 5)
None
(0, 5)
(2, 7)
Удачных вам регулярных выражений. Стоит уделить изучению материалов по регекспам хотя бы несколько часов, поверьте ваши вложения времени с лихвой окупятся в будущем.
Posted in Code, Notes, Python | No Comments »
Wednesday, November 17th, 2010
Эти функции позволяют вам быстро делать некоторые вещи, для которых в старом добром паскале приходилось писать лишний код. Все ниженаписанное относится к так называемому функциональному программированию, луркайте подробности.
Функции map, zip и lambda в примерах.
Простая задача есть список a = [1, 2] и список b = [3, 4] одинаковой длины и нужно слить их парами. Проще простого – используя функцию zip :
a = [1,2]
b = [3,4]
print zip(a,b)
[(1, 3), (2, 4)]
или тройками :
a = [1,2]
b = [3,4]
c = [5,6]
print zip(a,b,c)
[(1, 3, 5), (2, 4, 6)]
или в более общем виде
list = [a, b, c]
print zip(*list)
[(1, 3, 5), (2, 4, 6)]
Звездочка * перед list как-бы говорит что передается список аргументов, т.е. Действовать эквивалентно тому как если бы передали a, b, c т.е. Можно даже так print zip(*[a, b, c]) результат не изменится.
Далее функция – map. Случаются ситуации, когда внезапно нужно применить какую-либо функцию к каждому элементу списка.
Нуб напишет так :
def f(x):
return x*x
nums = [1, 2, 3]
results = []
for num in nums:
results.append(f(num))
print results
Немного поизучавший мануалы так :
def f(x):
return x*x
print [ f(num) for num in nums ]
Программист сделает проще :
def f(x):
return x*x
print map(f, nums)
А вот тру-мэдскиллз кодер сделает следующим образом :
print map(lambda x: x*x, nums)
Последняя запись являет собой пример наиболее грамотного подхода. Дело в том, что когда человек пишет код как стихи в порыве вдохновения, крайне роляет скорость написания (отсюда растут корни трепетной любви многих питон кодеров к vim и emacs), а сильная сторона питона как раз в размере генерируемого кода – он очень компактный. Написать одну строчку естественно быстрее чем 7, да и изучать короткий код проще, однако написание подобного кода требует определенного навыка. Другая сторона медали – иногда про-devs очень любят писать в одну строчку целые последовательности достаточно сложных действий, да так что очень трудно понять что там происходит и что получается в конечном итоге.
Из примера понятно, что map применяет какую-либо функцию к списку и возвращает результат опять же в виде списка. Вы можете передать несколько списков, тогда функция (идущая первым параметром) должна принимать несколько аргументов (по количеству списков переданных в map) .
def f(x, y):
return x*y
a = [1,3,4]
b = [3,4,5]
print map(f, a, b)
[3, 12, 20]
Жир, правда?
Однако если списки разной длины, т.е. Один короче другого, то он будет дополнен значениями None до нужной длины. Если убрать из списка b последнее значение – пример не будет работать, т.к. В функции f произойдет попытка умножения числа на None, а в питоне строгая типизация, что кстати выгодно отличает его от php, который в подобной ситуации работал бы дальше.
Поэтому если функция f достаточно объемна, неплохо бы проверять передаваемые значения. Например ;
def f(x, y):
if (y == None):
y = 1
return x*y
Если же заместо функции стоит None – то map действует примерно так же как и zip, но если передаваемые списки разной длины в результат будет писаться None – что кстати очень уместно в некоторых моментах.
a = [1,3,4]
b = [3,4]
print map(None, a, b)
[(1, 3), (3, 4), (4, None)]
Теперь про лямбда функции в python. Они используются когда вам необходимо определить функцию, ведь часто (как в предыдущих примерах) функция настолько мала, что определять её отдельно смыла нет (ведь это лишние строчки кода и ухудшение читабельности).
Поэтому функцию можно определить “на месте” f = lambda x: x*x как бы говорит нам – принимает x, возвращает x*x
Так используя стандартные инструменты питона можно записать довольно сложные действия в одну строчку. К примеру функцию :
def f(x, y):
if (y == None):
y = 1
return x*y
можно представить как :
lambda x, y: x * (y if y is not None else 1)
А теперь хорошо бы передавать списки отсортированные по длине – len(a) > (b) – проще простого – воспользуемся функцией sorted :
sorted([a, b], key=lambda x: len(x), reverse=True)
фунция sorted принимает список значений ([a,b] = [[1,2],[2,4,5]]) и сортирует по ключу key – который у нас задан функцией len(x) – возвращающей длину списка, сортируем в порядке убывания (reverse=True)
В конечном итоге вся операция записывается таким образом :
map(lambda x, y: x * (y if y is not None else 1), *sorted([a, b], key=lambda x: len(x), reverse=True))
списки a и b могут быть разной длины и передаваться в каком угодно порядке.
Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям.
Posted in Code, Python | 3 Comments »
Sunday, November 14th, 2010
Задача классическая. Удалить повторы из какого-либо списка. Самый быстрый вариант сделать так :
def uniq(seq):
"""The fastest way to unique list"""
seen = set()
seen_add = seen.add
return [ x for x in seq if x not in seen and not seen_add(x)]
Posted in Code, Python | 3 Comments »
Saturday, November 13th, 2010
Часто встречающаяся задача – получить случайную последовательность, случайной длинны из какого-либо набора данных. Например – 5-10 кейвордов из списка кеев в несколько тысяч, или выбор последовательности действия для бота имитирующего поведение человека. Ну в простейшем варианте – все просто :
import random
data = ['add_friends', 'post_story', 'vote', 'comment']
chain = random.sample(data, 2)
А если хочется задать вероятность наступления события?
import random
def get_random_chain(chain, min_max=[1,1]):
""" Get random chain from list """
items_chain = []
random.seed()
for item, num in chain.iteritems():
items_chain.extend([item] * num)
random.shuffle(items_chain)
chain_len = random.randint(min_max[0], min_max[1])
return random.sample(items_chain, chain_len)
Вот так использовать (исходная последовательность задается в виде словаря key : value – где value вероятность наступления события) :
ACTIONS = {
"post" : 20,
"vote" : 80
}
what_to_do = get_random_chain(ACTIONS, [5,10])
Получить случайную цепочку действий длинной в данном случае от 5 до 10 элементов.
Обратите внимание длинна цепочки может быть сколь угодно длинной и превышать исходную последовательность.
Posted in Code, Python | No Comments »
Saturday, November 13th, 2010
Вам нужен http://www.crummy.com/software/BeautifulSoup/ – отличная штука для работы с html/xml документами, работает даже если xml кривой. Очень часто встречающаяся задача – удалить html тэги из строки.
from BeautifulSoup import BeautifulSoup
''.join(BeautifulSoup(page).findAll(text=True))
Так же можно заюзать уже готовый код от Lorien’а (помните про open source?) – clean.py, не забудьте импортировать в проект так же и htmldata.py
Posted in Code, Python | No Comments »
Saturday, November 13th, 2010
Достаточно модный тренд, вообщем самое время поговорить о мощном движении Open Source и его пользе. Наверняка многие слышали о таких темах как sourceforge.net, code.google.com? Достаточно плотно сидят в выдаче. В чем заключается на данный момент работа программиста? Ведь почти все что нужно так или иначе есть в готовом виде, и нужно лишь протянуть руку чтобы использовать чужие разработки, а не терять время разрабатывая очередной велосипед. Настоящие развалы готового кода практически на все случаи жизни можно найти на социальных сайтах :
А возможно не только найти, но и поучаствовать в допиливании обертки для очередного API который вы можете использовать для построения своих сайтов.
Posted in Code, Python, social networks | 1 Comment »
Wednesday, November 10th, 2010
Часто настроек в приложении может быть дофига и невольно задумываешься о том, чтобы вынести их в отдельный файл – файл настроек. Бывает программисты по инерции начинают писать код который будет считывать и обрабатывать этот файл, и бывает даже строковыми методами. Однако в питоне ничего не мешает нам создать файл вроде settings.py и исполнять его на уровне кода.
Вот к примеру файл settings.py :
import os.path as path
template_dir = path.join(path.dirname(__file__), "templates")
user_record = {
'id' : 1,
'mail' : "xyu@gmail.com",
'pass' : "1234"
}
А вот так его можно вызывать из кода :
import settings
def main():
print settings.template_dir
if __name__ == "__main__":
main()
или так (по модному) :
def main():
mod = __import__("settings")
print getattr(mod, 'template_dir')
if __name__ == "__main__":
main()
Posted in Python | No Comments »