Ещё немного теории
Выходим на новый
уровень
Структуры
данных
Эта глава описывает подробнее некоторые вещи, которые вы уже изучили, а также раскрывает некоторые новые темы.
Подробнее о списках
У типа данных список также имеются не описанные ранее методы. Ниже приведены все методы объекта типа список:
list.append(x) Добавить элемент к концу списка; эквивалент list[len(list):] = [x]
list.extend(L) Расширить список за счёт добавления всех элементов переданного списка; эквивалентно list[len(list):] = L.
list.insert(i, x) Вставить элемент в указанную позицию. Первый аргумент — это индекс того элемента, перед которым требуется выполнить операцию вставки, поэтому вызов list.insert(0, x) вставляет элемент в начало списка, а list.insert(len(list), x) эквивалентно list.append(x).
list.remove(x) Удалить первый найденный элемент из списка, значение которого — x. Если элемент не найден, генерируется ошибка.
list.pop([i]) Удалить элемент, находящийся на указанной позиции в списке, и возвратить его. Если индекс не указан, list.pop() удаляет и возвращает последний элемент списка. (Квадратные скобки вокруг i в сигнатуре метода означают, что параметр необязателен, а не необходимость набора квадратных скобок в этой позиции. Вы часто будете встречать такую нотацию в Справочнике по библиотеке.)
list.index(x) Вернуть индекс первого найденного в списке элемента, значение которого равно x. Если элемент не найден, генерируется ошибка.
list.count(x) Вернуть значение сколько раз, x встречается в списке.
list.sort() Сортировать элементы списка, на месте.
list.reverse() Обратить порядок элементов списка, на месте.
Пример, использующий большинство методов списка:
>>> a = [66.25, 333, 333,
1, 1234.5]
>>> print(a.count(333),
a.count(66.25), a.count('x'))
2 1 0
>>> a.insert(2,
-1)
>>> a.append(333)
>>> a
[66.25, 333, -1, 333, 1, 1234.5, 333]
>>> a.index(333)
1
>>> a.remove(333)
>>> a
[66.25, -1, 333, 1, 1234.5, 333]
>>> a.reverse()
>>> a
[333, 1234.5, 1, 333, -1, 66.25]
>>> a.sort()
>>> a
[-1, 1, 66.25, 333, 333, 1234.5]
Использование списка в качестве стека
Методы списков позволяют легко использовать список в
качестве стека, где последний добавленный элемент становится первым полученным
(„первый вошёл - последний вышел“). Чтобы положить элемент на вершину стека,
используйте метод append(). Для получения элемента с вершины стека - метод
pop() без указания явного индекса. Например:
>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]
Использование списка в качестве очереди
Вы можете без труда использовать список также и в качестве очереди, где первый добавленный элемент оказывается первым полученным („первый вошёл - первый вышел“). Чтобы добавить элемент в конец очереди, используйте метод append(), а чтобы получить элемент из начала очереди - метод pop() с нулём в качестве индекса. Например:
>>> queue = ["Eric", "John", "Michael"]
>>> queue.append("Terry") # Прибыл Terry
>>> queue.append("Graham") # Прибыл Graham
>>> queue.pop(0)
'Eric'
>>> queue.pop(0)
'John'
>>> queue
['Michael', 'Terry', 'Graham']
Списковые сборки
Использование метода списковой сборки — легкий способ создать список на основе последовательности. В большинстве случаев он применяется для создания списков, в которых каждый элемент является результатом некой операции, произведённой над каждым членом последовательности, или для создания выборок из тех элементов, которые удовлетворяют определённому условию.
Любая списковая сборка состоит из выражения, за которым следует оператор for, а затем ноль или более операторов for или if. Результатом станет список, получившийся через вычисление выражения в контексте следующих за ним операторов for и/или if. Если в результате вычисления выражения строится кортеж, его нужно явно обернуть в скобки.
В следующем примере на основе списка чисел создаётся список, где каждое число утроено:
>>> vec
= [2, 4, 6]
>>> [3*x for x in vec]
[6, 12, 18]
Применим фантазию:
>>> [[x, x**2] for x in vec]
[[2, 4], [4, 16], [6, 36]]
Здесь мы вызываем метод по очереди с каждым элементом последовательности:
>>> freshfruit
= [' banana', ' loganberry ', 'passion fruit ']
>>> [weapon.strip()
for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
Используя оператор if, мы можем отфильтровать поток:
>>> [3*x for x in vec if x
> 3]
[12, 18]
>>> [3*x for x in vec if x
< 2]
[]
Кортежи могут быть созданы без использования скобок, но не в этом случае:
>>> [x, x**2 for x in vec] # ошибка - для кортежей необходимы скобки
File "<stdin>", line
[x, x**2 for x in
vec]
^
SyntaxError: invalid syntax
>>> [(x, x**2) for x in
vec]
[(2, 4), (4, 16), (6, 36)]
Вот несколько вложенных циклов for и ещё кое-какое забавное поведение:
>>> vec1 = [2, 4, 6]
>>> vec2 = [4, 3, -9]
>>> [x*y for x in vec1 for
y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18,
-54]
>>> [x+y for x in vec1 for
y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
>>> [vec1[i]*vec2[i]
for i in range(len(vec1))]
[8, 12, -54]
Списковые сборки могут применяться в сложных выражениях и вложенных функциях[34]:
>>> [str(round(355/113,
i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416',
'3.14159']
Вложенные списковые сборки
Если вы в состоянии это переварить: списковые сборки могут быть вложенными. Но как любой мощный инструмент, их следует использовать с осторожностью.
Представьте нижеследующий пример матрицы 3x3 в виде списка, содержащего три других списка, по одному в ряд:
>>> mat = [
... [1, 2, 3],
... [4, 5, 6],
... [7, 8, 9],
... ]
Чтобы поменять строки и столбцы местами, можно использовать такую списковую сборку:
>>> print([[row[i]
for row in mat] for i in [0, 1, 2]])
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Применяя вложенные списковые сборки, необходимо помнить об важной вещи:
Во избежание недоразумений при конструировании вложенных списковых сборок, читайте их справа налево.
Более многословная, с использованием операторов, версия примера может служить иллюстрацией:
for i in [0, 1, 2]:
for row in mat:
print(row[i],
end="")
print()
В реальных случаях лучше использовать встроенные функции вместо сложных выражений. В нашем случае поможет функция zip():
>>> list(zip(*mat))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
В разделе Распаковка списков параметров описано предназначение звёздочки в этих строках.
Оператор del
Существует способ удалить элемент, указывая его индекс,
а не его значение: оператор del. В отличие от метода pop(), он не возвращает
значения. Оператор del может также использоваться для удаления срезов из списка
или полной очистки списка (что мы делали ранее через присваивание пустого
списка срезу). Например:
>>> a = [-1, 1, 66.25, 333,
333, 1234.5]
>>>
>>> a
[1, 66.25, 333, 333, 1234.5]
>>>
>>> a
[1, 66.25, 1234.5]
>>>
>>> a
[]
del может быть также использован для удаления переменных полностью:
>>> del a
Ссылка на имя a в дальнейшем вызовет ошибку (по крайней мере до тех пор, пока с ним не будет связано другое значение). Позже мы с вами узнаем другие способы использования del.
Кортежи и последовательности
Мы видели, что списки и строки поддерживают много привычных свойств, таких как индексирование и операция получения срезов. Существует два подвида типов данных последовательность (sequence) (см. Справочник по библиотеке — Последовательности), и поскольку Python — развивающийся язык, со временем могут быть добавлены другие последовательные типы данных. Итак, существует также и другой, достойный рассмотрения, стандартный последовательный тип данных: кортеж.
Кортеж состоит из некоторого числа значений разделённых запятыми, например:
>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Кортежи могут быть вложенными:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3,
4, 5))
Как видите, кортежи на выводе всегда заключены в скобки, таким образом вложенные кортежи интерпретируются корректно; они могут быть введены и с обрамляющими скобками и без, тем не менее в любом случае скобки чаще всего необходимы (если кортеж — часть более крупного выражения).
Кортежи можно использовать в различных целях. Например: (x, y) пары координат, записи о рабочих из базы данных, и так далее. Кортежи, как и строки, неизменяемы: невозможно присвоить что-либо индивидуальным элементам кортежа (однако, вы можете симулировать большинство схожих эффектов за счёт операций срезов и конкатенации). Также можно создать кортежи, содержащие изменяемые объекты, такие как списки.
Определённая проблема состоит в конструировании кортежей, состоящих из нуля или одного элемента: в синтаксисе языка есть дополнительные хитрости, позволяющие достигнуть этого. Пустые кортежи формируются за счёт пустой пары скобок; кортеж с одним элементом конструируется за счёт запятой, следующей за числом (единственное значение не обязательно заключать в скобки). Необычно, но эффективно. Например:
>>> empty = ()
>>> singleton = 'hello', # <-- обратите внимание на замыкающую запятую
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)
Выражение t = 12345, 54321, 'hello!' является примером упаковки кортежей (tuple packing): значения 12345, 54321 и 'hello!' упаковываются в кортеж вместе. Обратная операция также возможна:
>>> x, y, z = t
Такое действие называется, довольно удачно, распаковкой последовательности (sequence unpacking). Для распаковки на левой стороне требуется список переменных с количеством элементов равным длине последовательности. Обратите внимание, что множественное присваивание на самом деле является лишь комбинацией упаковки кортежа и распаковки последовательности.
Здесь есть некоторая асимметрия: упаковка нескольких значений всегда создаёт кортеж, а распаковка работает для любой последовательности.
Множества
Python имеет также тип данных множество. Множество — это неупорядоченная коллекция без дублирующихся элементов. Основные способы использования — проверка на вхождение и устранение дублирующихся элементов. Объекты этого типа поддерживают обычные математические операции над множествами, такие как объединение, пересечение, разность и симметрическая разность.
Для создания множеств могут быть использованы фигурные скобки или функция set(). Заметьте: Для создания пустого множества нужно использовать set(), а не {}: в последнем случае создаётся пустой словарь (dictionary) — тип данных, который мы обсудим в следующем разделе.
Продемонстрируем работу со множествами на небольшом примере[35]:
>>> basket = {'apple',
'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)
{'orange', 'banana', 'pear', 'apple'}
>>> fruit_list = ['apple',
'orange', 'apple', 'pear', 'orange', 'banana']
>>> fruit = set(fruit_list) # создать множество на основе данных из списка (заметьте исчезновение дубликатов -перев.)
>>> fruit
{'orange', 'pear', 'apple', 'banana'}
>>> fruit
= {'orange', 'apple'} # синтаксис {} эквивалентен [] у списков
>>> fruit
{'orange', 'apple'}
>>> 'orange' in fruit # быстрая проверка на вхождение
True
>>> 'crabgrass' in fruit
False
>>> # Демонстрация операций со множествами на примере букв из двух слов
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # уникальные буквы в a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b # буквы в a но не в b
{'r', 'd', 'b'}
>>> a | b # все буквы, которые встречаются в a или в b
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b # буквы, которые есть и в a и в b
{'a', 'c'}
>>> a ^ b # буквы в a или в b, но не в обоих
{'r', 'd', 'b', 'm', 'z', 'l'}
Как и у списков, у множеств существует синтаксис сборок:
>>> a = {x for x in
'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}
Словари
Другой полезный встроенный в Python тип данных — это словарь (dictionary) (см. Справочник по библиотеке — Связывающие типы). Словари иногда встречаются в других языках в виде «ассоциативных записей» или «ассоциативных массивов». В отличие от последовательностей, которые индексируются по диапазону чисел, словари индексируются по ключам (keys), которые, в свою очередь, могут быть любого неизменяемого типа; строки и числа всегда могут быть ключами. Кортежи могут быть ключами только если они составлены из строк, чисел или кортежей; если кортеж содержит какой-либо изменяемый объект, явно или неявно, то он не может быть использован в качестве ключа. Вы не можете использовать списки в роли ключей, поскольку списки могут быть изменены на месте присваиванием по индексу, присваиванием по срезу или такими методами как append() и extend().
Лучше всего воспринимать словарь как неупорядоченный набор пар ключ: значение с требованием, чтобы ключи были уникальны (в пределах одного словаря). Пара скобок создает пустой словарь: {}. Указывая разделённый запятыми список пар ключ: значение внутри скобок, вы задаёте содержимое словаря; в таком же формате словарь можно вывести.
Главные операции над словарём — это сохранение значения с каким-либо ключом и извлечение значения по указанному ключу. Также возможно удалить пару ключ: значение используя оператор del. Если вы сохраняете значение используя ключ, который уже встречается в словаре — старое значение, ассоциированное с этим ключом, стирается. Извлечение значения по несуществующему ключу вызывает ошибку.
Выполнение конструкции list(d.keys()) с объектом словаря возвращает список всех ключей, использующихся в словаре, в случайном порядке (если вы хотите отсортировать его, к списку ключей можно применить функцию sorted()). Чтобы проверить, содержит ли словарь определённый ключ, используйте ключевое слово in.
Вот небольшой пример использования словарей:
>>> tel
= {'jack': 4098, 'sape': 4139}
>>> tel['guido']
= 4127
>>> tel
{'sape': 4139, 'guido': 4127,
'jack': 4098}
>>> tel['jack']
4098
>>>
>>> tel['irv']
= 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack':
4098}
>>> list(tel.keys())
['irv', 'guido', 'jack']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> 'guido' in tel
True
>>> 'jack' not in tel
False
Конструктор dict() строит словарь непосредственно на основе пар ключей и значений, где каждая пара представлена в виде кортежа. Когда пары могут быть сформированы шаблоном, списковые сборки помогут описать список пар более компактно.
>>> dict([('sape',
4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098,
'guido': 4127}
В дополнение ко всему этому, для создания словарей из произвольных выражений для ключей и значений, могут быть использованы словарные сборки:
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
Позже в учебнике мы изучим выражения-генераторы (Generator Expressions), которые даже лучше подходят для снабжения конструктора dict() парами ключ-значение.
Если ключи являются простыми строками, иногда легче описать пары используя именованные параметры:
>>> dict(sape=4139,
guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098,
'guido': 4127}
Организация циклов
При организации перебора элементов из словаря ключ и соответствующее ему значение могут быть получены одновременно посредством метода items().
>>> knights
= {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for
k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave
Функция enumerate() поможет пронумеровать элементы перебираемой в цикле последовательности:
>>> for
i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe
Для того, чтобы организовать цикл параллельно для двух или более последовательностей, элементы можно предварительно сгруппировать функцией zip()[36].
>>> questions
= ['name', 'quest', 'favorite color']
>>> answers
= ['lancelot', 'the holy grail', 'blue']
>>> for
q, a in zip(questions, answers):
... print('What is
your {0}? It is {1}.'.format(q,
a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.
Изменить порядок следования последовательности на обратный поможет функция reversed().
>>> for
i in reversed(range(1, 10, 2)):
... print(i)
...
9
7
5
3
1
Для организации цикла по отсортированной последовательности можно применить функцию sorted(), которая возвращает отсортированный список, оставляя исходный без изменений.
>>> basket = ['apple',
'orange', 'apple', 'pear', 'orange', 'banana']
>>> for
f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear
Подробнее об условиях
Условия в операторах if и while могут содержать любые операции, а не только операции сравнения.
Операции сравнения in и not in проверяют, встречается значение в последовательности или нет. Операции is и is not проверяют, не являются ли два объекта на самом деле одним и тем же (это имеет смысл лишь для изменяемых объектов, таких как списки). Все операции сравнения имеют один и тот же приоритет, меньший чем у любых операций над числами.
Сравнения можно объединять в цепочки. Например, a < b == c проверяет, меньше ли a чем b и, сверх того, равны ли b и c.
Сравнения могут быть скомбинированы с использованием булевых операций and и or, а результат сравнения (или любого другого булева выражения) можно отрицать используя not. Эти операции имеют меньший приоритет, чем у операций сравнения; среди них у not высший приоритет, а у or — низший, поэтому A and not B or C эквивалентно (A and (not B)) or C. Как всегда, явно заданные скобки помогут выразить желаемый порядок выполнения операций.
Булевы операции and и or — это так называемые коротящие операции[37] (short-circuit operators): их операнды вычисляются слева направо и вычисление заканчивается как только результат становится определён (очевиден). Например, если A и C истинны, а B — ложно, в условии A and B and C выражение C не вычисляется. Коротящая операция возвращает последний элемент, который был вычислен, что может быть применено не только в целях задания логики.
Можно присвоить результат сравнения, или другого булева выражения, переменной. Например,
>>> string1, string2,
string3 = '', '
>>> non_null = string1 or
string2 or string3
>>> non_null
'Trondheim'
Заметьте, что в Python (в отличие от C) присваивание не может использоваться внутри выражений. Программисты на C могут возмутиться по этому поводу, но на самом деле это позволяет избежать ряда проблем, обычного для программ на C: указания оператора присваивания (=) в выражении, вместо предполагавшегося сравнения (==).
Сравнение последовательностей и других типов
Объекты последовательностей можно сравнивать с другими объектами с тем же типом последовательности. Сравнение использует лексикографический порядок: сравниваются первые два элемента, и если они различны — результат сравнения определён; если они равны, сравниваются следующие два элемента и так далее до тех пор, пока одна из последовательностей не будет исчерпана. Если сравниваемые два элемента сами являются последовательностями одного типа, лексикографическое сравнение происходит в них рекурсивно. Если все элементы обоих последовательностей оказались равны, последовательности считаются равными. Если одна последовательность оказывается стартовой последовательностью другой, более короткая последовательность считается меньшей. Лексикографическое упорядочивание строк использует порядок в таблице Unicode для индивидуальных символов. Несколько примеров сравнений между однотипными последовательностями:
(1, 2, 3) < (1, 2, 4)
[1, 2, 3] < [1, 2, 4]
"Паскаль" < "Питон" < "Си" < "Си++"
(1, 2, 3, 4) < (1, 2, 4)
(1, 2) < (1, 2, -1)
(1, 2, 3) == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'), 4) < (1, 2, ('abc', 'a'))
Обратите внимание, что сравнение объектов различных типов операциями < или > позволено, если объекты имеют соответствующие методы сравнения. Например, смешанные числовые типы сравниваются в соответствии с их численными значениями, так что 0 равен 0.0 и т.д. В противном случае интерпретатор, прервав процесс сортировки, возбудит исключение TypeError.
Модули
Если вы выйдете из интерпретатора и зайдёте в него снова, то все определённые вами имена (функции и переменные) будут потеряны. По этой причине, если вы захотите написать несколько более длинную программу, вам лучше использовать текстовый редактор для подготовки ввода для интерпретатора и запускать последний в режиме файлового ввода. Это называется созданием сценария. Если ваша программа становится обширнее, вы можете предпочесть разделить её на несколько файлов для удобства эксплуатации. Также вы можете захотеть использовать сразу в нескольких программах некоторую полезную функцию, написанную вами, не копируя её определение каждый раз.
В языке Python можно поместить требуемые определения в файл и использовать их в сценариях или в интерактивном режиме интерпретатора. Такой файл называется модулем (module). Определения из модуля могут быть импортированы в других модулях, либо в главном модуле (собрание переменных, к которым есть доступ в сценарии, который непосредственно запускается, и в режиме интерактивном режиме).
Модуль — это файл, содержащий определения и операторы Python. Именем файла является имя модуля с добавленным суффиксом .py. Внутри модуля, имя модуля (в качестве строки) доступно в виде значения глобальной переменной с именем __name__. Например, используя ваш любимый текстовый редактор, создайте в текущем каталоге файл с именем fibo.py со следующим содержимым:
"""Модуль вычисления чисел Фибоначчи"""
def fib(n): # вывести числа Фибоначчи вплоть до n
a, b = 0, 1
while b < n:
print(b, end='
')
a, b = b, a+b
print()
def fib2(n): # вернуть числа Фибоначчи вплоть до n
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
return result
Теперь можно войти в интерпретатор Python и импортировать этот модуль следующей командой:
>>> import fibo
Это действие не переводит имена определённых в модуле функций в текущую таблицу символов, а лишь имя модуля fibo. Используя имя модуля, вы можете получить доступ к функциям:
>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
Если вы собираетесь использовать функцию часто, можно присвоить её локальному имени:
>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Подробнее о модулях
Помимо определений функций модуль может содержать исполняемые операторы. Назначение этих операторов — инициализация модуля: они выполняются при первом импортировании модуля где-либо[38].
Каждый модуль имеет свою собственную таблицу символов, которая используется в качестве глобальной всеми определёнными в модуле функциями. Таким образом, автор модуля может использовать глобальные символы в модуле, не опасаясь неожиданных совпадений с глобальными переменными пользователя. С другой стороны, если вы знаете, что делаете, можно сослаться на глобальные переменные модуля, пользуясь той же нотацией, которая применялась для ссылок на его функции: <имя_модуля>.<имя_элемента>.
Модули могут импортировать другие модули. Не требуется указывать все операторы import в начале модуля (или сценария, с той же целью), но обычно так и делается. Имена из импортированного модуля добавляются в глобальную таблицу символов модуля его импортирующего.
Есть вариант оператора import, который переносит имена из модуля прямо в таблицу символов импортирующего модуля. Например:
>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
При этом имя самого модуля, из которого переносятся имена элементов, не добавляется в локальную таблицу символов (так, в этом примере, имя fibo не определено)
И есть даже способ импортировать все имена, которые определяет данный модуль:
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Импортируются все имена, кроме тех, которые начинаются на подчёркивание (_). В большинстве случаев программисты на Python не используют эту возможность, поскольку она внедряет в интерпретатор целый набор новых неизвестных имён и может скрыть некоторые объекты, которые вы уже определили.
Для повышения эффективности, каждый модуль импортируется лишь единожды за сеанс работы с интерпретатором. Поэтому, если вы изменили ваши модули, вам придётся перезапустить интерпретатор. Или, если вам нужно перезагрузить конкретный модуль, можно использовать imp.reload() таким образом: import imp; imp.reload(<имя_модуля>)
Выполнение модулей в качестве сценариев
Когда вы запускаете модуль Python в виде
python fibo.py <параметры>
то код в этом модуле будет исполнен в момент его импортирования, но значением __name__ будет строка "__main__". Это значит, что добавляя следующий код в конец сценария:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
вы можете сделать возможным запуск файла и в качестве сценария, и в качестве импортируемого модуля. Это возможно, поскольку разбирающий командную строку код выполняется только при исполнении модуля как основного (main) файла:
$ python fibo.py 50
1 1 2 3 5 8 13 21 34
Если модуль импортируется, код не будет выполнен:
>>> import fibo
>>>
Такой приём часто используется, чтобы предоставить удобный пользовательский интерфейс к модулю или для тестирования (выполнение модуля в качестве сценария запускает набор тестов).
Путь поиска модулей
Если импортируется модуль с именем spam, интерпретатор ищет файл с именем spam.py в текущем каталоге, а затем в каталогах, указанных в переменной окружения PYTHONPATH. У неё такой же синтаксис, как и у переменной шелла PATH, которая, в свою очередь, является перечислением каталогов. Когда переменная PYTHONPATH не установлена, или файл не найден в описанных в ней местах, поиск продолжается по пути по умолчанию, зависящему от указанного при установке; на Unix это обычно .:/usr/local/lib/python.
В действительности поиск модулей производится в списке каталогов в переменной sys.path, которая обычно содержит: каталог, в котором находится сценарий на входе (или текущий каталог), PYTHONPATH и умолчанием для каталога, указанного при установке. Это позволяет программам на Python (которые знают, что делают) изменять или подменять путь поиска модулей. Заметьте: поскольку каталог, содержащий запускаемый вами сценарий, также находится в пути поиска, важно, чтобы в нем не было сценариев с именем стандартного модуля. Иначе, когда этот модуль будет импортироваться, Python будет пытаться загрузить в виде модуля сам сценарий, что в большинстве случаев вызовет ошибку. Для более подробной информации обратитесь к разделу Стандартные модули.
„Скомпилированные“ файлы Python
Интерпретатор Python применяет один важный приём для ускорения запуска программы: если в каталоге, где располагается файл с некоторым модулем spam.py, находится также файл spam.pyc, предполагается, что это уже скомпилированная в байт-код („byte-compiled“) версия модуля spam. В файле spam.pyc зафиксировано время изменения файла spam.py версии, использовавшейся для создания spam.pyc. Если версии не совпадают — файл .pyc игнорируется.
В обычном случае, вам не нужно ничего делать для создания файла spam.pyc. Каждый раз, когда spam.py успешно компилируется, предпринимается попытка записать скомпилированную версию в spam.pyc. Не считается ошибкой, если попытка неудачна: если по какой-либо причине файл не записан полностью, результирующий файл spam.pyc будет считаться некорректным и по этой причине в дальнейшем игнорироваться. Содержимое файла spam.pyc платформо-независимо, благодаря чему каталог модулей Python может использоваться параллельно машинами с различной архитектурой.
Несколько советов экспертам:
Когда интерпретатор Python запускается с лагом -O, в файлах .pyo сохраняется сгенерированный оптимизированный код. На данный момент оптимизатор помогает не сильно — он лишь удаляет операторы assert. В случае использования -O оптимизируется весь байт-код (bytecode); файлы .pyc игнорируются, а файлы .py компилируются в оптимизированный байт-код.
Передача двух флагов -O интерпретатору Python (-OO) принуждает компилятор байт-кода выполнять оптимизации, в редких случаях результат выполнения которых оказывается некачественно функционирующей программой. На данный момент из байт-кода удаляются только строки __doc__, в результате получаются более компактные файлы .pyo. Поскольку некоторые программы могут рассчитывать на их (строк) доступность, следует использовать эту возможность только в том случае, если вы знаете что делаете.
Программа сама по себе не работает хоть сколь-нибудь быстрее, будучи прочитанной из файла .pyc или .pyo, чем если бы она была прочитана из файла .py. Единственный процесс, оказывающийся более быстрым при использовании файлов .pyc или .pyo — это скорость их подгрузки.
Если сценарий запущен из командной строки, его байт-код никогда не будет записан в файл .pyc или .pyo. Таким образом, время запуска сценария может быть уменьшено за счёт перемещения большей части его кода в модули или использования небольшого загрузочного сценария, импортирующего этот модуль. Кроме того, можно указывать файл .pyc или .pyo прямо в командной строке.
Можно иметь в наличии файл с именем spam.pyc (или spam.pyo, когда используется -O), не имея файла spam.py для того же модуля. Таким образом можно распространять библиотеки кода Python в том виде, из которого трудно восстановить исходный код.
Модуль compileall может создать файлы .pyc (или файлы .pyo, когда используется -O) для всех модулей в каталоге.
Стандартные модули
Python поставляется с библиотекой стандартных модулей, описанной в отдельном документе, Справочнике по библиотеке Python (далее — «Справочнику по библиотеке»). Некоторые модули встроены в интерпретатор. Они обеспечивают доступ к операциям, не входящим в ядро языка, и встроены для большей эффективности и предоставления доступа к основным средствам операционной системы, таким как системные вызовы (system calls). Набор таких модулей — выбор настройки, зависимый от используемой платформы. Например, модуль winreg предоставляется только на системах с Windows. Один конкретный модуль заслуживает большего внимания: модуль sys, встроенный в каждую версию интерпретатора Python. Переменные sys.ps1 и sys.ps2 определяют строки, использующиеся в качестве основного и вспомогательного приглашений:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = "Вводите: "
Вводите: print('Ох!')
Ох!
Вводите:
Эти две переменные определены только для интерактивного режима интерпретатора.
Переменная sys.path представляет из себя список строк, определяющий путь поиска модулей интерпретатора. Она инициализируется значением пути по умолчанию, взятым из переменной окружения PYTHONPATH, или встроенным значением по умолчанию, если PYTHONPATH не установлен. Вы можете изменить её значение, используя стандартные операции со списками:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
Функция dir()
Встроенная функция dir() используется для получения имён, определённых в модуле. Она возвращает отсортированный список строк:
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__displayhook__', '__doc__',
'__excepthook__', '__name__', '__stderr__',
'__stdin__', '__stdout__', '_getframe',
'api_version', 'argv',
'builtin_module_names', 'byteorder',
'callstats', 'copyright',
'displayhook',
'exc_info', 'excepthook',
'exec_prefix', 'executable', 'exit',
'getdefaultencoding', 'getdlopenflags',
'getrecursionlimit', 'getrefcount',
'hexversion', 'maxint', 'maxunicode',
'meta_path', 'modules', 'path', 'path_hooks',
'path_importer_cache',
'platform', 'prefix', 'ps1', 'ps2',
'setcheckinterval', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'settrace',
'stderr', 'stdin', 'stdout',
'version', 'version_info', 'warnoptions']
Будучи использованной без аргументов, функция dir() возвращает список имён, определённых в данный момент.
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib
= fibo.fib
>>> dir()
['__builtins__', '__doc__',
'__file__', '__name__', 'a', 'fib', 'fibo', 'sys']
Обратите внимание, что список состоит из имён всех типов: переменных, модулей, функций и т.д.
В возвращаемом функцией dir() списке не содержится встроенных функций и переменных. Если вы хотите получить их список, то они определены в стандартном модуле builtins:
>>> import builtins
>>> dir(builtins)
['ArithmeticError',
'AssertionError', 'AttributeError', 'BaseException', 'Buffer
Error', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Excep
tion', 'False', 'FloatingPointError',
'FutureWarning', 'GeneratorExit', 'IOError
', 'ImportError', 'ImportWarning',
'IndentationError', 'IndexError', 'KeyError',
'KeyboardInterrupt', 'LookupError',
'MemoryError', 'NameError', 'None', 'NotImp
lemented', 'NotImplementedError', 'OSError',
'OverflowError', 'PendingDeprecatio
nWarning', 'ReferenceError', 'RuntimeError',
'RuntimeWarning', 'StopIteration',
'SyntaxError', 'SyntaxWarning',
'SystemError', 'SystemExit', 'TabError', 'True',
'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', '
UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueE
rror', 'Warning',
'ZeroDivisionError', '__build_class__', '__debug__', '__doc__'
, '__import__', '__name__', 'abs',
'all', 'any', 'basestring', 'bin', 'bool', 'b
uffer', 'bytes', 'chr', 'chr8',
'classmethod', 'cmp', 'compile', 'complex', 'cop
yright', 'credits', 'delattr',
'dict', 'dir', 'divmod', 'enumerate', 'eval', 'ex
ec', 'exit', 'filter', 'float',
'frozenset', 'getattr', 'globals', 'hasattr', 'h
ash', 'help', 'hex', 'id', 'input',
'int', 'isinstance', 'issubclass', 'iter', '
len', 'license', 'list', 'locals',
'map', 'max', 'memoryview', 'min', 'next', 'o
bject', 'oct', 'open', 'ord', 'pow',
'print', 'property', 'quit', 'range', 'repr
', 'reversed', 'round', 'set',
'setattr', 'slice', 'sorted', 'staticmethod', 'st
r', 'str8', 'sum', 'super', 'trunc',
'tuple', 'type', 'vars', 'zip']
Пакеты
Пакеты — способ структурирования пространств имён (namespaces) модулей Python за счёт использования имён модулей, разделённых точками („dotted module names“). Например, имя модуля A.B означает — подмодуль[39] с именем B в пакете с именем A. Также как использование модулей позволяет авторам различных модулей не заботиться о пересекающихся именах среди глобальных переменных, использование именования через точку позволяет авторам многомодульных пакетов (таких как NumPy или Python Imaging Library) не заботиться о конфликтах имён модулей.
Допустим, вы собираетесь разработать набор модулей (пакет, package) для унифицированной работы со звуковыми файлами и звуковыми данными. Существует множество форматов звуковых файлов (обычно их можно распознать по расширению, например: .wav, .aiff, .au). Таким образом, вам может понадобиться создать и поддерживать разрастающуюся коллекцию модулей для конвертирования между различными форматами файлов. Также вам наверняка захочется иметь побольше операций для обработки звуковых данных (таких как смешивание, добавление эха, применение функции эквалайзера, создание искусственного стерео-эффекта), поэтому в дополнение к этому вы будете писать нескончаемый поток модулей для исполнения этих операций. Вот возможная структура вашего пакета (выраженная в терминологии иерархической файловой системы):
sound/ Пакет верхнего уровня
__init__.py Инициализация пакета работы со звуком (sound)
formats/ Подпакет для конвертирования форматов файлов
__init__.py
wavread.py (чтение wav)
wavwrite.py (запись wav)
aiffread.py (чтение aiff)
aiffwrite.py (запись aiff)
auread.py (чтение au)
auwrite.py (запись au)
...
effects/ Подпакет для звуковых эффектов
__init__.py
echo.py ( эхо )
surround.py ( окружение )
reverse.py ( обращение )
...
filters/ Подпакет для фильтров
__init__.py
equalizer.py ( эквалайзер )
vocoder.py ( вокодер )
karaoke.py ( караоке )
...
При импорте пакета Python ищет подкаталог пакета в каталогах, перечисленных в sys.path.
Файлы __init__.py необходимы для того, чтобы Python трактовал эти каталоги как содержащие пакеты. Это сделано во избежание нечаянного сокрытия правомерных модулей, встречающихся в дальнейшем по пути поиска, каталогами с часто используемыми именами, таким как "string". В наипростейшем случае файл __init__.py может быть пустым, но в более сложных может содержать код инициализации пакета или устанавливать значение описанной ниже переменной __all__.
Пользователи пакета могут импортировать из него конкретные модули, например:
import sound.effects.echo
Таким образом подгружается подмодуль sound.effects.echo. Ссылаться на него нужно используя его полное имя:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
Другой способ импортирования подмодуля:
from sound.effects import echo
Так тоже подгружается подмодуль echo, но теперь он доступен без префикса пакета, поэтому может использоваться следующим образом:
echo.echofilter(input, output, delay=0.7, atten=4)
И еще один вариант — прямое импортирование желаемой функции или переменной:
from sound.effects.echo import
echofilter
Опять же, таким образом подгружается подмодуль echo, но теперь его функция echofilter() может быть вызвана непосредственно:
echofilter(input, output, delay=0.7, atten=4)
Заметьте, что при использовании выражения from пакет import элемент, элементом может быть подмодуль (или подпакет) пакета или любое другое имя, определённое в пакете - например, функция, класс или переменная. Оператор import сначала проверяет, определён ли элемент в пакете; если нет — он трактует его как модуль и пытается загрузить. Если не удается его найти, порождается исключение ImportError.
Напротив, при использовании синтаксиса в стиле import элемент.подэлемент.подэлемент, все элементы кроме последнего должны быть пакетами; последний элемент может быть модулем или пакетом, но не может быть классом, функцией или переменной, определёнными в предыдущем элементе.
Импорт * из пакета
Что происходит, когда пользователь пишет from sound.effects import * ? В идеале, мы бы надеялись, что таким образом код выходит в файловую систему и находит какие подмодули существуют в пакете, импортируя их все. К сожалению, такой метод не очень хорошо работает на платформах Windows, поскольку у файловой системы не всегда есть корректная информация о регистре имён файлов. На этих платформах нет гарантированного способа узнать, нужно ли импортировать файл ECHO.PY в качестве модуля echo, Echo или ECHO. (Например, у Windows 95 есть назойливая привычка показывать имена всех файлов с заглавной буквы.) Ограничение DOS на имя файла в формате 8+3 добавляет забавную проблему, связанную с длинными именами модулей.
Единственный выход для автора пакета — предоставить его подробное содержание. Оператор import использует следующее соглашение: если в коде файла __init__.py текущего пакета определён список __all__, то он полагается списком имён модулей, которые нужно импортировать в случае from пакет import *. На совести автора поддержка этого списка в соответствующем состоянии в каждой новой версии пакета. Впрочем, авторы пакета могут его не поддерживать вообще, если не видят смысла в импортировании * из их пакета. Например, файл sounds/effects/__init__.py может содержать следующий код:
__all__ = ["echo", "surround", "reverse"]
Это будет значить, что выражение from sound.effects import * импортирует три именованных подмодуля из пакета sound.
Если список __all__ не определён, оператор from
Sound.Effects import * не импортирует все подмодули пакета sound.effects в
текущее пространство имён: он лишь убеждается, что импортирован пакет sound.effects
(возможно, выполняя код инициализации из __init__.py), а затем импортирует все
определённые в пакете имена. В этот список попадают любые имена, определённые
(и загруженные явно подмодулями) в __init__.py. В него также попадают все явно
загруженные предшествующими операторами import подмодули. Рассмотрим следующий код:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
В этом примере модули echo и surround импортируются в текущее пространство имён, поскольку они определены в пакете sound.effects на тот момент, когда исполняется оператор from ... import. (И это также работает если определён __all__.)
Обратите внимание, что в общем случае импортирование * из модуля не приветствуется, поскольку в результате часто получается плохо-читаемый код. Однако, вполне нормально использовать его в интерактивных сессиях, чтобы меньше печатать, а определённые модули разработаны для экспорта только тех имён, которые следуют определённым шаблонам.
Помните: в использовании from пакет import определённый_подмодуль нет ничего плохого. На самом деле — это рекомендованная запись, до тех пор пока при импортировании модуля не нужно использовать подмодули с одинаковым именем из разных пакетов.
Ссылки внутри пакета
Когда пакеты структурированы в подпакеты (например, в случае пакета sound), для того, чтобы сослаться на пакеты-потомки вы можете использовать абсолютное импортирование (absolute imports). Например, если модуль sound.filters.vocoder нуждается в модуле echo из пакета sound.effects, он должен использовать from sound.effects import echo.
Вы можете также использовать относительное
импортирование (relative imports), применяя следующую форму оператора import:
from модуль import имя . При таком способе
импортирования для описания текущего и родительского пакетов используется
символ точки. Например, для модуля surround вы можете написать:
from . import
echo
from .. import
formats
from ..filters import equalizer
Обратите внимание, что относительное импортирование основано на имени текущего модуля. Поскольку имя главного модуля всегда „__main__“, модули, предназначенные для использования в качестве главных модулей приложения на Python, должны всегда использовать абсолютное импортирование (absolute imports).
Пакеты в нескольких каталогах
Пакеты поддерживают ещё один специальный аттрибут: __path__. Перед исполнением файла __init__.py этого пакета, он инициализируется списком, содержащим имя каталога, в котором этот файл находится. Изменив переменную, можно повлиять на ход поиска модулей и подпакетов, содержащихся в пакете.
Хотя эта возможность нужна не так часто, она может быть использована для расширения набора модулей, находящихся в пакете.
Ввод и вывод
Ознакомить пользователя с выводом программы можно различными способами — данные могут быть выведены в читабельном виде или записаны в файл для последующего использования. Часть возможностей будет обсуждена в этой главе.
Удобное форматирование вывода
На данный момент мы выяснили два способа вывода значений: операторные выражения (expression statements) и функция print(). (Третий способ — использование метода write() объектов файлов; на файл стандартного вывода можно сослаться как на sys.stdout. Более подробную информацию по этому пункту смотрите в Справочнике по библиотеке.)
Часто возникает желание иметь больший контроль над форматированием вывода, чем обычная печать значений разделённых пробелами. Есть два способа форматирования вашего вывода. Первый способ — выполнять самостоятельно всю работу над строками: используя срезы строк и конкатенацию вы можете создать любой шаблон, какой пожелаете. Стандартный модуль string содержит много полезных операций для выравнивания строк по определённой ширине колонки (скоро мы их кратко рассмотрим). Второй способ — использование метода str.format().
Модуль string содержит класс Template, который предоставляет ещё один способ подстановки значений в строки.
Остаётся, конечно, один вопрос: каким образом конвертировать значения в строки? К счастью, в Python есть два способа для преобразования любого значения в строку — это функции repr() и str().
Предназначение функции str() — возврат значений в довольно-таки читабельной форме; в отличие от repr(), чьё назначение — генерирование форм[40], которые могут быть прочитаны интерпретатором (или вызовут ошибку SyntaxError, если эквивалентного синтаксиса не существует). Для тех объектов, у которых нет формы для человеческого прочтения функция str() возвратит такое же значение, как и repr(). У многих значений, таких как числа или структуры, вроде списков и словарей, одинаковая форма для обоих функций. Строки и числа с плавающей точкой, в частности, имеют по две разных формы.
Несколько примеров:
>>> s = 'Привет, мир.'
>>> str(s)
'Привет, мир.'
>>> repr(s)
"'Привет, мир.'"
>>> str(0.1)
'0.1'
>>> repr(0.1)
'0.10000000000000001'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'Значение x - ' + repr(x) + ', а y - ' + repr(y) + '...'
>>> print(s)
Значение x - 32.5, а y - 40000...
>>> # Фунция repr(), применённая к строке, добавляет кавычки и обратные слэши:
... hello =
'привет, мир\n'
>>> hellos
= repr(hello)
>>> print(hellos)
'привет, мир\n'
>>> # Параметром функции repr() может быть объект Python:
... repr((x, y, ('фарш', 'яйца')))
"(32.5, 40000, ('фарш', 'яйца'))"
Вот два способа вывести таблицу квадратов и кубов:
>>> for
x in range(1, 11):
... print(repr(x).rjust(2),
repr(x*x).rjust(3), end=' ')
... # Обратите внимание на использование end в предыдущей строке
... print(repr(x*x*x).rjust(4))
...
1 1 1
2
4 8
3
9 27
4 16
64
5 25
125
6 36
216
7 49
343
8 64
512
9 81
729
10 100 1000
>>> for
x in range(1, 11):
... print('{0:2d}
{1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
(Обратите внимание, что в первом примере единичные пробелы между колонками добавлены функцией print(): она всегда вставляет пробелы между своими параметрами)
Этот пример демонстрирует работу метода строковых объектов rjust(), выравнивающего строку по правому краю в поле переданной ширины, отступая пробелами слева. Имеются также похожие методы ljust() и center(). Эти методы не выводят ничего, они лишь возвращают новую строку. Если строка на входе чересчур длинная, то они не усекают её, что обычно является меньшим из зол. (Для усечения можно добавить операцию среза, например: x.ljust(n)[:n].)
Есть другой метод — zfill(), который заполняет нулями пространство слева от числовой строки. Он распознаёт знаки плюс и минус:
>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'
Основной способ применения метода str.format() выглядит так[41]:
>>> print('Мы — те {0}, что говорят "{1}!"'.format('рыцари', 'Ни'))
Мы — те рыцари, что говорят "Ни!"
Скобки с символами внутри (их называют полями форматирования (format fields)) заменяются на объекты, переданные методу format. Номер в скобках обозначает позицию объекта в списке параметров, переданных методу format.
>>> print('{0} и {1}'.format('фарш', 'яйца'))
фарш и яйца
>>> print('{1} и {0}'.format('фарш', 'яйца'))
яйца и фарш
Если в методе format используются именованные параметры, можно ссылаться на их значения, используя имя соответствующего аргумента[42].
>>> print('Этот {food} — {adjective}.'.format(
... food='фарш', adjective='непередаваемо ужасен'))
Этот фарш — непередаваемо ужасен.
Позиционные и именованные параметры можно произвольно совмещать[43]:
>>> print('История о {0}е, {1}е, и {other}е.'.format('Билл', 'Манфред',
other='Георг'))
История о Билле, Манфреде, и Георге.
После имени поля может следовать необязательный спецификатор формата ‘:’. С его помощью можно управлять форматированием значения. Следующий пример оставляет у числа Пи только три цифры после десятичного разделителя.
>>> import math
>>> print('Значение ПИ — примерно
{0:.3f}.'.format(math.pi))
Значение ПИ — примерно 3.142.
После спецификатора ‘:’ можно указать число — минимальную ширину поля, выраженную в количестве символов. Это удобно использовать для создания красивых таблиц:
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for
name, phone in table.items():
... print('{0:10}
==> {1:10d}'.format(name, phone))
...
Jack ==> 4098
Dcab ==> 7678
Sjoerd ==> 4127
Если ваша строка с форматами очень длинна, а вы не хотите разбивать её на подстроки, было бы неплохо если бы вы могли ссылаться на переменные, предназначенные для форматирования, не по позиции, а по имени. Это можно сделать, просто передав словарь и используя квадратные скобки ‘[]’ для доступа к ключам.
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
Тоже самое можно сделать, передав словарь именованных параметров, используя нотацию „**“:
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack:
{Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
В частности, такой приём удобно использовать в сочетании со встроенной функцией vars(), которая возвращает словарь с локальными переменными.
Подробное описание форматирования строк с применением метода str.format() описано в разделе Синтаксис строк форматирования.
Форматирование строк в старом стиле
Для форматирования строк можно использовать и операцию %. Она интерпретирует левый операнд как строку форматирования в стиле sprintf, которую следует применить к правому операнду, и возвращает строку, получившуюся в результате этого преобразования. Например:
>>> import math
>>> print 'Значение ПИ — примерно %5.3f.' % math.pi
Значение ПИ — примерно 3.142.
Поскольку метод str.format() довольно нов, большая
часть исходных кодов Python всё ещё использует операцию %. Однако, со временем,
форматирование строк будет удалено из языка, поэтому в большинстве случаев следует
использовать str.format().
Практическое задание
1) Стандартно. Попробуйте разобрать примеры. И только попробуйте их не разобрать!!! ]:-)