Сводный план лекций по спецкурсу «Язык программирования 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
- Любые функции (методы) применимы к любым объектам
- Если в процессе выполнения происходит обращение к несуществующему объекту (полю), активизируется исключение
- Проверка существования объекта (поля) происходит в момент обращения к енму
(дополнительно) Все операции над объектами (типа +, [ , () и т. п.) — спецметоды объектов
Логические выражения
Сравнение, в т. ч. сравнение любого объекта с любым, операция 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 на примере задачи поиска.
Решние домашних заданий
- Использование редактора:
- Как оформлять и посылать Д/З
Ввод/вывод (input() и raw_input())
правила оформления и принципы выполнения Д/З
Стандартные типы данных и выражения-конструкторы
Дополнения к предыдущей лекции
- О неэстетичности цикла с пост-условием
Условное выражение 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 в файле
Кодировки, исключения и генераторы
Долги за прошлую лекцию:
- Что такое «передача параметров по соиспользованию»?
- Защита от «побочного эффекта»:
⇒ предварительный разбор лексем, выделение и классификация идентификаторов. Доказательство: 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 в файле
Пример:
Исключения
JT: Ошибки выполнения в интерпретируемых ЯП
- Ошибки Python — объекты
raise
Иерархия (например, ArithmeticError ⊃ ZeroDivisionError)
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 — рекомендации к оформлению кода.
Анализаторы кода:
Статический анализ: pyflakes, …
Личные рекомендации
- В коротком коде ошибок меньше.
- Ширина строки ограничена шириной мозга.
- В нечитаемом коде ошибок нет: никто не знает, отчего он не работает.
- Комментарии описывают задачу, а не решение.
- Пробелы и пустые строки — вакуум, символы — атомы. Дышать вам.
Переписать код в 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
Обращайте внимание на пометку Availability:
Обращайте внимание на пометку 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) Количество разных символов
Ввести строку (слова, разделённые пробелами), и вывести через пробел вначале слова, состоящие из повторения единственного символа (если таковые имеются), затем — слова, образованные всего из двух символов в любом количестве и сочетании, затем — из трёх и т. д. Слова с одинаковым количеством символов выводить в порядке их появления в строке.
sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list
--> new list sorted key=None, cmp=None, reverse=False) sorted(iterable,
Функциональное программирование
filter(), map(), reduce()
Гвидо и reduce(): в блоге, на слэшдоте
lambda и списковые конструкторы
functools.html: partial()
Итераторы (itertools.html):
Бесконечные (.stop() или другое частичное вычисление)
.i*()-аналоги и некоторые другие манипуляции последовательностями
- Комбинаторика
Надстройки над стандартными структурами данных
deque — быстрая стеко-очередь
defaultdict — словарь со значением по умолчанию
OrderedDict — словарь с постоянным порядком ключей
Counter — словарь для подсчёта всего
Куча (heapq.html): «The interesting property of a heap is that a[0] is always its smallest element»
weakref.html: Слабые ссылки
Разное
inspect.html: анализ кода
«Массивы» и проблемы представления: array.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
super(класс) (Raymond Hettinger с восторгом раскрывает эту тему)
У меня от всего этого мозги закукливаются, for TrueЪ probgammers only -- FrBrGeorge 2014-11-28 15:35:41
Ещё ссылки
- Статьи на Хабре:
Про дескрипторыперевод статьи Раймонда, важное дополнение;
Вообще (тысячи их)
Декораторы
Декоратор — это функция, возвращающая функцию. Нужна для красоты.
- Пример, где нужна красота: метод класса (unbound) vs. метод объекта
И вот: @property, @classmethod, @staticmethod
Две статьи на Хабре: Понимаем декораторы и Понимаем параметрические декораторы
Повторное использовние, декораторы, оператор 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
Что дальше?
Мелочи и подчистка
eval() и exec(), полная версия (simple_stmts.html, functions.html, functions.html)
«TypeError: media_is_eligible() takes at least 2 arguments (2 given)»
- …
Вопросы быстродействия
- 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)
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- 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.
- Now is better than never.
Although never is often better than right now.
- 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.
- Namespaces are one honking great idea -- let's do more of those!
Дальнейшее движение
- Изучение алгоритмического программирования на Python:
Проект «Interactivepython»: Problem Solving with Algorithms and Data Structures и перевод (!): http://aliev.me/runestone/ (via Иван Морозов)
- Инструментальная разработка и промышленное программирование
- «Академическое» программирование
- Сам Python и его реализации
EE: import antigravity