List comprehensions
Продолжим наш цикл уроков. Добрый день.
Генерация списков
Генерация списков (не знаю как адекватно перевести на русский list comprehensions) — яркий пример «синтаксического сахара». То есть конструкции, без которой легко можно обойтись, но с ней намного лучше :) Генераторы списков, как это не странно, предназначены для удобной обработки списков, к которой можно отнести и создание новых списков, и модификацию существующих.
Допустим, нам необходимо получить список нечетных чисел, не превышающих 25.
В принципе, только познакомившись с работой команды xrange решить эту проблему несложно.
В общем-то, полученный результат — целиком нас устраивает всем, кроме длинной записи. тут-то на помощь и придет наш «сахарок». В самом простом виде, он обычно
Синтаксис, в принципе прост. Все выражение записывается в квадратных скобках. Сначала идет выражение, которое будет задавать элементы списка, потом — цикл с помощью которого можно изменять выражение. Обе части могут быть сколь угодно сложными. Например, вот как можно получить список квадратов тех же нечетных чисел:
По желанию, можно добавить дополнительные условия фильтрации. Например, доработаем наш предыдущий пример так, чтобы исключались квадраты чисел, кратных 3.
Вот пример немного посложнее.
Тут мы использовали генератор списков для превращения словаря в набор записей, это может быть удобно в таких задачах как сохранение конфигов или генерация HTML. Выражение "%s = %d" % (name, salary) — предназначено для форматирования строк, и по сути похоже на аналоги в С. В начале идет строка где задаются позиции для вставки значений (%s — строковое, %d — числовое). После знака % — «вставляемые» значения в виде кортежа.
В принципе — генератором можно обрабатывать и готовые списки.
Рассмотрим простой пример. Допустим, у нас имеется лог-файл, в котором хранится статистика запросов к серверу в виде «ip bytes» через пробел, по одному хосту на
строку. Примерно так:
Нам необходимо вычислить суммарный объем траффика на каждый хост и выдать его в виде списка в поряке убывания траффика.
Программу для решения данной проблемы будет весьма недлинной :) Ее можно еще сильнее сократить, но это явно пойдет в ущерб ее читабельности.
Разберем ее пошагово.
1. В этой строке мы читаем из файла, который открываем с помощью функции open. Функция open по-умолчанию открывает файл для чтения и возвращает файловый объект, который кроме всего прочего является итерируемым. То есть по нему можно «двигаться» с помощью цикла for, чем мы и пользуемся в нашем случае. Кроме того, с помощью метода split мы делим каждую строку на пару — адрес — траффик.
2. Для удобства, мы формируем хеш, ключами в котором являются адреса, а значениями — траффик. Если ключа еще нет, то мы его созадаем, если же есть, то мы плюсуем текущий траффик к его предыдущим «наработкам». После этого цикла мы получим хеш с суммами траффика по всем хостам.
3. К сожалению, словари в Пайтоне не сортируются. Потому нам придется перевести его в список для сортировки. Следующие две строки переводят словарь в список и осуществляют его сортировку по второму полю.
4. Вот и все что осталось — «собрать» результат, как мы уже это делали раньше.
На сегодня хватит :)
Домашнее задание.
1. Реализовать функцию-генератор строки с таблицей умножения на число Х.
2. Есть лог-файл какого-то чата. Посчитать «разговорчивость» пользователей в нем в виде ник — количество фраз. Посчитать среднее число букв на участника чата.
ЗЫ О чем лучше продолжать — про классы и ООП или про элементы функционального программирования?
Продолжим наш цикл уроков. Добрый день.
Генерация списков
Генерация списков (не знаю как адекватно перевести на русский 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. Есть лог-файл какого-то чата. Посчитать «разговорчивость» пользователей в нем в виде ник — количество фраз. Посчитать среднее число букв на участника чата.
ЗЫ О чем лучше продолжать — про классы и ООП или про элементы функционального программирования?