среда, 26 марта 2014 г.

Внутрь питона

Блуждая по сети нашел несколько неплохих статей о внутреннем устройстве python. Будет полено для тех кто хочет разобраться как устроен и работате python 

Целые числа

Словари

Списки

По мере нахождения новйо информации буду пополнять список

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

Sublime Text 2

В процессе работы у каждого разработчика складывается свое рабочее окружение. Пять капель и смоей стороны. Для работы в питоне я считаю идеальным инструментом - PyCharm, но для написания небольших скриптов использую Sublime Text 2.

Sublime Text 2 - очень популярный редактор с большим функционалом, фишками и огромным количеством дополнительных плагинов для него.
http://www.sublimetext.com/2


Набор плагинов для работы



Package Control
Первое что нужно ставить после установки ST. Он позволяет устанавливать дополнительные плагины из репозитариев.
https://sublime.wbond.net/

SublimeLinter
Этот плагин добавляет поддержку lint в ST
https://github.com/SublimeLinter/SublimeLinter-for-ST2


SublimeCodeIntel
Плагин, добавлюющий в ST «умный autocomplete». Не такой умный как в PyCharm, но это лучше чем ничего.
https://github.com/SublimeCodeIntel/SublimeCodeIntel


AutoPep8
Проверка кода python на соотвествие pep8. Есть возможность автоматического переформатирования кода.
https://github.com/wistful/SublimeAutoPEP8

как работатет 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

среда, 12 марта 2014 г.

Небольшая особенность параметра args в subprocess.Popen

Как известно в subprocess.Popen можно передать args в виде строки и списка. В чем разница? Рассмотрим два небольших примера:

args = 'more "c:\\temp files\\1.txt"'
p1 = subprocess.Popen(args)

args = ['more''"c:\\temp files\\1.txt"']
p2 = subprocess.Popen(args)


По идее разница не большая, попробуем запустить
В первом случае отобразится содержимое файла 1.txt
hello world

Однако во втором случае консоле отобразится предупреждение
Не удается получить доступ к файлу C:\c:\temp

Что пошло не так во втором примере? Давайте более детально посмотрим на реализацию subprocess.Popen.

В конструкторе инициализация атрибутов, далее идет вызов функций _execute_child, делающей основную работу по запуску процессов на MS Windows, вот в ней то и кроется загвоздка. Переходим к реализации _execute_child и видим условие:

if not isinstance(args, types.StringTypes):
    args = list2cmdline(args)
    print('after list2cmdline', args)

То есть, если передаваемые аргументы args не типа string, то вызывается list2cmdline. как раз во втором случае Popen вызывается со списком аргументов.
Вот реализация метода:


def list2cmdline(seq):
    result = []
    needquote = False
    for arg in seq:
        bs_buf = []

        # Add a space to separate this argument from the others
        if result:
            result.append(' ')

        needquote = (" " in arg) or ("\t" in arg) or not arg
        if needquote:
            result.append('"')

        for c in arg:
            if c == '\\':
                # Don't know if we need to double yet.
                bs_buf.append(c)
            elif c == '"':
                # Double backslashes.
                result.append('\\' * len(bs_buf)*2)
                bs_buf = []
                result.append('\\"')
            else:
                # Normal char
                if bs_buf:
                    result.extend(bs_buf)
                    bs_buf = []
                result.append(c)

        # Add remaining backslashes, if any.
        if bs_buf:
            result.extend(bs_buf)

        if needquote:
            result.extend(bs_buf)
            result.append('"')
    return ''.join(result)

Код довольно простой. В цикле происходит перебор членов списка аргументов. Если аргумент содержит пробел или горизонтальную табуляцию или пустую строку, то функция автоматически добавит кавычки в начале и конце строки. Так если передать 'file directory', то на выходе получим '"file directory"', тоже самое произойдет если передать именованный параметр '-p file', то на выходе получим '"-p file"'.

При использовании subprocess.Popen в качестве аргументов нужно передать либо полностью сформировнную строку, либо если передается  список аргументов, в котором встречается директория с составным именем, то заранее использовать объединение по средством кавычек не нужно. 

Более подробно в документации http://docs.python.org/2/library/subprocess.html#converting-argument-sequence


вторник, 11 марта 2014 г.

Небольшие особенности os.path.join

Небольшая оговорка - речь пойдет о join из модуля ntpath, python27.
На практике программист сталкивается с двумя видами путей - абсолютными и относительными. При использовании join натолкнулся на ряд особенностей поведения

>>>os.path.join('c:\\first''e:\\second')
e:\second

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

>>> os.path.join('\\first''\\second')
 \\second 

Как ни странно та же картина будет в следующем случае
>>> os.path.join('c:\\folder''\\dirname')
\\dirname

Что будет если попробовать соединить пути без разделителя
>>> os.path.join('c:''folder')

В этом случае join вернет неожиданную конструкцию
>>>c:folder

Что само по себе не является корректным путем в Windows



четверг, 6 марта 2014 г.

sys.modules

Иногда встречаются ситуации, когда необходимо обратиться к объекту в текущем модуле, зная толь его имя. Делается это следующим образом
import sys
thismodule = sys.modules[__name__]
setattr(thismodele, obj_name, value)


sys.modules – обычный словарь, содержащий список загруженных модулей. Более подробно здесь