Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пишем прекрасный, идиоматический Python

Anna | 16.06.2014 | нет комментариев

Изредка трудно обнаружить в Сети положительные, а основное актуальные «best practices» для языка. Документация, безусловно же, содержит всю нужную информацию, но отсеять надобную вещь в абзацах подробного (на то она и документация) изложения, достаточно трудно. Но незадолго мне улыбнулся поиск Google, и я наткнулся на дюже пригодные «паттерны» языка Python от одного из core разработчиков — Raymond Hettinger.

Примечание: Все рекомендации даны в нескольких вариантах: вначале идут самые «дрянные» варианты, а дальше предлагается лучшая альтернатива. Актуально для версии языка 2.7, различия для версии 3.3 читайте в примечаниях к определенному «паттерну».

Цикл по массиву из чисел

Нехорошо: изредка пишут так.

for i in [0, 1, 2, 3, 4, 5]:
    print i**2

Отлично: наилучший, с генератором. Но в 32 битной системе список из миллиона чисел будет занимать ~ 32 mb памяти.

for i in range(6):
    print i**2

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

for i in xrange(6):
    print i**2

Примечание: В версии Python 3.3 xrange теснее в ядре и называеться легко range.

Цикл по списку

Нехорошо: Зачастую прежние С программисты пишут так.

colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
    print colors[i]

Отлично: наилучший вариант.

colors = ['red', 'green', 'blue', 'yellow']
for color in colors:
    print color

Но если необходимо пройти по списку задом на перед?

Нехорошо: вновь, прошло из C дает о себе знать:

colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
    print colors[i]

Отлично: но в Python пишут вот так:

colors = ['red', 'green', 'blue', 'yellow']
for color in reversed(colors):
    print color
Цикл по списку с индексами

Нехорошо тоже что и выше.

colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
    print i, '-->', colors[i]

Отлично: больше изящный вариант:

colors = ['red', 'green', 'blue', 'yellow']
for i, color in enumerate(colors):
    print i, '-->', color
Цикл по двум спискам

Нехорошо тоже что и выше.

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
n = min(len(names), len(colors))
for i in range(n):
    print names[i], '-->', colors[i]

Отлично: делаем с 2-х списков один список кортежей. Задача в том что zip использует огромнее памяти чем 1-й вариант.

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
for name, color in zip(names, colors):
    print name, '-->', color

Отменно: в различии от zipizip использует кэширование, что помогает значительно сэкономить память.

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue', 'yellow']
for name, color in izip(names, colors):
    print name, '-->', color

Примечание: В версии Python 3.3 izip вписан в ядро и называеться легко zip.

Сортировка списка по алгорифму

Нехорошо: применяя функцию для сопоставления.

colors = ['red', 'green', 'blue', 'yellow']

def compare_length(c1, c2):
    if len(c1) < len(c2): return -1
    if len(c1) > len(c2): return 1
    return 0

print sorted(colors, cmp=compare_length)

Отлично: применяя сортировку по ключу. Использует гораздо поменьше памяти.

colors = ['red', 'green', 'blue', 'yellow']

print sorted(colors, key=len)

Примечание: Способ cmp убран с ядра Python 3.x.

Цикл по ключам словаря

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

for k in d:
    print k

Для метаморфозы словаря в цикле используйте цикл по ключам (Пример: удаление всех ключей начинающихся с R):

for k in d.keys():
    if k.startswith('R'):
        del d[k]

В этом случае d.keys() делает копию ключей словаря, что разрешает нам вольно трудиться с подлинной конструкцией.

Цикл по ключам и значением словаря

Нехорошо: цикл по ключам и возвращение значение по последним. Неторопливый метод:

for k in d:
    print k, '-->', d[k]

Отлично: стремительней делать цикл по значениях:

for k, v in d.items():
    print k, '-->', v

Отменно: Но само наилучший и стремительный метод это применять итератор:

for k, v in d.iteritems():
    print k, '-->', v
Соединение 2-х списков в один словарь

Дюже стремительный способ, применяется только один кортеж для генерации словаря.

names = ['raymond', 'rachel', 'matthew']
colors = ['red', 'green', 'blue']

d = dict(izip(names, colors))
# d будет иметь следующее значение: 
# {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}
Подсчет элементов в словаре

Нехорошо: обыкновенный метод:

colors = ['red', 'green', 'red', 'blue', 'green', 'red']
d = {}

for color in colors:
    if color not in d:
        d[color] = 0
    d[color]  = 1

#{'blue': 1, 'green': 2, 'red': 3}

Отлично: использует функцию get():

colors = ['red', 'green', 'red', 'blue', 'green', 'red']
d = {}

for color in colors:
    d[color] = d.get(color, 0)   1

Отменно: само продвинутый метод это применять defaultdict(). Но вы обязаны знать как он работает.

d = defaultdict(int)
for color in colors:
    d[color]  = 1
Группирование элементов списка

Нехорошо: если необходимо сгруппировать элементы списка по некоторому знаку (в примере — длинна строки) Зачастую применяют такой способ:

names = ['raymond', 'rachel', 'matthew', 'roger', 'betty', 'melissa', 'judith', 'charlie']
d = {}

for name in names:
    key = len(name)
    if key not in d:
        d[key] = []
    d[key].append(name)
{5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew', 'melissa', 'charlie']}

Отлично: но есть метод значительно изящней и стремительней:

d = defaultdict(list)
for name in names:
    key = len(name)
    d[key].append(name)
Результат

На сегодня все. Верю эти банальные, но пригодные примеры помогут кому-то усовершенствовать свой код, как они помогли это сделать мне. Их автором является Raymond Hettinger (@raymondh), Python Core Developer.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB