# тут у нас импорты import itertools as it import more_itertools as mit import functools as ft from random import randrange, choice # понадобятся для примеров # этим будут выводиться результаты экспериментов def p(iterable, upto=20): """Выводит на экран до @upto первых элементов итератора""" print list( it.islice(iterable, upto) if upto else iterable) # генератор тестовых данных def generate(min_len=3, max_len=10): """Возвращает итератор бесконечному списку случайных строк состоящих из символов [0-9a-f] и имеющих длину @min_len..@max_len""" rng = range(min_len, max_len + 1) while True: yield ''.join( choice('abcdef0123456789') for _ in xrange(randrange(min_len, max_len + 1))) # проверим, как это всё работает p(generate(), 5) # import functools as ft # c partial всё просто def repeat(s, n): return s * (n + 1) p( map( ft.partial(repeat, "*"), # тут мы применили repeat только к первому параметру (частично применили) range(5))) # использование wraps КРАЙНЕ рекомендуется при написании декораторов def printer(fn): @ft.wraps(fn) # wraps копирует метаданные(имя, модуль, docstring) исходной функции в обёртку def inner(*args, **kwargs): res = fn(*args, **kwargs) print "Result -> %s" % res return res return inner @printer def f(x,y): """ Очень важная функция! """ return x + y f(10, 11) help(f) # метаданные остались на месте! @ft.total_ordering class Color(object): """Цвет радуги""" RED, ORANGE, YELLOW, GREEN, BLUE, NAVY_BLUE, PURPLE = _values = list(enumerate( 'Красный Оранжевый Желтый Зеленый Голубой Синий Фиолетовый'.split() )) def __init__(self, value): assert value in self._values self._value_idx, self._value_name = value def __repr__(self): return self._value_name # для полного набора операций сравнения нам достаточно определить только "==" и "<" # остальные операторы на выведет total_ordering def __eq__(self, other): return isinstance(other, self.__class__) and (self._value_idx == other._value_idx) def __lt__(self, other): return isinstance(other, self.__class__) and (self._value_idx < other._value_idx) # получаем экземпляры red, orange, yellow, green, blue, navy, purple = map( lambda x: Color(getattr(Color, x)), ['RED', 'ORANGE', 'YELLOW', 'GREEN', 'BLUE', 'NAVY_BLUE', 'PURPLE']) # тестируем if ( red < orange < green < purple > blue >= blue and yellow == Color(Color.YELLOW) # экземпляры разные, но суть одна and blue != navy ): print "Всё хорошо! (пока)" print sorted([blue, red, Color(Color.ORANGE), purple, green, yellow, red, navy]) # import itertools as it # всё как обычно, только лениво p( it.imap( lambda (n, s): s * n, it.ifilter( lambda (n, s): n > 0, it.izip( [-5, 0, 3, 7, -2, -10, 0, 2, 1], "abcdefghijklmnopqrstuvwxyz")))) def fn(*args): fmt, data = args[0], args[1:] return '%r\t%% %r\t-> %s' % (fmt, data, fmt % data) print "--- (i)map ---" for s in it.imap( fn, ['%08d', '%2.3f'], # два (в данном случае) [100142, 3.14159] # "столбца" параметров ): print s print print "--- starmap ---" for s in it.starmap( fn, [ # один(!) список наборов параметров ('%08d', 100142), ('%d/%d', 3, 14), ('#%02X%02X%02X', 255, 127, 15), # наборы разной длины! ] ): print s p( it.count(10, 5) ) p( it.chain(xrange(3), "asdasdsd") ) p( it.cycle("abc") ) p( it.repeat(42) ) p( it.combinations("ADTF", 2) ) p( it.product([1,2,3], "abc") ) # разряженный массив smile = set([(1, 1), (3, 1), (0, 3), (4, 3), (1, 4), (2, 4), (3, 4)]) def render(data, width, height): return '\n'.join( it.imap(''.join, ( ([' ', '*'][(x, y) in data] for x in xrange(width)) for y in xrange(height)))) print render(smile, 5, 5) # подсчет кол-ва точек в области points_in_area = lambda data, (x0, y0), (x1, y1): sum( (p in data) for p in it.product( xrange(x0, x1 + 1), xrange(y0, y1 + 1))) print print "%s точек образуют \"рот\" смайлика" % points_in_area(smile, (0, 2), (4, 4)) p(it.islice(xrange(100), 5, 15, 4)) gt_0 = lambda x: x < 0 p(it.takewhile(gt_0, xrange(-10, 10))) p(it.dropwhile(gt_0, xrange(-10, 10))) p( it.compress( it.count(), it.cycle([1, 0, 1, 0, 0]))) # выборка по паттерну def frame(iterable, size=2): """Скользящий буфер размера @size""" res = [] for i in xrange(size): i, iterable = it.tee(iterable) res.append(i) iterable.next() return it.izip(*res) def sliding_avg(source, buf_len): """Сглаживание данных из @source усреднением по буферу размера @buf_len""" avg = lambda x: float(sum(x)) / buf_len return it.imap(avg, frame(source, buf_len)) p( sliding_avg( # бесконечный генератор случайных чисел в диапазоне [0,10) it.imap(lambda _: randrange(0, 10), it.count()), buf_len=20, ) ) data = sorted( it.islice( generate(min_len=1), 100), key=len) dict(it.imap( lambda (x, y): (x, list(y)), it.groupby(data, len))) import more_itertools as mit p( mit.chunked(xrange(10), 3) ) p( mit.grouper(3, xrange(10), None) ) print ''.join( mit.collate( sorted("ada78huh18jkashd"), sorted("86daseqfr3657") ) ) p( mit.flatten( [[1,2,3,4,5], [10, 20, 30], [400, 500]])) p( it.imap( lambda x: x[0], mit.iterate( lambda (a, b): (b, a + b), (1, 1)))) p( mit.repeatfunc( randrange, None, 1, 7)) def pairwise(source): peekable_source = mit.peekable(source) for i in peekable_source: yield (i, peekable_source.peek()) p( pairwise(xrange(10)) ) print mit.first("abc", None) print mit.first("", None) p( mit.take(3, it.count(1000))) print mit.nth("abcdefg", 5) data = (x for x in xrange(10)) # неперезапускаемый итератор mit.consume(data, 5) # слили 5 элементов в эфир p(data) p( mit.take(10, mit.padnone("abc")) ) print mit.ilen(xrange(10)) # проход по менеджеру контекста, поддерживающему протокол итерации, # с последующим закрытием (менеджера) # код закомментирован, т.к. зацикливается по причине бесконечности исходного файла :) # p( # it.imap( # int, # mit.with_iter( # open('/dev/random'))) chunked = lambda iterable, size: ( it.takewhile(bool, it.imap(list, mit.repeatfunc(it.islice, None, iter(iterable), size))) ) print list(chunked(xrange(10), 3)) do = lambda x, *tups: reduce(lambda x, tup: tup[0](x, *tup[1:]), tups, x) do_last = lambda x, *tups: reduce(lambda x, tup: tup[0](*(tup[1:] + (x,))), tups, x) # пример использования print do( " hello, world ? ", (str.strip,), (str.split,), (' '.join,), (str.capitalize,), (str.replace,'?','!') ) # и ещё один print do( generate(), # случайные строки (it.islice, 100), # в кол-ве 100 штук (lambda x: sorted(x, key=len),), # сортируем по длине (тут, увы, требуется keyword-аргумент, поэтому lambda) (it.groupby, len), # группируем по длине же (dict,), # превращаем в словарь (dict.keys,), # возвращаем его ключи (set,) # в виде множества ), "<- множество длин случайных строк" chunked = lambda iterable, size: do_last( iterable, # исходные данные (iter,), # принудительно превращаем в неперезапускаемый итератор (lambda x: mit.repeatfunc(it.islice, None, x, 3),), # раз за разом применяем islice, (it.imap, list), # форсируя ленивые слайсы превращением их в списки, (it.takewhile, bool), # продолжаем обработку, пока не попадётся первый пустой список ) print list(chunked(xrange(10), 3))