36
Красота и изящность стандартной библиотеки Python Примеры использования Макс Усачев [email protected]

Красота и изящность стандартной библиотеки Python

Embed Size (px)

DESCRIPTION

Красота и изящность стандартной библиотеки Python. Автор: Максим Усачев

Citation preview

Page 1: Красота и изящность стандартной библиотеки Python

Красота и изящность стандартной библиотеки Python

Примеры использования

Макс Усачев[email protected]

Page 2: Красота и изящность стандартной библиотеки Python

Про группировкуэлементов

Page 3: Красота и изящность стандартной библиотеки Python

Группировка элементов

Дана произвольная строка

import string import random

RANDOM_STRING_LENGTH = 999 choices = string.ascii_letters + string.digits

random_string = [random.choice(choices) for \ i in xrange(RANDOM_STRING_LENGTH)]

Найти позиции каждого уникального символа этой строки в исходной строке.

Page 4: Красота и изящность стандартной библиотеки Python

Группировка элементов

Первое, что приходит людям на уми они так это и оставляют:

result = {} for index in xrange(len(random_string)): element = random_string[index] if element in result.keys(): result[element].append(index) else: result[element] = [index]

Page 5: Красота и изящность стандартной библиотеки Python

Группировка элементов

После тревожной ночи иногдакод становится чуть лучше:

result = {} for index, element in enumerate(random_string): if element in result: result[element].append(index) else: result[element] = [index]

Page 6: Красота и изящность стандартной библиотеки Python

Группировка элементов

А потом ты понимаешь...Что кода слишком много!

result = {} for index, element in enumerate(random_string): result.setdefault(element, []).append(index)

Page 7: Красота и изящность стандартной библиотеки Python

Группировка элементов

Казалось бы, куда уже короче ...

result = {} for index, element in enumerate(random_string): result.setdefault(element, []).append(index)

Page 8: Красота и изящность стандартной библиотеки Python

Группировка элементов

Модуль collections !

Модуль collections реализует высокопроизводительные контейнерные типы данных.

Counter, deque, OrderedDict и defaultdict, а также функция для создания типов данных - namedtuple().

Контейнеры, создаваемые при помощи этого модуля, представляют собой альтернативу встроенным в Python контейнерам общего назначения: dict, list, set и tuple.

Документация: http://docs.python.org/2/library/collections.html#module-collectionsИсходный код: http://hg.python.org/cpython/file/2.7/Lib/collections.py

http://hg.python.org/cpython/file/2.7/Lib/_abcoll.py

Page 9: Красота и изящность стандартной библиотеки Python

Группировка элементов

Примеры использования defaultdictКогда фабричная функция is None

>>> from collections import defaultdict

>>> d = defaultdict() >>> d['foo'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'foo'

new in Python v2.5

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

Page 10: Красота и изящность стандартной библиотеки Python

Группировка элементов

Примеры использования defaultdictКогда фабричная функция is not None

>>> d = defaultdict(int) >>> d['foo'] 0 >>> d['foo'] += 1 >>> d defaultdict(<type 'int'>, {'foo': 1}) >>> d['foo1'] += 5 >>> d defaultdict(<type 'int'>, {'foo': 1, 'foo1': 5})

Page 11: Красота и изящность стандартной библиотеки Python

Группировка элементов

Примеры использования defaultdictКогда фабричная функция is not None

>>> d = defaultdict(list) >>> d['foo'].append('foo') >>> d defaultdict(<type 'list'>, {'foo': ['foo']}) >>> d = defaultdict(set) >>> d['foo'].add('foo') >>> d['foo'].add('bar') >>> d['foo'].add('foo') >>> d defaultdict(<type 'set'>, {'foo': set(['foo', 'bar'])}

Page 12: Красота и изящность стандартной библиотеки Python

Группировка элементов

Теперь все ясно ;)

result = {} for index, element in enumerate(random_string): result.setdefault(element, []).append(index)

Используем defaultdict

result = defaultdict(list) for index, element in enumerate(random_string): result[element].append(index)

Page 13: Красота и изящность стандартной библиотеки Python

Группировка элементов

Действительно, высокопроизводительный контейнерРезультаты timeit

Самый простой подход, (if key in result ...): 3.07053208351

С использованием setdefault: 3.91122484207

С использованием defaultdict: 2.63944602013

Page 14: Красота и изящность стандартной библиотеки Python

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

Page 15: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Знакомая картина?

# pure Python elements = [ (subelement1, subelement2, ....), (subelement11, subelement22, ....), (subelement111, subelement222, ....), (subelement1111, subelement2222, ....), ]

# Django Model.objects.all().values_list('name', 'surname', 'age')

Page 16: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Более "живой" пример

from mock import Mock

database = Mock() database.make_query = Mock(return_value=[

('Book1', 'Author1', '10/01/2001'),('Book2', 'Author2', '10/02/2002'),('Book3', 'Author3', '10/03/2003'),

('Book4', 'Author4', '10/04/2004'),('Book5', 'Author5', '10/05/2005')])

publications = data.make_query() # pass publications as template context

Page 17: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Дальше только хуже ...

{% for publication in publications %} <div>publication[0]</div> <span>publication[1]</span> <b>publication[2]</b> {% endfor %}

Page 18: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Модуль collections!

namedtuple - фабричная функция для кортежей с именованными полями.

Именованные кортежи позволяют определить имена для каждой позиции в кортеже.

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

Именованные кортежи используют памяти не больше, чем обычные кортежи.

new in Python v2.6

Page 19: Красота и изящность стандартной библиотеки Python

Назови меня по имени

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

>>> from collections import namedtuple

>>> Person = namedtuple('Person', 'name surname age') >>> person = Person(name='Max', surname='Usachev', age=25) >>> person = Person('Max', 'Usachev', 25)

>>> person.name, person.surname, person.age ('Max', 'Usachev', 25) >>> person[0], person[1], person[2] ('Max', 'Usachev', 25)

Page 20: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Как оно работает еще

>>> person._asdict() OrderedDict([('name', 'Max'), ('surname', 'Usachev'), ('age', 25)])

>>> Person.full_name = property(lambda self: ' '.join((self.name, self.surname))) >>> person.full_name 'Max Usachev'

>>> Person._make(('Max', 'Usachev', 25)) Person(name='Max', surname='Usachev', age=25) >>> Person._fields ('name', 'surname', 'age')

Page 21: Красота и изящность стандартной библиотеки Python

Назови меня по имени

Дополненный начальный пример

from collections import namedtuple ...

Publication = namedtuple('Publication', 'name author date') publications = map(Publication._make, database.make_query())

{% for publication in publications %} <div>publication.name</div> <span>publication.author</span> <b>publication.date</b> {% endfor %}

Page 22: Красота и изящность стандартной библиотеки Python

Про сортировку

Page 23: Красота и изящность стандартной библиотеки Python

sortируй правильно

Все та же randomная строкаЗнаем что и как часто

# DON'T COUNT THIS WAY

letters = [(letter, random_string.count(letter)) for \ letter in set(random_string)]

Какой символ встречается чаще всего?

Page 24: Красота и изящность стандартной библиотеки Python

sortируй правильно

Самое распространенное решение

sorted(letters, key=lambda element: element[1])

Page 25: Красота и изящность стандартной библиотеки Python

sortируй правильно

Но все-таки лучше так:

sorted(letters, key=itemgetter(1))

И timeit уверен в этом!

С использованием lambda: 4.4638299942

С использованием itemgetter: 3.61604499817

Page 26: Красота и изящность стандартной библиотеки Python

sortируй правильно

Модуль operator

Модуль operator предлагает набор эффективных функций, соответствующих внутренним операторам Python:- add(a,b)- div(a, b)- not(a)- ...

А также такие полезные функции, как:- attrgetter(*attrs)- itemgetter(*items)- methodcaller(name[, args...]

Page 27: Красота и изящность стандартной библиотеки Python

sortируй правильно

Как работает operator.itemgetter

>>> from operator import itemgetter

>>> getter = itemgetter(0) >>> getter('abc') 'a' >>> getter([0, 1, 2]) 0

>>> getter = itemgetter(0, -1) >>> getter('abc') ('a', 'c') >>> getter([1, 2, 3]) (1, 3)

new in Python v2.4

Page 28: Красота и изящность стандартной библиотеки Python

sortируй правильно

Как работает operator.attrgetter

>>> from operator import attrgetter

>>> getter = attrgetter('name') >>> class Foo(object): pass >>> foo = Foo() >>> foo.name = 'foo' >>> getter(foo) 'foo' >>> foo.weight = 20 >>> getter = attrgetter('name', 'weight') >>> getter(foo) ('foo', 20)

new in Python v2.4

Page 29: Красота и изящность стандартной библиотеки Python

Про фильтрацию

Page 30: Красота и изящность стандартной библиотеки Python

filtруй правильно

Часто нужно принять решение на основе содержимого списка,а точнее, проверить, не пустой ли он

elements = [...] condition = lambda x: ...

if len([element for element in elements if condition(element)]): # do something

Page 31: Красота и изящность стандартной библиотеки Python

filtруй правильно

Для начала так:

if [element for element in elements if condition(element)]: # do something

* Но список может быть большим

* А если нашли первый подходящий элемент, то зачем искать дальше?

Напрашивается решение на основе генераторов!

Page 32: Красота и изящность стандартной библиотеки Python

filtруй правильно

Вот оно!

if any(element for element in elements if condition(element)): # do something

Т.е. any вернет True как только встретит первый трушный элемент

Внимание, вопрос: что тут не так?

Page 33: Красота и изящность стандартной библиотеки Python

filtруй правильно

Как работает any:

def any(iterable): for element in iterable: if element: return True return False

Page 34: Красота и изящность стандартной библиотеки Python

filtруй правильно

И если вдруг:

>>> nums = [0, 22, 15] >>> condition = lambda x: x < 10 >>> any(num for num in nums if condition(num)) False

Page 35: Красота и изящность стандартной библиотеки Python

filtруй правильно

Решение:

>>> any(condition(num) for num in nums) True

Page 36: Красота и изящность стандартной библиотеки Python

делай все правильно

* Пишите красивый код

* Пишите правильный код (cпрашивайте себя "Не ХХХXХ ерунду ли я пишу?")

* Изучайте стандартную библиотеку Python

* Используйте collections, operator, itertools ...

* Приходите снова!