26.12.09


Каплями снова небо плачет
Почему не сложилось иначе?
Почему на дворе не лето?
И зачем же я помню про лето?

Снова эти холодные игры
Почему я сейчас без тебя?
Почему между нами так много?
И зачем же я помню тебя?

В попытках достать до смысла


В попытках достать до смысла
А вдруг этот мир живой?
Умом ли живое постигнуть?
Пади на колени и вой

К пределу глаза закатывая
Гортани рви сухожилия
Кто знает, а может силой
Твоё обернётся бессилие

Как знать, чем наполнит Вечность
Умом забытое логово
Быть может ему в этом мире
Судьба отыскать дорогу

Свою. Что и ты когда-то
Смог разглядеть сквозь время
Да только нагрёб ты много
И шагу ступить это бремя

Не даст. Чтож застывшим древом
Пустить в землю гроба корни?
И вечность вернутся в саване
Изгнившего мяса клочья

Неужто намертво челюсти
Вцепились в чужое счастье
В попытках всё заарканить
Постигнув умом Настоящее?

25.12.09

Большой список строк


Стоит задача построчных манипуляций с большим файлом. Пробовал разные подходы. Оказалось, что попытки работы напрямую с файлом упираются в кэш файловой системы. Все эти tell-ы и seek-и выполняются быстро только если файл целиком влазит в этот самый кэш.

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

Первое, что по этому поводу выяснилось, стандартный list питона кушает памяти в 2 раза больше, чем содержит данных. Я тестил на строчках требуемой длины (27 байт).

Вообще, мне хотелось бы даже сжать данные. Потому попробовал я записать bz2 файлик в tmpfs. Это ведь тоже работа с памятью. А потом считывать из него нужные строчки, там тоже можно сики делать. Это оказалось просто невероятно медленно.

Потом посмотрел в сторону mmap.  Даже если просто в память через неё писать, работает раза в два дольше, чем с закэшированным файлом. Либо кто-то из нас тормоз, либо одно из двух :)

Остановился на array. То, что получилось работает на скорости сравнимой с стандартным list-ом. Вот оно, собственно:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import array


def main():
    # тестим
    import random

    a = StringList()
    a.append(u'Утол')
    a.append(u'Мар')
    print len(a)
    print a[1].encode('utf-8')
    print random.choice(a).encode('utf-8')


class StringList(object):
    '''
    Экономичный к памяти список строк
    '''
    def __init__(self, encoding='cp1251'):
        self.data = array.array('c')
        self.index = array.array('L')
        self.encoding = encoding

    def append(self, s):
        self.index.append(len(self.data))
        self.data.fromstring(s.encode(self.encoding))

    def __getitem__(self, id):
        start = self.index[id]
        try:
            end = self.index[id + 1]
        except IndexError:
            end = len(self.data)
        return self.data[start:end].tostring().decode(self.encoding)

    def __len__(self):
        return len(self.index)


if __name__ == "__main__":
    main()

23.12.09

Найдя причины пиздецов
Ты радуешься очень сильно
Порою, радость так обильна
Что привлекает пиздецов

22.12.09

Python + YAML

Зачем это, собственно?

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

Конечно, хочется парсить автоматом. Да ещё, чтобы сам конфиг был читабельным. Варианты:

  • XML: избыточный синтаксис, неудобный парсинг
  • INI: ConfigParser - это просто пиздец, наследие винды, не иначе
  • CSV: удобно, но требует специального редактора
  • JSON: почти хорошо, но кое-чего нет и синтаксис немного избыточен
  • YAML: наш победитель :)

По сути yaml - это расширение json. Или json подмножество yaml :)

Как это работает

Для начала ставим пакет. Я подобные простенькие вещи ставлю глобально. Например, так:

sudo aptitude install python-yaml

А дальше всё стандартно:

>>> import yaml
>>> yaml.load('[1, a, false]')  # парсим yaml-строку
[1, 'a', False]
>>> yaml.dump([2, 'b', None])  # дампим в yaml-строку
'[2, b, null]\n'

Можно парсить данные прямо из файла:

cfg = yaml.load(open('test.yaml'))

Например, из такого файла test.yaml:

# Простые типы, а это камент, кстати :)
word: Строка    # без кавычек удобно
num: 2009       # число
none: null      # None
bool: true      # Bool

# Список одной строкой
lst1: [буквы, 123, null]

# Многострочный вариант списка
lst2:
    - буквы   # тут возможны каменты
    # и тут тоже
    - 123
    - null

# Словарь в одну строку
dic1: {word : буквы, num : 123, none : null}

# Многострочный словарь
dic2:
    word: буквы
    num: 123
    none: null

# Длинная строка, переносы удаляются
big_str1: >
    Тру
    лю
    лю

# Длинная строка, переносы сохраняются
big_str2: |
    Тра
    ля
    ля

# Вложенности
langs:
    - XML:
        читабельность: никакая
        использование: мерзкие парсеры
        назначение: обмен данными
    - YAML:
        читабельность: высокая
        использование: святая простота
        назначение: конфиги

Получится такая структура данных:

{
    'word' : u'Строка',
    'num'  : 2009,
    'none' : None,
    'bool' : True,

    'lst1' : [u'Строка', 123, None],
    'lst2' : [u'Строка', 123, None],

    'dic1' : {'none' : None, 'num': 123, 'word' : u'буквы'},
    'dic2' : {'none' : None, 'num': 123, 'word' : u'буквы'},

    'big_str1' : u'Тра ля ля\n',
    'big_str2' : u'Тру\nля\nля\n',

    'langs': {
        'XML': {
            u'читабельность' : u'никакая',
            u'использование' : u'мерзкие парсеры',
            u'назначение'    : u'обмен данными',
        },
        'YAML': {
            u'читабельность' : u'высокая',
            u'использование' : u'святая простота',
            u'назначение'    : u'конфиги',
        }
    },
}

Вот, собственно, и всё чем сам пользуюсь. Но это не все возможности yaml, и желающие изъебнуться и здесь найдут чем позабавиться :)

21.12.09

Ось жизни

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


Про равновесие

Наверное, всем в голову приходила идея равновесия. Если совсем грубо, хорошего в жизни столько же, сколько и плохого. Очень простая и логичная идея. Ум очень любит подобные идеи и крепко цепляется за них. А для этой идеи куча подтверждений на поверхности валяется. Сегодня выпил(выкурил, съел) что-то энергетическое - завтра как минимум слабость, или откровенно хуёво. Сегодня отдохнул, завтра энергии больше.

Такая вот демотивирующая идея. Какой смысл напрягаться в поисках хорошего, если потом будет откат? Или какой смысл истязать себя аскезами, если последующий кайф лишь уравновесит страдания?


Про ноль

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


Про ось

Итак, этот самый ноль вовсе не абсолютен. Он меняется в течении жизни. Для волн "хорошо-плохо" изменение нуля является осью.

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

Вверх относительно чего, спросит математик? Относительно отношения за некоторый период прошлого, думаю. Дело в том, что психика более инертна по сравнению с умом. Ты можешь изменить отношение на противоположное, но подсознательный кайф будет идти в прошлых координатах какое-то время. Он может гаситься осознанным отношением, но он будет.

Обычно же, отношение резко не меняется. Поэтому, я просто буду говорить: вверх и вниз.

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


Про отношение

Дальше я собираюсь использовать термин "Отношение". Под Отношением я буду понимать сумму отношение + действия. На мой взгляд есть только Отношение. На физический уровень оно отражается как действие, а на ментальный как отношение.

Я не представляю, как можно изменить отношение не меняя действий. Разум не поверит в такой фокус и не даст по настоящему измениться отношению.


Управление осью жизни

Непродолжительные эксперименты показывают, что направление оси регулируется Отношением. И оно инертно. Т.е. при изменении Отношения, ось _постепенно_ меняет направление.

Отследить это можно, если придерживаться определённого отношения некоторое время. Делать это мешают локальные волны. Разум говорит: о, неудача - значит действия неправильные, давай менять. Но это локальная волна. Сколько раз я попадался в эту ловушку. Я менял отношение и этот локальный спад оборачивался глобальным.


Картинка

Картинка, иллюстрирующая изменение оси на фоне локальных волн при поддержании неизменного отношения. Это реальная статистика отражающая успешность одного проекта.


20.12.09

[django] Как поиметь юзера везде

Часто текущего юзера хочется иметь там, где его по умолчанию нету. Например, в формах. Для этого нужно засунуть этого юзера в тред-локалс, а потом оттуда доставать в нужном месте.

Я уже давно стырил откуда-то такой вот код для этого самого всовывания/высовывания:

# -*- coding: utf-8 -*-
try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()

def set_current_user(user):
    setattr(_thread_locals, 'user', user)

def get_current_user():
    return getattr(_thread_locals, 'user', None)


Положим этот код, например в common.user, тогда прослойка для засовывания будет такой:

from common.user import set_current_user

class CurrentUserMiddleware(object):
    def process_request(self, request):
        set_current_user(getattr(request, 'user', None))

Вот и всё. Теперь в любом месте имеем текущего юзера:

from common.user import get_current_user

user = get_current_user()
...

19.12.09

Запасные варианты

Пофиксил очередной баг в сознании.

Вводная. Очевидно, что мысли влияют на мир. Споры ведутся о том непосредственное ли это влияние или опосредованное. Я не знаю ни одного сторонника первого подхода, непосредственно материализующего предметы. И в то же время вижу страдания сторонников второго, в процессе нахождения всё новых и новых путей этого самого влияния. Всякие там феромоны :)

Поэтому, я забил. Бесполезный спор. Если знаешь путь влияния, им можно надёжно пользоваться, это практично. Если не знаешь, но очень хочется результатов, идея о непосредственном влиянии даст силы попытаться. И иногда попытки срабатывают. Не важно было ли влияние через ещё не известные пути, или непосредственное. Важно то, что идея непосредственности помогла достичь результата. Она тоже практична.

Не понял, зачем отвлёкся. Итак, влияние есть. Теперь, про баг сознания. Очевидно, что материальные предметы вызывают определённые мысли. А мысли в свою очередь вызывают определённые изменения. Такой пример: я замечаю повышение активности отморозков на улице. Естественное желание - купить наган. Но наган постоянно будет напоминать мне о том, зачем он куплен и таким образом притягивать не интересную мне ситуацию. Раньше в принятии решения участвовали две переменные: вероятность того, что вещь потребуется (-) ненужные мысли, которые она вызывает.

Чуть подробнее. Раньше я решал однозначно: если конкретной причины покупать нет - не покупаю. Конкретная причина - это когда я уже попал в неприятную ситуацию и уже вижу пути её развития. Рост преступности - причина абстрактная. Наезды на кого-нибудь из близких - конкретная. Именно такое поведение мне казалось оптимальным с точки зрения влияния мыслей. Но при этом было подсознательное чувство недопонимания.

Так вот, происходило примерно следующее. Я не покупаю наган. И этот наган не вызывает ненужных мыслей. Однако, каждый раз выходя на улицу, эти мысли вызывают отморозки. И я занимаюсь тем, что фильтрую мысли. Чтобы бороться нужно помнить о том, с чем борешься. Т.е. в некотором объёме эти мысли должны-таки присутствовать для продолжения борьбы.

Итак, три несовершенства налицо:
1. негативные мысли всё же присутствуют
2. постоянно тратятся силы на поддержание их на низком уровне
3. снижается восприятие настоящего, как следствие п.2

Так вот, в своих рассуждениях я не учитывал влияние нагана как "запасного варианта". Помимо полезности в определённой ситуации, он так же успокаивает разум. Если в кармане наган, я спокоен естественным образом. Я знаю, если неприятная ситуация сложится, выход есть. Разум больше не мечется в попытках придумать этот самый выход. Он не засоряет мою голову мыслями п.1, при этом не нужен п.2 и естественно исчезает п.3.

Ну да, я утрирую, конечно. Правильнее сказать "засоряет меньше", насколько уж он верит в запасной вариант. А верит тем больше, чем вариант рациональнее.

Т.е. в вопросе покупать или не покупать наган я теперь учитываю его влияния как "запасного варианта". Итого: насколько он может пригодиться физически (+) насколько успокоит как запасной вариант (-) насколько сам будет вызывать ненужные мысли.

15.12.09

Эмуляция key-value хранилища в django orm

Это может пригодиться в нескольких случаях. Например, при разработки проекта который может в будущем поиметь нагрузку. Чтобы на этапе разработки всем участникам не возиться с установкой кв-бд можно использовать эту заглушку. При этом структура проекта будет изначально строиться соответственно и заменой пары строк вы подключите реальное key-value хранилище.

Ещё один вариант использования - хранение настроек. Допустим заранее не известно, сколько их будет и какие. Вот, используя эту штукенцию можно избежать постоянного перекраивания модели.


class KV(models.Model):
key = models.CharField(u'Key', max_length=50, unique=True)
val = PickledObjectField(u'Value')

@classmethod
def get(cls, key, default=None):
try:
return cls.objects.get(key=key).val
except cls.DoesNotExist:
return default

@classmethod
def put(cls, key, val):
obj, new = cls.objects.get_or_create(key=key)
obj.val = val
obj.save()

@classmethod
def rm(cls, key):
try:
cls.objects.get(key=key).delete()
except cls.DoesNotExist:
pass



Работает, соответственно, так:


KV.put('updated', datetime.now())
print KV.get('updated')
KV.rm('updated')


А dict-style интерфейс я так и не написал. Пока думал как лучше сделать, текущую задачу уже решил :)

Django ORM без Джанги

Я так и не смог себя заставить изучить Алхимию. Не лезет в голову то, что разум трактует как избыточное. А использование Django-orm в не веб проектах раздражало. Пишешь какой-нибудь парсер приходится захламлять папку целиковой джанга-структурой.

Так вот, наконец-то я выделил время и разобрался-таки, как засунуть всю конфигурацию django orm в один файлик. Делюсь сей радостью :)

Всего один файлик models.py:


#!/usr/bin/python
# -*- coding: utf-8 -*-

from django.conf import settings
settings.configure(
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': 'db.sqlite',
        }
    }
)
from django.db import models


class Person(models.Model):
    nick = models.CharField(max_length=100, unique=True)
    email = models.EmailField(max_length=100, unique=True)

    def __unicode__(self):
        return self.nick

    class Meta:
        app_label = ''


def create_table(cls):
    from django.db import connection
    from django.core.management.color import no_style
    
    sql, references = connection.creation.sql_create_model(cls, no_style())
    cursor = connection.cursor()
    for q in sql:
        try:
            cursor.execute(q)
        except:
            pass
    

def main():
    create_table(Person)


if __name__ == "__main__":
    main()



Для создания таблиц просто запускайте этот файлик. Ну а использовать как обычно

from models import Person

Person.objects.....

TDS

Недавно вернулся в доры :) Пошёл трафик, писал тдс-ку. Она поумнее аналогов, например, биды кеев умеет мнговенно определять с незначительной погрешностью. Так вот, дошли руки до анализа уникальности. Задумался над структурой, кв-бд в голову полезли всякие.

Стоп, думаю, надо отвлечься, в ванной поваляться, чувствую есть решение проще. И оно, действительно, пришло. Куки. Прямо в куках и храню историю посещении тдс-ки. Когда и куда отправлял сёрфера.

Решение помимо лёгкости реализации и устойчивости к нагрузкам может и на конверте сказаться в лучшую сторону. В случае всевозможных cpa и шопов, везде, где платят процент в той или иной форме. В таких случаях по ипу вы можете отсеять реальный уник, а это потенциальный покупатель. А если продавать траф, то конечно лучше по ипам уникализировать, а то как неуник засчитают частично.

Т.е. я назвал бы такой способ уникализации более точным. Но использовать эту точность можно только самому, т.к. доказать её невозможно.

Tokyo Cabinet

Это такая key-value бд, кто не знает. Возможно, самая быстрая из имеющихся. Я до этого юзал gdbm, потому и сравнивал только с оной. Так вот, tc по всем параметрам её превосходит. И размер файла меньше, и скорость больше. И ещё приятная мелочь, в gdbm len(db) первый раз тратил время. Т.е. она не хранит количество записей, а пересчитывает каждый раз. В tc в этом смысле всё отлично.

Ну и ещё плюшки, которые пока не юзал. Есть серверный вариант. Кроме индекса по ключу есть бТри индексы, некая симпл-дб и поля фиксированной длины, последние должны быть мега-быстрыми на изменение.

Ещё она может работать с таблицами в памяти, видел сравнение с мемКешд, чуточку уступает.

Ссылки:
- сам кабинет
- питон-обёртка которую юзаю. В ней, кстати не всё есть и это может оказаться не кстати. Например, тех же фиксед-лен-филдов нету. Но она не единственная.
- оодб на её основе написанная на питоне. Код приятный. Но под 2.6 к сожалению. В общем, только взял на заметку пока.

Жизнь рождает порядок, но порядок не рождает жизни

"Жизнь рождает порядок, но порядок не рождает жизни" - некоторое время назад прочитал и всплывает в голове регулярно. Уж сколько раз я пытался сделать что-то идеально. Тужился, тужился и вытужиива херь мертворожденную. А сделанное спонтанно живёт себе, само-структурируется со временем.

Нет, не хочу я абсолютизировать. Конечно, бывает, и потуги проектирования приносят хороший результат. Но всё же, проявления озвученной мысли я вижу чаще. И ещё забавно, все поисковики обыскал, не могу найти, где прочитал это. Приснилось, что ли :)

Из пизды вприпрыг бежал
Чтоб в могилке полежать
Больше силится сожрать
Но из жопы вылезает
А потом опять бежал
Но уже не убежать
Это выглядит смешно
Только он ещё не знает