Как стать автором
Обновить

Основы Python — кратко. Часть 4. Генераторы списков

Время на прочтение3 мин
Количество просмотров217K
List comprehensions

Продолжим наш цикл уроков. Добрый день.

Генерация списков

Генерация списков (не знаю как адекватно перевести на русский list comprehensions) — яркий пример «синтаксического сахара». То есть конструкции, без которой легко можно обойтись, но с ней намного лучше :) Генераторы списков, как это не странно, предназначены для удобной обработки списков, к которой можно отнести и создание новых списков, и модификацию существующих.
Допустим, нам необходимо получить список нечетных чисел, не превышающих 25.
В принципе, только познакомившись с работой команды xrange решить эту проблему несложно.

>>> res = []
>>> for x in xrange(1, 25, 2):
...     res.append(x)
...
>>> print res 

В общем-то, полученный результат — целиком нас устраивает всем, кроме длинной записи. тут-то на помощь и придет наш «сахарок». В самом простом виде, он обычно

>>> res = [x for x in xrange(1, 25, 2)]
>>> print res
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23]

Синтаксис, в принципе прост. Все выражение записывается в квадратных скобках. Сначала идет выражение, которое будет задавать элементы списка, потом — цикл с помощью которого можно изменять выражение. Обе части могут быть сколь угодно сложными. Например, вот как можно получить список квадратов тех же нечетных чисел:

>>> res = [x**2 for x in xrange(1, 25, 2)]
>>> print res
[1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529]

По желанию, можно добавить дополнительные условия фильтрации. Например, доработаем наш предыдущий пример так, чтобы исключались квадраты чисел, кратных 3.

>>> res = [x**2 for x in xrange(1, 25, 2) if x % 3 != 0]
>>> print res
[1, 25, 49, 121, 169, 289, 361, 529]

Вот пример немного посложнее.

>>> dic = {'John':1200, 'Paul':1000, 'Jones':1850, 'Dorothy': 950}
>>> print "\n".join(["%s = %d" % (name, salary) for name, salary in dic.items()])
Jones = 1850
Dorothy = 950
Paul = 1000
John = 1200

Тут мы использовали генератор списков для превращения словаря в набор записей, это может быть удобно в таких задачах как сохранение конфигов или генерация HTML. Выражение "%s = %d" % (name, salary) — предназначено для форматирования строк, и по сути похоже на аналоги в С. В начале идет строка где задаются позиции для вставки значений (%s — строковое, %d — числовое). После знака % — «вставляемые» значения в виде кортежа.

В принципе — генератором можно обрабатывать и готовые списки.

Рассмотрим простой пример. Допустим, у нас имеется лог-файл, в котором хранится статистика запросов к серверу в виде «ip bytes» через пробел, по одному хосту на
строку. Примерно так:

127.0.0.1 120
10.1.1.1 210
127.0.0.1 80
10.1.1.1 215
10.1.1.1 200
10.1.1.2 210

Нам необходимо вычислить суммарный объем траффика на каждый хост и выдать его в виде списка в поряке убывания траффика.
Программу для решения данной проблемы будет весьма недлинной :) Ее можно еще сильнее сократить, но это явно пойдет в ущерб ее читабельности.

#!/usr/bin/env python
#coding: utf8

# 1 считываем из файла строки и делим их на пары IP-адрес
raw = [x.split(" ")  for x in open("log.txt")]

# 2 заполняем словарь
rmp = {}
for ip, traffic in raw:
        if ip in rmp:
                rmp[ip] += int(traffic)
        else:
                rmp[ip] = int(traffic)

# 3 переводим в список и сортируем
lst = rmp.items()
lst.sort(key = lambda (key, val): key)
# 4 получаем результат
print "\n".join(["%s\t%d" % (host, traff) for host, traff in lst])

Разберем ее пошагово.
1. В этой строке мы читаем из файла, который открываем с помощью функции open. Функция open по-умолчанию открывает файл для чтения и возвращает файловый объект, который кроме всего прочего является итерируемым. То есть по нему можно «двигаться» с помощью цикла for, чем мы и пользуемся в нашем случае. Кроме того, с помощью метода split мы делим каждую строку на пару — адрес — траффик.
2. Для удобства, мы формируем хеш, ключами в котором являются адреса, а значениями — траффик. Если ключа еще нет, то мы его созадаем, если же есть, то мы плюсуем текущий траффик к его предыдущим «наработкам». После этого цикла мы получим хеш с суммами траффика по всем хостам.
3. К сожалению, словари в Пайтоне не сортируются. Потому нам придется перевести его в список для сортировки. Следующие две строки переводят словарь в список и осуществляют его сортировку по второму полю.
4. Вот и все что осталось — «собрать» результат, как мы уже это делали раньше.

На сегодня хватит :)
Домашнее задание.
1. Реализовать функцию-генератор строки с таблицей умножения на число Х.
2. Есть лог-файл какого-то чата. Посчитать «разговорчивость» пользователей в нем в виде ник — количество фраз. Посчитать среднее число букв на участника чата.

ЗЫ О чем лучше продолжать — про классы и ООП или про элементы функционального программирования?
Теги:
Хабы:
+1
Комментарии83

Публикации

Изменить настройки темы

Истории

Работа

Python разработчик
135 вакансий
Data Scientist
62 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн