Архив метки: Python

A Byte of Python

pythonГод публикации: 2013

Автор: Swaroop C H

Язык: Русский

Переводчик: Владимир Смоляр

Страниц: 251

Лицензия: и Creative Commons AributionShare

Alike 3.0 Unported

Это книга для начинающих изучать популярный язык программирования — Python. Это один из немногих очень простых в освоении и в то же время достаточно мощных языков. Это важно для начинающих специалистов, у которых нет много времени на изучение языка, а также тем, кто хочет писать программы быстро с минимумом ошибок. Читать

Как можно участвовать в ICFPC (2016)

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

В этом году мы с товарищами (ForNever, Minoru, Hagane, grouzen) опять взялись участвовать в ICFPC. Если кто не в курсе, что это такое — см мой предыдущий пост или серию постов товарища adept.
В этот раз для разнообразия мы не писали AI для игрушки. Организаторы были из Японии, и поэтому мы весь уик-енд… складывали оригами. Кто-то из кода, а кто-то нет.
Задача состояла в том, чтобы из квадратного «листа бумаги» складывать разные (плоские) фигуры. В качестве задачи даётся описание нужной фигуры, а решение — набор складок на квадрате и описание, какие вершины в какие переходят при складывании. Первая сотня фигур была предложена организаторами, а дальше задачи могли отправлять участники, и за отправку задач тоже давали очки.
При этом, на самом деле, это было «не настоящее оригами». Были допустимы решения, невозможные с бумагой — части листа могли проходить друг через друга при складывании. При отправке решений чужих задач можно было даже «рвать бумагу» (при отправке своих задач — нельзя). Момент про разрешено ли разрезание мы уточняли долго и сложно.
Контест в этот раз проходил с утра пятницы по вечер воскресенья в моём часовом поясе.

В пятницу

с утра я «по-быстрому» написал скачивалку задач с сервера и закачивалку решений (на python, просто потому что там было REST API, а у меня уже был опыт использования для этого питоньей библиотеки requests). Ещё я написал парсер предложенного формата задач и рендерилку, которая рисует фигуры из задач в виде svg (на Haskell). Сразу пригодился хаскельный модуль Data.Ratio. Дело в том, что в задачах использовались координаты в виде рациональных чисел, причём размеры числителя и знаменателя не были ограничены. Так что быстро образовалась строчка type Number = Ratio Integer.
Потом я посмотрел на результаты рендера и увидел, что первые семь задач тривиальные (там просто квадрат, сдвинутый или повёрнутый, но не сложенный), решения для них легко написать вручную. Решил и залил.
Потом мы начали думать над задачей (я уже писал, у меня всегда так — сначала код, потом думать).
Когда нет ограничения на разрезание бумаги, задача сводится к тому, чтобы разрезать квадрат на эн многоугольников и сложить из них нужную фигуру. Насколько я знаю, подобные темы широко и глубоко изучены, но я не знаком с конкретными работами и алгоритмами. (в университете был даже какой-то спецкурс по оригами, как разделу геометрии, но я на него не попал). Поэтому я долго и упорно думал в эту сторону, но ничего не придумал.
В чате довольно быстро образовалось несколько идей:

  • Разрезать требуемую фигуру на треугольники и попытаться из таких треугольников сложить квадрат.
  • Какой-нибудь вариант генетических алгоритмов: разрезаем квадрат как попало и складываем как попало, оцениваем скор в соответствии с правилами организаторов.
  • Быстро придумался простой алгоритм для складывания любого достаточно маленького выпуклого многоугольника: пройти по всем его рёбрам и сложить бумагу вдоль них. Если останутся торчащие «хвосты», то опять пройти по рёбрам и подвернуть вдоль них.
  • Кроме силуэта фигуры, в задачах приводился её «скелет» — набор всех рёбер в положении после складывания. При этом, правда, было указание, что это только подсказка, складывать в соответствии с этим скелетом не обязательно. Так вот, появилась идея брать этот скелет и пытаться разворачивать его до квадрата.

Товарищ grouzen произвёл обширные изыскания существующих научных работ на тему оригами и около, и обеспечил нас пейперами для чтения на всю неделю. К сожалению, применить их мы не смогли.
Потом начался как всегда разброд и шатание, каждый стал заниматься чем-то своим.
Я решил начать с написания какого-никакого «фреймворка» для дальнейшей работы — набора функций для разрезания многоугольников, объединения и т.п. Некоторые из геометрических алгоритмов тривиальны (отражение многоугольника относительно прямой), зато другие зубодробительны (объединение произвольных многоугольников). Для таких алгоритмов я стал гуглить существующие реализации, по возможности на Haskell (т.к. парсер задач уже был на Haskell). Нашёл только clipper. Это биндинги к одноимённой библиотеке на C++. Сразу обнаружилась особенность: Clipper работает с целочисленными координатами (видим

Майкл Доусон — Программируем на Python, ответы на 5-ую главу…

Задача №1

  1. # coding=utf-8
  2. # Создайте программу, которая будет выводить список слов в случайном порядке.
  3. # На экране должны печататься без повторений все слова из представленного списка.
  4. import random
  5. print(«Введите 4 слова для демонстрации программы:»)
  6. a = input(«Первое слово: n«)
  7. b = input(«Второе слово: n«)
  8. c = input(«Третье слово: n«)
  9. d = input(«Четвертое слово: n«)
  10. WORDS = [a, b, c, d]
  11. print(«nИзначальный список:n«, WORDS)
  12. # Эта функция не упоминалась в главе, но чтобы не писать лишнего, лучше заменим строчки этим:
  13. random.shuffle(WORDS)
  14. print(«nСписок в случайном порядке:n«, WORDS)
  15. input(«nНажмите Enter, чтобы выйти…»)

Задача №2

  1. «»» coding=utf-8
  2. Напишите программу «Генератор персонажей» для ролевой игры.
  3. Пользователю должно быть предоставлено 30 пунктов,которые можно
  4. распределить между четырями характеристиками: Сила, Здоровье,
  5. Мудрость и Ловкость. Надо сдлать так, чтобы пользователь мог
  6. не только брать эти пункты из общего»пула», но и возвращать их туда из
  7. характеристик, которым он решит присвоить другие значения.»»»
  8. «»» Также, хоть это и не требуется в задании, мы будем требовать
  9. от игрока, чтобы он улаживался в отведенные 30 очков и использовал их все.
  10. Также, только после окончания задания заметил, что 5 глава была
  11. про списки и словари, соответственно, автором, скорей всего,
  12. подразумевалось, что здесь должны использоваться словари.
  13. Переделывать или писать вторую версию с использованием словаря
  14. не буду, так как считаю, что алгоритм решения ясен.Даже будет короче.
  15. А в следующей главе изучите функции и попробуйте сделать это задание,
  16. сипользуя функции. И вы удивитесь, насколько сократится код.
  17. Но, следуя согласно книге, подразумевается, что мы пока не знаем о них.»»»
  18. # Объяснение условий игроку.
  19. print(«»»Вам будут представлены изначальные характеристики героя: Сила, Здоровье, Мудрость и Ловкость.
  20. Вам нужно будет, как в ролевой игре, распределить 30 очков между навыками»»»)
  21. # Объявляем переменные.
  22. strength = 0
  23. health = 0
  24. wisdom = 0
  25. agility = 0
  26. choice = None

    </li >

  27. global_choice = None
  28. while global_choice != 0:
  29. # Вывод актуальной таблицы после действия.
  30. ost_points = (30 — strength — health — wisdom — agility)
  31. print(«Таблица характеристик на данный момент: n«
  32. «ttt1. Сила:», strength, «n«
  33. «ttt2. Здоровье:», health, «n«
  34. «ttt3. Мудрость:», wisdom, «n«
  35. «ttt4. Ловкость:», agility, «nn«
  36. «tttСвободное количество очков:», ost_points, «n«)
  37. # Первый выбор
  38. print(«Что вы хотите сделать сейчас?n«
  39. «ttt1. Добавить очки в одну из характеристик.n«
  40. «ttt2. Убрать очки из характеристики.n«
  41. «ttt3. Закончить распределиние очков.n«)
  42. global_choice = int(input())
  43. if global_choice == 1:
  44. print(«В какую из характеристик вы хотите добавить очки?n«
  45. «ttt1. Сила.n«
  46. «ttt2. Здоровье.n«
  47. «ttt3. Мудрость.n«
  48. «ttt4. Ловкость.n«)
  49. choice = int(input())
  50. if choice == 1:
  51. print(«Сколько очков вы хотите добавить?n«)
  52. scores = int(input())
  53. if scores >= 0 and scores <= ost_points:
  54. strength += scores
  55. else:
  56. print(«Недопустимое количество очков.n«)
  57. elif choice == 2:
  58. print(«Сколько очков вы хотите добавить?n«)
  59. scores = int(input())
  60. if scores >= 0 and scores <= ost_points:
  61. health += scores
  62. else:
  63. print(«Недопустимое количество очков.n«)
  64. elif choice == 3:
  65. print(«Сколько очков вы хотите добавить?n«)
  66. scores = int(input())
  67. if scores >= 0 and scores <= ost_points:
  68. wisdom += scores
  69. else:
  70. print(«Недопустимое количество очков.n«)
  71. elif choice == 4:
  72. print(«Сколько очков вы хотите добавить?n«)
  73. scores = int(input())
  74. if scores >= 0 and scores <= ost_points:
  75. agility += scores
  76. else:
  77. print(«Недопустимое количество очков.n«)
  78. # Второй выбор
  79. elif global_choice == 2:
  80. print(«Из какой характеристики вы хотите убрать очки?n«
  81. «ttt1. Сила.n«
  82. «ttt2. Здоровье.n«
  83. «ttt3. Мудрость.n«
  84. «ttt4. Ловкость.n«)
  85. choice = int(input())
  86. if choice == 1:
  87. print(«Сколько очков вы хотите убрать?n«)
  88. scores = int(input())
  89. if scores >= 0 and (strength — scores) >= 0:
  90. strength —= scores
  91. else:
  92. print(«Недопустимое количество очков.n«)
  93. elif choice == 2:
  94. print(«Сколько очков вы хотите убрать?n«)
  95. scores = int(input())
  96. if scores >= 0 and (health — scores) >= 0:
  97. health —= scores
  98. else:
  99. print(«Недопустимое количество очков.n«)
  100. elif choice == 3:
  101. print(«Сколько очков вы хотите убрать?n«)
  102. scores = int(input())
  103. if scores >= 0 and (wisdom — scores) >= 0:
  104. wisdom —= scores
  105. else:
  106. print(«Недопустимое количество очков.n«)
  107. elif choice == 4:
  108. print(«Сколько очков вы хотите убрать?n«)
  109. scores = int(input())
  110. if scores >= 0 and (agility — scores) >= 0:
  111. agility —= scores
  112. else:
  113. print(«Недопустимое количество очков.n«)
  114. # Третий выбор. Проверяем, все ли очки использованы.
  115. elif global_choice == 3:
  116. if ost_points == 0:
  117. break
  118. else:
  119. print(«Используйте все очки, данные вам!n«)
  120. print(«Ваш герой готов! Таблица его характеристик выглядит так: n«
  121. «ttt1. Сила:», strength, «n«
  122. «ttt2. Здоровье:», health, «n«
  123. «ttt3. Мудрость:», wisdom, «n«
  124. «ttt4. Ловкость:», agility, «n«)
  125. input(«nНажмите Enter, чтобы выйти…»)

Задача №3

  1. # coding=utf-8
  2. «»»
  3. Напишите программу «Кто твой папа?», в которой пользователь будет
  4. вводить имя человека, а программа — называть отца этого человека.
  5. Чтобы стало интересней, можно «научить» программу родственным
  6. отношениям среди литературных персонажей, исторических персонажей,
  7. исторических лиц и современных знаменитостей.
  8. Предоставьте пользователю возможность добавлять,
  9. заменять и удалять пары «сын-отец».»»»
  10. MENU = («»»
  11. 1 — Поиск отца человека по имени
  12. 2 — Изменение данных
  13. 3 — Удаление данных
  14. 4 — Добавить новые данные
  15. 5 — Выход
  16. «»»)
  17. family = {«Остап Бендер»: «Турецкоподанный»,
  18. «Люк Скайуокер»: «Дарт Вейдер»,
  19. «Солид Снейк»: «Биг Босс»}
  20. choice = None
  21. son = «»
  22. father = «»
  23. while choice != 5:
  24. print(MENU)
  25. choice = int(input(«Выберите пункт меню:»))
  26. # Поиск отца человека по имени.
  27. if choice == 1:
  28. son = input(«Введите имя человека: «)
  29. if son in family:
  30. print(«nРодителем человека по имени», son, «является», family[son])
  31. else:
  32. print(«Ошибка, такого человека нет в базе данных»)
  33. # Изменение данных.
  34. elif choice == 2:
  35. son = input(«Введите имя человека: «)
  36. if son in family:
  37. father = str(input(«Введите новое имя его отца: «))
  38. family[son] = father
  39. print(«nРодителем человека по имени», son, «является», family[son])
  40. else:
  41. print(«Ошибка, такого человека нет в базе данных»)
  42. # Удаление данных.
  43. elif choice == 3:
  44. son = input(«Введите имя человека: «)
  45. if son in family:
  46. del family[son]
  47. print(«nЗапись удалена»)
  48. else:
  49. print(«Ошибка, такого человека нет в базе данных»)
  50. # Добавить новые данные.
  51. elif choice == 4:
  52. son = input(«Введите имя человека: «)
  53. if son in family:
  54. print(«nТакая запись уже существует»)
  55. else:
  56. father = str(input(«Введите имя родителя: «))
  57. family[son] = father
  58. print(«Добавлено в базу данных»)
  59. # Выход.
  60. elif choice == 5:
  61. print(«До свиданья!»)

Задача №4

  1. # coding=utf-8
  2. «»»
  3. Доработайте программу «Кто твой папа? так, чтобы можно было,
  4. введя имя человека, узнать, кто его дед. Программа должна
  5. по-прежнему пользоваться словарем с парами «сын-отец».
  6. Подумайте, как включить в этот словарь несколько
  7. поколений. «»»
  8. MENU = («»»
  9. 1 — Поиск деда человека по имени
  10. 2 — Изменение данных
  11. 3 — Удаление данных
  12. 4 — Добавить новые данные
  13. 5 — Выход
  14. «»»)
  15. family = {«Остап Бендер»: {«Турецкоподанный»: «Отец турецкоподанного»},
  16. «Люк Скайуокер»: «Дарт Вейдер»,
  17. «Солид Снейк»: «Биг Босс»}
  18. choice = None
  19. son = «»
  20. father = «»
  21. while choice != 5:
  22. print(MENU)
  23. choice = int(input(«Выберите пункт меню:»))
  24. # Поиск от ца человека по имени.
  25. if choice == 1:
  26. son = input(«Введите имя человека: «)
  27. if son in family:
  28. print(«nРодителем человека по имени», son, «является», family[son[0]], «а его дедом», family[son[1]])
  29. else:
  30. print(«Ошибка, такого человека нет в базе данных»)
  31. # Изменение данных.
  32. elif choice == 2:
  33. son = input(«Введите имя человека: «)
  34. if son in family:
  35. father = str(input(«Введите новое имя его отца: «))
  36. family[son] = father
  37. print(«nРодителем человека по имени», son, «является», family[son])
  38. else:
  39. print(«Ошибка, такого человека нет в базе данных»)
  40. # Удаление данных.
  41. elif choice == 3:
  42. son = input(«Введите имя человека: «)
  43. if son in family:</ div>
  44. del family[son]
  45. print(«nЗапись удалена»)
  46. else:
  47. print(«Ошибка, такого человека нет в базе данных»)
  48. # Добавить новые данные.
  49. elif choice == 4:
  50. son = input(«Введите имя человека: «)
  51. if son in family:
  52. print(«nТакая запись уже существует»)
  53. else:
  54. father = str(input(«Введите имя родителя: «))
  55. family[son] = father
  56. print(«Добавлено в базу данных»)
  57. # Выход.
  58. elif choice == 5:
  59. print(«До свиданья!»)

Автор: Alek Azimov

pytest продолжение

В первой части статей мы немного познакомились с основными базовыми возможностями pytest. Рассмотрели его особенностей и подходы.

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

Последовательно выполнение тестовых сценариев


В тестировании часто бывают случаи, когда необходимо объединить несколько проверок в один большой тест и выполнить их последовательно. Причем бывает и так, что один сценарий зависит от результатов работы предыдущего (но такое лучше стараться избегать в автотестировании). 

В следующих статьях мы посмотрим как можно избежать этой ситуации пользуясь стандартными средствами пайтеста.

Например, тестируемая программа при первом запуске накатывает схему базы (sqlite чтобы не морочиться) и заполняет её некоторой служебной информацией. Допустим перед нами стоит задача «дешево» протестировать этот модуль. Сходу задачу модно разбить на 2 подзадачи — проверка создания файла базы, затем проверка схемы и в конце проверка данных.

Самый простой вариант — нумерация в названии тестов

# conftest.py
import os
import pytest
import sqlite3


def pytest_configure(config):

    config.DB_PATH = «db.sqlite»


@pytest.fixture(scope=»module»)
def creator(request):
    DB_PATH = request.config.DB_PATH
    con = sqlite3.connect(DB_PATH)
    cur = con.cursor()
    cur.executescript(«»»
        create table person(
            firstname,
            lastname,
            age
        );

        create table book(
            title,
            author,
            published
        );

        insert into book(title, author, published)
        values (
            'Dirk Gently''s Holistic Detective Agency',
            'Douglas Adams',
            1987
        );
        «»»)
    con.commit()
    con.close()
    return DB_PATH


@pytest.fixture
def cursor(request):
    class cursor:

        def __init__(self, dbpath):
            self.dbpath = dbpath
            self.conn = sqlite3.connect(self.dbpath)

        def table_exists(self, table):
            cursor = self.conn.cursor()
            cursor.execute(
                «SELECT name FROM sqlite_master WHERE type = «table»»)
            tables = cursor.fetchall()
            for each in tables:
                if table in each:
                    return True
            return False

        def getrows(self, table):
            cursor = self.conn.cursor()
            cursor.execute(«SELECT * FROM %s;» % (table))
            return cursor.fetchall()

    return cursor(request.config.DB_PATH)

# test.py
def test_1_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.parametrize(«table», [«person», «book»])
def test_2_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.parametrize(«table», [«book»])
def test_3_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Спасибо документации питона за готовые примеры.

У такого подхода есть ряд недостатков.
1. В названии теста появляется нумерация — это лишняя мета информация. (Это может сказаться на тестовом отчете или билд логе CI сервера)
2. Название теста усложняется
3. Вставка нового элемента в середину приведет к смене нумерации всех последующих тестов

Вариант посложнее — маркеры


Свои маркеры мы реализовывать не будем, а используем готовый плагин pytest-ordering. В принципе вся реализация такого плагина составит не больше 100 строчек кода.

# test.py
@pytest.mark.order1
def test_db_exists(creator):
    assert os.path.exists(creator)


@pytest.mark.order2
@pytest.mark.parametrize(«table», [«person», «book»])
def test_check_scheme(table, creator, cursor):
    result = cursor.table_exists(table)
    assert result


@pytest.mark.order3
@pytest.mark.parametrize(«table», [«book»])
def test_check_rows(table, creator, cursor):
    assert cursor.getrows(table)


Наши тестовые функции преобразились, стали более понимаемы для чтения.
Из коробки плагин содержит создание цепочек выполнения, более понятные маркеры (pytest.mark.run('first'), pytest.mark.run('second')) и прочее. Более подробно в микро доку плагина.

Ссылки
[1] https://docs.python.org/2/library/sqlite3.html
[2] http://pytest-ordering.readthedocs.org/en/develop/

Автор: Евгений Курочкин

{} vs dict()


В питоне предусмотрена возможность создать словарь двумя способами — через фигурные скобки {} и через конструктор dict(). В чем разница и что лучше использовать в коде?


Код

a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}

Пример наглядно демонстрирует что при статическом определении атрибутов количество кода практически одинаковое (скобки больше всего лишь на 2 символа). 

Инициализация

Конструктор словаря предлагает расширенный функционал для инициализации словаря.

d = dict((str(v),v) for v in range(10))
dict(zip(['one', 'two', 'three'], [1, 2, 3]))


Скорость работы

Выполним в консоли следующие выражения

>>python -m timeit «{}»
10000000 loops, best of 3: 0.034 usec per loop

>>python -m timeit «dict()»

10000000 loops, best of 3: 0.127 usec per loop

Почему такая существенная разница в скорости? Все просто, смотрим что выдает диассемблер

>>import dis

>>def d(): t = {}

>>dis.dis(d)

  1           0 BUILD_MAP                0
              3 STORE_FAST               0 (t)
              6 LOAD_CONST               0 (None)

              9 RETURN_VALUE

>>def d(): t = dict()
>>dis.dis(d)

  1           0 LOAD_GLOBAL              0 (dict)

              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (t)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE



При вызове конструктора dict() выполняется большее количество инструкций питона.

Вывод

Если для словаря заранее известны пары ключ-словарь, то в коде лучше использовать фигурные скобки, т.к. они дают некоторый прирост скорости при создании словаря. При динамическом создании словаря придется использовать конструктор.

PS. Все выводы актуальны и для списков


Ссылки

https://docs.python.org/2/library/stdtypes.html#mapping-types-dict
http://stackoverflow.com/questions/6610606/dict-literal-vs-dict-constructor-any-preferred

Автор: Евгений Курочкин

Топ 10 вопросов по python на stackoverflow

What does the yield keyword do in Python?
What is a metaclass in Python?
How to check whether a file exists using Python
Does Python have a ternary conditional operator?
Calling an external command in Python
How can I make a chain of function decorators in Python?
What does `if __name__ == “__main__”:` do?
How can I merge two Python dictionaries in a single expression?
Sort a Python dictionary by value
How do I install pip on Windows?

Довольно ожидаемо

[1] stackoverflow.com

Автор: Евгений Курочкин