Сводный план лекций по спецкурсу «Язык программирования Python» (осень 2014

История Python. Командная строка

  • Россум,_Гвидо_ван

  • Влияние ЯП 80-х годов на концепцию Python (ABC, Modula, ...)
  • Мощность сообщества и кодовой базы, стандартный модули и Python Package Index

  • Свободное лицензирование

Работа в командной строке

  • Командная строка - калькулятор
  • Подсистема помощи
    • Просто help()

    • Команда help(объект) и что она делает

    • Интерактивная HTML-документация
  • Объекты Python
    • Создание объектов при интерпретации команд
    • Имена объектов и счётчик ссылок (sys.getrefcount)

    • Операция = как операция именования a == b vs. a is b

      • Изменение объекта по любому из имён
    • Области видимости, функция dir() и dir(объект)

  • Различные удобства ЯП, возникающие уже в командной строке
  • «Продвинутые» командные надстройки:

Настройка командной строки

  • История, поиск по истории (^R)
  • Достраивание имён
  • Файлы:
    • .bashrc:

      . . .
      export PYTHONSTARTUP=$HOME/.pythonstartup
      . . .
    • .pythonstartup:

      import atexit
      import os
      import readline
      import rlcompleter  # пока не настроен
      
      historyPath = os.path.expanduser("~/.pyhistory")
      
      def save_history(historyPath=historyPath):
         import readline
         readline.write_history_file(historyPath)
      
      if os.path.exists(historyPath):
         readline.read_history_file(historyPath)
      
      atexit.register(save_history)
      del os, atexit, readline, rlcompleter, save_history, historyPath
    • .inputrc

      . . .
      "\C-i": complete
      . . .

Логические операции, операторы ветвления и цикла

Неявная динамическая типизация в Python

  1. Любые функции (методы) применимы к любым объектам
    • Если в процессе выполнения происходит обращение к несуществующему объекту (полю), активизируется исключение
  2. Проверка существования объекта (поля) происходит в момент обращения к енму
  3. (дополнительно) Все операции над объектами (типа +, [ , () и т. п.) — спецметоды объектов

Логические выражения

  • Сравнение, в т. ч. сравнение любого объекта с любым, операция is

  • Тип bool и операции and, or и not, условные вычисления

  • Понятие о нулевом элементе (класса) и методе __nonzero__

  • Операции and и or для произвольных объектов

    • блеск и нищета конструкции вида a = b and c or d

Множественное присваивание

Конструкции типа a,b,c=d,e,f=1,2,"". Атомарность множественного присваивания и a,b=b,a

Условный оператор и операторы цикла

  • Понятие «блок с отступом» (indented block)
  • Оператор if/elif/else, неструктурная сущность elif

  • Оператор while/break/continue. Клауза else.

  • Оператор for по итерируемому объекту (__iter__). Клауза else на примере задачи поиска.

Решние домашних заданий

  • Использование редактора:
    • vim, Geany, различные IDE

    • Настройка отступов (табуляции — зло)
  • Как оформлять и посылать Д/З

Стандартные типы данных и выражения-конструкторы

Дополнения к предыдущей лекции

  • О неэстетичности цикла с пост-условием
  • Условное выражение A if C else B как адекватная замена C and A or B

  • Волшебные сравнения вида A < B < C

  • Конструкции вида +=, &= и т. п.

  • raw_input() vs. input(), eval() и `-выражение

  • Пару слов о модулях: it's all about namespace

Скалярные типы данных

  • Целые и длинные целые
  • Вещественные и комплексные числа
    • о несуществовании вещественных чисел в цифровых ЭВМ (2.2 + 3.3)

    • ⇒ модули decimal, fractions

    • модуль random

  • Булевский и типы-объекты (None, NotImplemented, Ellipsis и т. п.)

Последовательности

  • Кортежи (константные списки)
    • со скобками и без, с запятой в конце и без неё
    • кортеж в левой части присваивания и цикла for

    • секционирование последовательностей на примере кортежей
      • отрицательные значения и умолчания
    • методы: count и index; функция len(), операция in

    • перечисления и многоточие (Ellipsis) — для пользовательских объектов
  • Списки
    • принципиальное отличие изменяемых структур от неизменяемых: non-hashable, /!\ скорость?

    • секция в левой части присваивания
    • методы append/pop/extend; insert/remove; reverse/sort

    • выражение-генератор списка
      • вложенное выражение-генератор (например, [x*y for x in xrange(5) for y in xrange(x)])

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

    • модификатор r"

  • Проблема UTF и Unicode-строки
  • bytearray, список однобайтовых целых, он же изменяемая строка

  • xrange

Множества

  • set() и frozenset()

  • Выражение-генератор множества

Множества, словари, строки и функции

Дополнение к предыдущей лекции:

  • «Неочевидная» работа конструкции типа [(i,j) for i in xrange(3) if j!=1 for j in xrange(3)]: как читать вложенные циклические выражения

Множества

  • Зачем множества?
  • Константные множества
  • Выражение-генератор множества

Словари

  • Хешируемые объекты и (видимо) поиск по хешу ⇒ хеш == индекс словаря
    • ⇒ не требуется сохранение порядка
  • Задание словаря
    • в виде {ключ:значение, …}

    • в виде циклического конструктора типа {выражение:выражение for имя in последовательность}

    • с помощью именованных параметров функции: dict(key=val, …) (см. далее)

    • из списка пар dict(список_пар)

      • BTW: функции zip() и enumerate()

  • Dict[key] и Dict[key]=значение: автодобавление ключа

  • итератор и проверка in по ключу

  • keys()/values()/items()

    • BTW типы view<что-нибудь>, например, viewkeys() (поддерживает алгебру множеств)

  • pop(), popitem(); update(), get() и sedtefault()

  • JT: В питоне вообще много сделано на словарях

Функции

  • JT: «Побочный эффект» — ересь, мелочь или строгая теория?

  • Вызываемый объект «fun(arg1, arg2, ...) is a shorthand for fun.__call__(arg1, arg2, ...)»

    • Передача по ссылке (википедия: по соиспользованию)

    • Отсутствие проверки вплоть до вызова (динамическая типизация)
    • Пространство имён и локальные переменные
      • Локальность переменных (по первой встрече в LHS или RHS), global

    • Умолчания для параметров (присваивание во время определения) и пропуск параметров
      • ⇒ Позиционные и именованные параметры
    • Строки документации
  • Функции-выражения (lambda)

    • JT: Краешек бездны: функционалы

    • Краешек оврага: «таблицы эмуляции» и передача функции в качестве параметра (например, sorted()/max() и cmp()/key())

  • Свёртка позиционных и именованных параметров
    • * и ** в списке формальных параметров

    • * и ** при вызове функции

    • ⇒ переменное количество параметров
    • ⇒ произвольные (!) именованные параметры

Строки

  • Напоминалка: строки — необычные последовательности (.index(), .count(),  in  и т. п. работают по подстрокам)

  • Строковые методы
    • Полезные и не очень (обзор)
    • Разбор ввода и склейка вывода с помощью .split() и .join()

  • Форматирование строки с помощью .format()

    • Старый C-like стиль: строка%послдедовательность

  • Кодировка, строки, u-строки и их преобразование
    • однобайтовый UTF в Python2

    • chr()/ord()

    • unicode() (нужна кодировка), обратное (используется LOCALE)

    • # coding: UTF в файле

Кодировки, исключения и генераторы

Долги за прошлую лекцию:

  • Что такое «передача параметров по соиспользованию»?
  • Защита от «побочного эффекта»:

   1 def fn():
   2   c = b
   3   b = 1
   4 
   5 b=3
   6 fn()
  • ⇒ предварительный разбор лексем, выделение и классификация идентификаторов. Доказательство: dis.dis(fn) vs. функция без b = 1.

  • Рекурсия. Оценка необходимости рекурсии. Гвидо и хвостовая рекурсия.

  • random.shuffle(), random.choice() и random.sample()

Пример исходного кода

Генератор «красивого» лабиринта.

Идея 1
Только половина ячеек лабиринта случайна, из остальных половина заранее проходима, а половина — нет:

.?.?.?.?.…
?#?#?#?#?…
.?.?.?.?.…
?#?#?#?#?…
Идея 2
Алгоритм.
  • Изначально все «?» непроходимы, а все «.» недостижимы.
  • Выбираем любую «.», делаем её достижимой и добавляем в план разведки.
  • Цикл, пока план разведки не пуст:
    • Выбираем случайную ячейку из плана
    • Если у неё есть неразведанный сосед (через одну ячейку)
      • Добавляем её обратно в план
      • Делаем соседа достижимым и добавляем его в план
      • Делаем стену между этой ячейкой и этим соседом проходимой
Идея 3
Если поместить в план разведки и вход, и выход, получится непроходимый лабиринт

   1 import random
   2 
   3 N = 15
   4 D = (-2,0), (0,2), (2,0), (0,-2)
   5 Map = {(i,j):2-(i%2|j%2) for i in xrange(N) for j in xrange(N)}
   6 Todo = [(N/2&-2,N/2&-2)] if random.randrange(2) else [(0,0),(N-1,N-1)]
   7 for x,y in Todo:
   8     Map[x,y]=0
   9 
  10 while Todo:
  11     x,y = Todo.pop(random.randrange(len(Todo)))
  12     Check = [(dx,dy) for dx,dy in D if 0<=x+dx<N and 0<=y+dy<N and Map[x+dx,y+dy]]
  13     if Check:
  14         dx,dy = random.choice(Check)
  15         Todo.extend([(x,y),(x+dx,y+dy)])
  16         Map[x+dx,y+dy]=Map[x+dx/2,y+dy/2]=0
  17 
  18 for i in xrange(N):
  19     print "".join(".#"[Map[i,j]] for j in xrange(N))

И результат:

...#.#.#.#.....
.###.#.#.#.#.##
...#.#...#.#.#.
##.#.#.###.###.
.........#.#.#.
.###.#####.#.#.
.#.............
####.#.#.###.##
.....#.#...#...
####.#.#.#.###.
.....#.#.#...#.
.#.#.###.###.##
.#.#.#.....#...
.#######.###.#.
.#.........#.#.

Кодировка, строки, u-строки и их преобразование

  • однобайтовый UTF в Python2

  • chr()/ord()

  • unicode() (нужна кодировка), обратное (используется LOCALE)

  • # coding: UTF в файле

Пример:

   1 # coding: utf
   2 a="Ку!"
   3 b=bytearray(a)
   4 u=unicode(a,"UTF")            # что будет без "UTF"?
   5 print "|".join(map(hex, b)) 
   6 print "|".join(a)
   7 print "|".join(u)
   8 print a,b,u

Исключения

  • JT: Ошибки выполнения в интерпретируемых ЯП

  • Ошибки Python — объекты
    • raise

    • Иерархия (например, ArithmeticErrorZeroDivisionError)

  • try: … except:

    • Обработка всех или заданных исключений
    • Клаузы else: и finally:

    • Параметры исключений (у разных разные)
  • raise Exception("QQ", "QKRQ", …)

Генераторы

  • Объекты-итераторы iter() из коллекции (.__iter__()) или из последовательности (.__getitem__())

    • .next() и StopIteration

    • Работа цикла for

  • Выражения-генераторы: для цикла лучше списков, но «одноразовые, что твои спорт-байкеры»
  • Генераторы: функции с yield вместо return

    • Параметрические: .send(par) вместо .next() ( ⇒ par = yield)

    • Управление: .close() и .throw(исключение)

JT: Отложенные вычисления и… «побочный эффект»

Файлы, ввод-вывод и связь с ОС

<!> См. разбор некоторых задач

Дисциплина оформления кода

Код чаще читают, чем пишут

Основная ссылка: pep-0008 — рекомендации к оформлению кода.

Анализаторы кода:

Личные рекомендации

  • В коротком коде ошибок меньше.
  • Ширина строки ограничена шириной мозга.
  • В нечитаемом коде ошибок нет: никто не знает, отчего он не работает.
  • Комментарии описывают задачу, а не решение.
  • Пробелы и пустые строки — вакуум, символы — атомы. Дышать вам.
  • Переписать код в 2 раза быстрее, чем написать, и в 22 раза быстрее, чем потом исправлять.

Рекомендации по превращению «кода на Basic» в «код на Python»

  • Конструкции языка

    • Несколько однотипных операций в столбик ⇒ работа с последовательностью
      • Например, множественное присваивание
    • Простой цикл ⇒ циклический конструктор
    • Несколько однотипных действий в коде ⇒ функция
    • Несколько однотипных функций ⇒ общая функция (duck typing!)
    • Пытаетесь различить свойства объектов из функции ⇒ дерево классов
  • Модули

    • Все задачи уже решены, если не в стандартных модулях, то в Python Package Index

    • Вам годится несколько модулей, не ленитесь и сравните API
    • Лучше сделать 10 файлов, чем 1 большой
    • Лучше сделать модуль, чем копировать файлы
    • Лучше сделать пакет, чем модуль-переросток
    • Опубликовал модуль — спас бобра помог людям

Ввод/вывод

  • Потоковый
    • Файловые объекты: open(), close(), read(), write(), readline() и итератор

    • Типизированные файлы: модуль struct.html

  • Сериализация: json.html и pickle.html

    • методы .dunp() и .load()

    • pickle умеет объекты!

    • json умеет не все hashable объекты в индексах

  • Индексированны доступ (БД): anydbm.html

    • dict-интерфейс

  • Спецфайлы: zipfile.html, json.html, configparser.html, …

Модули os и sys

  1. Обращайте внимание на пометку Availability:

  2. Обращайте внимание на пометку Deprecated

sys.html: Связь с системой: свойства самого python:

  • argv[]

  • exit()

  • stdin, stdout, stderr

  • getsizeof(), max…(), getrefcount()

  • ps1, ps2

os.html: Связь с операционной системой и обеспечение (относительной) кроссплатформенности:

  • Системные и другие libc-вызовы

    • Параметры процесса: environ[], chdir()/getcwd(), идентификаторы и флаги

    • Работа с файловым дескриптором вместо файлового объекта
    • Создание/удаление/переименование различных файловых объектов; получение и изменение их свойств
  • Манипуляция с именами файловых объектов (os.path.html)

  • Из используемого:
    • os.pipe(), os.tmpfile()

    • os.listdir(path)/os.makedirs(path[, mode])/os.removedirs(path)

    • os.stat(path), os.times()

    • os.urandom(n)

subprocess.html/subprocess32: Запуск подпроцессов — не слишком кроссплатформенная штука.

Модули-расширения языка

Долги по прошлой лекции:

  • Что есть полезного в __builtins__

    • В частности, getattr(), setattr() и hasattr()

  • Итераторы с явным индексом ограничены sys.maxint (i586: 2147483647)

  • Разбор задачи-однострочника:

    (DiffLet) Количество разных символов

    Ввести строку (слова, разделённые пробелами), и вывести через пробел вначале слова, состоящие из повторения единственного символа (если таковые имеются), затем — слова, образованные всего из двух символов в любом количестве и сочетании, затем — из трёх и т. д. Слова с одинаковым количеством символов выводить в порядке их появления в строке.

    Input:

        sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list
    Output:

    --> new list sorted key=None, cmp=None, reverse=False) sorted(iterable,

Функциональное программирование

Итераторы (itertools.html):

  • Бесконечные (.stop() или другое частичное вычисление)

  • .i*()-аналоги и некоторые другие манипуляции последовательностями

  • Комбинаторика

Надстройки над стандартными структурами данных

  • collections.html

    • deque — быстрая стеко-очередь

    • defaultdict — словарь со значением по умолчанию

    • OrderedDict — словарь с постоянным порядком ключей

    • Counter — словарь для подсчёта всего

  • Куча (heapq.html): «The interesting property of a heap is that a[0] is always its smallest element»

  • weakref.html: Слабые ссылки

Разное

Модули и классы

Долги за прошлую лекцию

  • Разбор какой-нибудь задачи ../05_ExceptionsGenerators

  • Предупредить о «парковке на слух»

Организация модуля

  • Поиск модуля: Кеш → finder → loader;
    • finder по умолчанию: sys.path

    • __import__()

  • Выполнение кода при загрузке модуля и при запуске его
    • Любой файл на Python — модуль
    • __name__ == "__main__"

  • .pyc и .pyo

  • Пакеты: __init__.py

    • Подпакеты, __all__ для указания пакетов при импорте *

    • относительный import (имя модуля: .*name)

  • Строка документации

Классы и объекты

JT

Объектное планирование и поддержка объектов со стороны языка.

объектно-ориентированный ЯП
  • модульность
  • инкапсуляция
  • наследование
  • полиморфизм

Классы — конструкторы объектов

Неожиданная статья про классы.

  • Класс: алгоритм создания объекта
  • Поля класса и поля объекта
    • Динамика создания полей
    • Правило видимости
  • Методы
    • Вызов метода: первый параметр — сам объект (self)

  • __init__(): когда вызывается

  • Напоминание о динамической типизаций
  • Строка документации

Перегрузка стандартных операций

  • Любая (?) операция — «синтаксический сахар» вокруг метода
  • Обзор спецметодов:

    • __repr__(), __str__()

    • Сравнения, __nonzero__()

    • __*attr__()

    • Контейнеры (__*item()__) и последовательности (__*slice__())

    • Арифметические операции
      • r-версии операций

      • i-версии операций

  • Мутное замечание насчёт old/new style, в частности, добычи спецметода

Оформление домашних заданий для объектного тестирования

  • Задание — модуль (по имени mod.py), тест — проверяющий код на Python (начинается с оператора import mod)

  • Использование unittest.html

Наследование и другие свойства ООП

Долги за прошлую лекцию:

  • Пакеты: неудобная для online-объяснения тема, проще посмотреть в modules.html

  • Разбор (возможно, только по смыслу) задач SubModules и GuessSigns

Наследование

  • Простое: class B(A):

    • Правила видимости полей, вызов «чужих» методов при необходимости
      • пример
    • рекуррентный вызов базовый_класс.__init__(self) при инициализации

      • пример
    • Порождение объектов (например, при __add__) при помощи self.__class__

    • Защита полей от случайного доступа с помощью «__» (a.__field в классе C превращается в a._C__field)

  • Множественное
    • старые классы: дерево

JT:

  • техника объектного планирования с деревом классов
  • «дешевизна» классов в python

Исключения как классы

См. classes.html

  • Зачем исключениям иерархия

Старые и новые классы

  • Главная проблема старых классов: тип «class»

    • (и другие: замкнутый граф наследования, спецметоды, …)
  • Новые классы: (Python2: class C(object):)

  • Просто «type» и объект этого типа

  • Ещё более (!) гибкий:

    • объект.__new__(self_класс, …)

    • __getattribute__

    • __slots__ (общие поля всех объектов класса)

    • Дескрипторы (Raymond Hettinger растолковывает)

      • это такой тип поля, для которого перегружаются __get__(), __set__() и __delete__() (а при вызове обращаются обратно к классу)

      • синтаксический сахар (и сверх того!) относительно __getattribute__()

  • Множественное наследование: C3 MRO

  • Метаклассы

У меня от всего этого мозги закукливаются, for TrueЪ probgammers only -- FrBrGeorge 2014-11-28 15:35:41

Ещё ссылки

Декораторы

Декоратор — это функция, возвращающая функцию. Нужна для красоты.

Повторное использовние, декораторы, оператор with

Сборочное программирование и повторное использование

  • Мечта: сборочное программирование. Повторное использование (и, внезапно, наше ejudge-тестирование): просто алгоритмы (вход-выход), unix way/Microsoft way. ООП. Повторно используемые библиотеки классов. Внезапно, Docker (повторное использование контейнеризованных приложений).
  • Алгоритмы + структуры данных = программы. More than this!
  • Аспектно-ориентированное программирование.
  • Веб-разработка: статические сайты из ФС, немного включенной динамики (PHP), много динамики (...)
  • Django: роутинг запросов по шаблонам (вместо ФС), парсинг URI на параметры, view как функция.

Декораторы

  • Определение, синтаксис, смысл
  • Пример с @staticmethod
  • Пример из Django (декоратор login_required, общий декоратор under_construction).

Оператор with. ContextManager

  • Проблема и варианты решения вручную
  • ContextManager и with

  • библиотека contextlib
  • декораторы contextmanager, closing

Что дальше?

Мелочи и подчистка

Вопросы быстродействия

  • 1 ms vs. 1 µs
  • Быстродействие и ЗБЧ
  • Быстродействие и вычислительная сложность
  • Быстродействие и дзен Python (см. далее)
  • Действительные случаи потери быстродействия

Python Patterns - An Optimization Anecdote (довольно старое эссе Гвидо, здесь он ещё любил reduce() ;) ):

  • Rule number one: only optimize when there is a proven speed bottleneck. Only optimize the innermost loop. (This rule is independent of Python, but it doesn't hurt repeating it, since it can save a lot of work. :) )

  • Small is beautiful. Given Python's hefty charges for bytecode instructions and variable look-up, it rarely pays off to add extra tests to save a little bit of work.
  • Use intrinsic operations. An implied loop in map() is faster than an explicit for loop; a while loop with an explicit loop counter is even slower.

  • Avoid calling functions written in Python in your inner loop. This includes lambdas. In-lining the inner loop can save a lot of time.
  • Local variables are faster than globals; if you use a global constant in a loop, copy it to a local variable before the loop. And in Python, function names (global or built-in) are also global constants!
  • Try to use map(), filter() or reduce() to replace an explicit for loop, but only if you can use a built-in function: map with a built-in function beats for loop, but a for loop with in-line code beats map with a lambda function!

  • Check your algorithms for quadratic behavior. But notice that a more complex algorithm only pays off for large N - for small N, the complexity doesn't pay off. In our case, 256 turned out to be small enough that the simpler version was still a tad faster. Your mileage may vary - this is worth investigating.
  • And last but not least: collect data. Python's excellent profile module can quickly show the bottleneck in your code. if you're considering different versions of an algorithm, test it in a tight loop using the time.clock() function.

/!\ Разбор каких-то задач?

Дзен Python

import this:

  • The Zen of Python, by Tim Peters (structured by FrBrGeorge CO)

    1. Beautiful is better than ugly.
    2. Explicit is better than implicit.
    3. Simple is better than complex.
      • Complex is better than complicated.
    4. Flat is better than nested.
    5. Sparse is better than dense.
    6. Readability counts.
    7. Special cases aren't special enough to break the rules.
      • Although practicality beats purity.
    8. Errors should never pass silently.
      • Unless explicitly silenced.
    9. In the face of ambiguity, refuse the temptation to guess.
    10. There should be one — and preferably only one — obvious way to do it.
      • Although that way may not be obvious at first unless you're Dutch.
    11. Now is better than never.
      • Although never is often better than right now.

    12. If the implementation is hard to explain, it's a bad idea.
      • If the implementation is easy to explain, it may be a good idea.

    13. Namespaces are one honking great idea -- let's do more of those!

Дальнейшее движение

  • Изучение алгоритмического программирования на Python:
  • Инструментальная разработка и промышленное программирование
  • «Академическое» программирование
  • Сам Python и его реализации

EE: import antigravity

LecturesCMC/PythonIntro2014/FullPlan (последним исправлял пользователь FrBrGeorge 2015-07-02 18:26:18)