пятница, 21 марта 2014 г.

как работатет odict

Как известно стандартный словарь питона не поддерживает сортировку ключей. Данная проблема просто решается небольшим модулем odict от небезызвестного Армина Ронахера - автора Flask, Jinja2, одного из основателей pocoo (www.pocoo.org). Скачать пакет можно здесь https://pypi.python.org/pypi/odict/1.5.1

Пробуем

>>> odict.odict((('first', 1), ('second', 2))).items()
[('first', 1), ('second', 2)]
>>> odict.odict((('first', 1), ('second', 2))).as_dict()
{'second': 2, 'first': 1}

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

Код Армина всегда отличался элегантностью и простотой, поэтому я не удержался чтобы заглянуть по капот odict.
odict - обвертка над стандартным словарем с небольшой костомизацией. 
Вся "магия" заключена в двух следующих методах:
def __setitem__(self, key, val):
    dict_impl = self._dict_impl() //здесь возвращается стандартный словарь
    try:
        dict_impl.__getitem__(self, key)[1] = val
    except KeyError:
        new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
        dict_impl.__setitem__(self, key, new)
        if dict_impl.__getattribute__(self, 'lt') == _nil:
            dict_impl.__setattr__(self, 'lh', key)
        else:
            dict_impl.__getitem__(
                self, dict_impl.__getattribute__(self, 'lt'))[2] = key
        dict_impl.__setattr__(self, 'lt', key)


Первоначально формируется значение ключа - список, содержащий три значения - предыдущий ключ словаря, значение текущего ключа, ключ следующего значения. Искушенный читатель уже догадался - это классический double linked list.
lh и lt - простые свойства, хранящие ключ головного и последнего элемента


def iteritems(self):
    dict_impl = self._dict_impl()
    curr_key = dict_impl.__getattribute__(self, 'lh')
    while curr_key != _nil:
        _, val, next_key = dict_impl.__getitem__(self, curr_key)
        yield curr_key, val
        curr_key = next_key

Генератор, возвращающий атрибуты в том порядке, в котором они поступили.

PS Код Армин как всегда элегантен и прост. Более подробно об odict можно почитать на github https://github.com/bluedynamics/odict

Комментариев нет:

Отправить комментарий