Главная страница

С. В. Вабищевич инженерпрограммист компании ооо ск хайникс мемори солюшнс Восточная Европа


Скачать 1.28 Mb.
НазваниеС. В. Вабищевич инженерпрограммист компании ооо ск хайникс мемори солюшнс Восточная Европа
Дата22.11.2021
Размер1.28 Mb.
Формат файлаpdf
Имя файлаKositsin.pdf
ТипУчебно-методическое пособие
#278468
страница3 из 9
1   2   3   4   5   6   7   8   9
codecs: codecs.open(…), codecs.encode(string, ‘utf-8’),
codecs.decode(string, ‘utf-8’).
У полученного файлового объекта есть следующие методы работы:

read для чтения некоторого количества байтов или символов;

readline для чтения следующей строки;

write для записи данных в файл;

seek для установки смещения в файле;

flush для сброса буфера на диск.
Важно! Метод flush не гарантирует запись на диск. Используй- те для этого
os.fsync.
По файлу допустимо итерирование по строкам:
>>> for line in f:
>>> print(line)
Также доступны файловые дескрипторы, отвечающие за стан- дартные потоки ввода (
sys.stdin) и вывода (sys.stdout и sys.stderr).
В стандартной библиотеке Python поддерживается работа также со специфическими форматами данных:
– архивами (модули
zipfile, gzip/zlib);

csv- файлами (самый простой текстовый формат таблиц);

json (основной формат данных в web).
Формат данных
json удобен для сохранения словарей, в частно- сти конфигураций объектов. Также есть сторонняя библиотека для работы с
yaml – расширенный и более читаемый json.
Для красивого форматирования объектов при печати есть до- ступный в стандартной библиотеке модуль
pprint.
2.9. СТРОКИ
ЗАДАНИЕ И ОСОБЕННОСТИ СТРОК
В Python 3.x типы строк принципиально отличаются от ти- пов строк в Python 2.x (табл. 1): строки являются последовательно- стью Unicode- символов, нежели последовательностью байтов.

26
Таблица 1
Сравнение типов строк в Python 2.x и Python 3.x
Тип строки
Python 2.x
Python 3.x кортеж байтов изменяемая последовательность байтов unicode строка
str
bytearray
unicode
bytes
bytearray
str
Строки могут быть заданы как в одинарных «'», так и двой ных «"» кавычках. Есть также строки в трех кавычках подряд (
docstring, ис- пользуются для описания документации объектов).
К строкам могут быть применены литералы:
r", u", b" – префик- сы, которые ставятся перед кавычками:
– «r» (raw string) – используется для указания того, что back slash в строке не нужно экранировать;
– «u» (Unicode) – обозначает строку Unicode- символов (актуаль- но в Python 2.x);
– «b» (binary) – обозначает строку, интерпретируемую как набор байтов (актуально для Python 3.x).
МЕТОДЫ РАБОТЫ СО СТРОКАМИ
Строки в Python неизменны, а потому к ним применимы все методы работы с кортежами: сложение, умножение, проверка вхождения, длина, индексация:
>>> x = ‘abc’
>>> ‘b’ in x
True
>>> x += ‘d’ * 2 # x: ‘abcdd’
>>> len(x)
5
>>> x[:2]
ab
Вопрос: какой алгоритм поиска подстроки в строке используется в стандартной библиотеке?
Для поиска подстрок используются следующие методы:

index – найти индекс вхождения подстроки в строку или бро- сить исключение в случае отсутствия;

count – подсчитать количество вхождений подстроки в строку;

27

find (rfind) – найти первое вхождение подстроки в строку сле- ва (справа) или вернуть «–1», если его нет.
>>> x.find(‘z’) # x: ‘abcdd’
–1
Для проверки того, что строка начинается или заканчивается некоторой подстрокой, используют методы
startswith и endswith:
>>> x.endswith((‘aa’, ‘dd’))
True
В качестве аргумента методам можно передать как некоторую подстроку, так и кортеж подстрок. В последнем случае будет прове- рено, начинается или заканчивается строка с хотя бы одной из пе- реданных подстрок.
Замена подстрок происходит с помощью метода
replace. По- скольку строки неизменяемые, его вызов создает новую строку.
>>> x = x.replace(‘a’, ‘z’) # ‘zbcdd’
Строки можно объединять (метод
join) и разбивать по симво- лу (методы
split и rsplit, обратите внимание на параметр max_split, который отвечает за максимальное количество разбивки строки):
# ‘zbcdd’ -> [‘zb’, ‘dd’] -> ‘zbcdd’
>>> ‘c’.join(x.split(‘c’)) zbcdd
Важно! Если требуется объединить большое количество строк, следует все строки занести в список и объединить их с помощью ме- тода
join, применив его к разделителю (например, разделителем мо- жет быть пробел или перенос строки).
При обработке строк полезно избавится от пробелов, переносов строк, табуляций или просто удалить некоторые символы из начала и/или конца строки. Для этого предназначены методы
strip, lstrip и
rstrip.
>>> x.strip(‘d’) zbc
Также есть другие методы работы со строками, например сле- дующие:
– преобразование регистра:
lower, upper, title, capitalize;
– кодирование:
encode, decode;
– проверка символов:
isalpha, isdigit и др.

28
Замечание. Строки, содержащие все цифры или все знаки пун- ктуации, определены в модуле string.
Работа с
base64 организуется с помощью библиотеки base64.
2.10. ИМПОРТ МОДУЛЕЙ
ОСНОВЫ ИМПОРТА МОДУЛЕЙ
Любой файл с кодом на Python является модулем. Чтобы использовать код, написанный в некотором файле, его можно загру- зить – выполнить импорт модуля:
>>> import [as ]
>>> from import ( [as ],
…,
[as ])
Первая инструкция импортирует модуль целиком, вторая – только некоторые объекты из него. Каждый загруженный объект можно сделать доступным под другим именем (alias). Это полез- но в том случае, когда в разных модулях есть объекты с одинако- выми именами.
Узнать версию Python можно, обратившись к атрибуту version модуля
sys:
>>> import sys
>>> print(sys.version)
3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 02:47:15) [MSC v.1900 32 bit (Intel)]
ЗАГРУЗКА МОДУЛЕЙ
Все загруженные модули хранятся в sys.modules:
>>> def is_fractions_imported():
>>>
return ‘fractions’ in sys.modules
>>> assert not is_fractions_imported()
>>> import fractions
>>> assert is_fractions_imported()

29
ПОИСК МОДУЛЕЙ
При загрузке модуля интерпретатор ищет модуль в следу- ющей последовательности:
– sys.modules (модуль уже мог быть загружен);
– builtins (это может быть встроенный модуль);
– sys.path:
текущая рабочая папка (current working directory);
PYTHONPATH;
папка установки Python, папка со стандартными библиоте- ками.
Переменная sys.path представляет собой список путей, по кото- рым нужно искать модуль. Эту переменную можно модифицировать, чтобы обеспечить возможность загрузить модуль, который находит- ся на нестандартном пути.
2.11. СТИЛЬ КОДА
О ПРОБЕЛАХ
Используйте ровно четыре пробела вместо tab.
Добавляйте две строки между глобальными функциями, одну – между методами классов.
Блоки
for, if и прочие желательно визуально отделять пустой строкой. Поскольку в Python блоки не выделяются фигурными скоб- ками, как в C/C++, но логически обособленны, визуально разделить их может только пустая строка.
>>> for i in range(20):
>>>
print(i)
>>>
>>> for j in range(2, 10):
>>>
print(j**2)
В конце файла желательно добавлять пустую строку.
Знаки математических операций следует выделять пробелами, кроме знака
«=» при передаче аргументов по умолчанию.
Перед и после скобок (при вызове функции, индексировании) пробел не нужен.
После запятой пробел нужен всегда, перед – никогда.

30
ИМЕНОВАНИЕ ПЕРЕМЕННЫХ
Нотация для имен переменных следующая:
– имя функции и переменной пишется в snake case: var_name, function_name;
– имя класса – в camel case: ClassName;
– имя переменной- константы – прописными буквами: CONST_
NAME.
Переменные должны иметь понятные имена и либо доносить назначение переменной, либо описывать то, что в ней содержится
(на что указывает).
В именах функций должен присутствовать глагол.
ДЛИНА СТРОК
Длина строк не должна превышать 100 символов (поч- ти всегда; при договоренности – 120 символов), документации – 72.
ПРОЧИЕ ЗАМЕЧАНИЯ
Дублирующийся код следует выносить в функции.
Комментарии нужны для пояснения тонких моментов.
Кодировка файлов желательна utf-8 (актуально для Python 2.x).
Можно дополнительно добавить строку в начало файла:
# -*- coding: utf-8 -*-
Поскольку функции в Python нельзя перегрузить (сделать с раз- ными сигнатурами), используют параметры по умолчанию. Неизме- ненные параметры принято не указывать:
>>> range(10) # range(0, 10, 1)
>>> range(2, 7) # range(2, 7, 1)
УТИЛИТЫ ДЛЯ ПРОВЕРКИ
Для проверки кода без выполнения можно использовать следующие утилиты, скрипты и среды разработки:
– pep8.py;
– PyChecker;

31
– PyFlakes;
– Pylint;
– PyCharm.
Более полные версии рекомендаций с примерами доступны в PEP-8 1
и Google Python Style Guide
2 2.12. МОДЕЛЬ ПАМЯТИ
ОБЪЕКТЫ
Все сущности в Python являются объектами (наследника- ми типа
object), в том числе
– числа, списки, словари;
– классы и функции;
– код.
Важно! Все переменные – ссылки на некоторые объекты, кото- рые располагаются по некоторым адресам памяти.
У всех объектов можно выделить следующие свой ства:
идентичность – адрес в памяти (функция
id), не изменяется, для сравнения используется
is и is not;
тип определяет допустимые значения и операции над ними, также не изменяется (см. функцию
type);
значение может быть изменяемым (list) и неизменяемым (tuple).
СРАВНЕНИЕ ОБЪЕКТОВ
Поскольку все переменные – ссылки на некоторые ячей- ки памяти, можно узнать адрес конкретного объекта – воспользо- ваться функцией
id(…).
Проверить, что
x и y указывают на один и тот же объект, мож- но с помощью инструкции
is:
>>> x is y
Проверка, что
x и y указывают на равные по значению объекты, происходит с помощью оператора сравнения на равенство
>>> x == y
1
https
://www.python.org/dev/peps/pep‑0008/
2
https
://github.com/google/styleguide/blob/gh‑ pages/pyguide.md

32
Ниже представлен пример сравнения двух одинаковых списков.
Можно видеть, что списки являются разными объектами, но имеют одинаковое значение.
>>> x = [3, 5, 9]
>>> y = [3, 5, 9]
>>> print(“are objects equal: %s”% (x == y))
are objects equal: True
>>> print(“are objects same:%s (id of x – %d; id of y – %d)”
% (x is y, id(x), id(y)))
are objects same: False (id of x – ; id of y – )
>>> print(“x equals itself comparing values (%s)”
“ and identifiers (%s)”% (x == x, x is x))
x equals itself comparing values (True) and identifiers
(True)
СВЯЗЬ ИМЕНИ И ОБЪЕКТА
Каждому имени в коде соответствует объект в памяти. При присваивании одной переменной значения другой переменной при- сваиваются ссылки на объект- значение (рис. 1).
x = 1
y = x x = 1
y = x y = 2
x y
1
x y
1 2
Рис. 1. Пример присваивания
ИЗМЕНЯЕМЫЕ ОБЪЕКТЫ
Значение объектов может меняться. Поскольку перемен- ным присваиваются ссылки на объект, меняются значения всех пе- ременных, указывающих на него (рис. 2).

33
x = [1
]
, 2
y = x y += [3]
x[0] = 0
x y
[0
]
, 2, 3
Рис. 2. Пример присваивания и изменения объектов
НЕИЗМЕНЯЕМЫЕ ОБЪЕКТЫ
Значение некоторых объектов, например кортежей, ме- няться не может:
>>> a = (1, 2)
>>> a[0] = 0
TypeError: ‘tuple’ object does not support item assignment
Рассмотрим пример, где предпринимается попытка изменить список, который размещается в кортеже.
>>> a = ([0],)
>>> a[0] += [1]
Вопрос: что будет в результате выполнения кода в этом при- мере?
При работе с неизменяемыми объектами некоторые операции создадут новый объект (рис. 3).
x y
(1, 2)
x y
(1, 2)
(1, 2, 3)
x = (1, 2)
y = x x = (1, 2)
y = x y += (3,)
Рис. 3. Пример присваивания и модификации кортежа
Важно! Объект типа object является также неизменяемым. В от- личие от кортежа
object не допускает абсолютно никаких операций над собой.

34
КОНТЕЙНЕРЫ
Объекты, например списки и словари, могут содержать ссылки на другие объекты. Как и ранее, модификация внутренних объектов приводит к изменению общего значения контейнера (рис. 4).
x = [1
]
, 2
y = ('a', x)
x[0] = 'b'
x y
['b', 2]
'a'
Рис. 4. Пример объекта- контейнера
КОПИРОВАНИЕ ОБЪЕКТОВ
К встроенным неизменяемым типам относятся следую- щие:
int, float, complex, bool, str, tuple, frozenset. К изменяемым –
list, dict, set.
При присваивании объектов происходит присваивание ссылок, однако модификация (если она допустима) неизменяемых объектов неявно создает копию (например, добавление элементов к кортежу или сложение строк), а модификация изменяемых меняет значения всех переменных.
Поэтому в случае присваивания изменяемых объектов, мо- жет, нужно создать копию. Для этого используются методы
copy и
deepcopy (модуль copy) либо конструктор копирования. Методы отличаются тем, что первый создает поверхностную (shallow) ко- пию – копирует только контейнер, но не сами элементы в нем, а вто- рой – полную (deep) копию. Другими словами, создавая копию спи- ска некоторых объектов, вызывая метод
copy, будет создан список, содержащий ссылки на те же самые объекты.
СИНГЛТОНЫ
Некоторые объекты используются достаточно часто, а по- тому очень накладно создавать множество отдельных сущностей, и они поддерживаются интерпретатором в единственном экзем- пляре. Это объекты:

None;

True;

False;

35

NotImplemented (используется в операторах сравнения);

Ellipsis (используется в математических библиотеках).
Замечание. В этом можно убедиться, вызвав функцию id.
Помимо
None, True, False, NotImplemented и Ellipsis, числа от
–5 до 256 могут быть также синглтонами ввиду их частого исполь- зования. Это зависит от реализации интерпретатора.
NONE КАК ПАРАМЕТР ПО УМОЛЧАНИЮ
Объект
None используется в качестве параметра по умол- чанию для обозначения того, что ничего не передано.
Если же значение
None допустимо и его нельзя использовать в качестве аргумента по умолчанию, то создают объект (например, глобальный) типа
object и проверяют, является ли переданный ар- гумент идентичным этому объекту.
Замечание. При каждой загрузке модуля объект создаваться за- ново не будет.
>>> not_set = object()
>>> def f(x=not_set):
>>> is_x_set = (x is not not_set)
2.13. ОСОБЕННОСТИ РАБОТЫ С КОЛЛЕКЦИЯМИ
УПАКОВКА ПЕРЕМЕННЫХ
Упаковка переменных – создание контейнера, например кортежа или списка.
>>> x = [1, 2]
>>> x0 = x[0]
>>> x1 = x[1]
>>> print(x0, x1)
1, 2
РАСПАКОВКА ПЕРЕМЕННЫХ
Распаковка переменных – присваивание каждому элемен- ту контейнера имени. Распаковывать
list, tuple, set, а также итера- торы можно автоматически.

36
>>> x = [1, 2]
>>> x0, x1 = x
>>> print(x0, x1)
1, 2
Для обмена переменных местами можно сначала упаковать пе- ременные, а потом распаковать их в другом порядке:
>>> x[0], x[1] = (x[1], x[0]) # скобки не обязательны
>>> print(x[0], x[1])
2, 1
Присваивание выполняется справа налево, но подвыражения в присваивании – в порядке следования:
>>> x = [1, 2]
>>> i = 0
>>> i, x[i] = 1, 1
>>> print(x)
[1, 1]
При распаковке допускается вложенность:
>>> ((x, _), z) = [[1, 2], 3]
>>> print(x, z)
1, 3
В Python 3 допустима частичная распаковка (PEP-3132)
1
:
>>> head, *middle, tail = list(range(5))
>>> print(head, middle, tail)
0, [1, 2, 3], 4
Для итерирования сразу по двум коллекциям можно воспользо- ваться функцией
zip. Она собирает пары элементов из коллекций и распаковывает их в заголовке блока
for:
>>> for x, y in zip([1, 2, 3], [–3, –2, –1]):
>>>
print(x % y == 0, end=’ ‘)
False True True
Важно! Функция zip возвращает новый список кортежей в Python 2.x и
генератор в Python 3.x.
Вопрос: что будет, если коллекции разной длины?
1
https
://www.python.org/dev/peps/pep‑3132

37
Для итерирования по коллекции с получением индекса каждого элемента можно воспользоваться функцией
enumerate(x).
>>> z1 = zip(range(len(x)), x))
>>> z2 = enumerate(x)
>>> assert list(z1) == list(z2)
True
СЛАЙСЫ
Помимо обращений по индексам есть возможность обра- щаться к диапазонам элементов коллекции:
>>> x = list(range(10))
>>> print(x[0:10:2])
0 2 4 6 8
Указание начала, конца и шага в диапазоне происходит с помо- щью символа «:» (двоеточие).
Слайсы, описывающие пустой диапазон, возвращают пустой список, а тип возвращаемого слайса часто соответствует типу пе- ременной, от которой слайс берется. Ниже представлено два при- мера: слайс за пределами коллекции и пустой слайс (из- за отрица- тельного шага):
>>> x[100:110]
[]
>>> x[0:10:-2]
[]
СПОСОБЫ ЗАДАНИЯ СЛАЙСОВ
Слайс допускает пропуск некоторых значений (например, начала диапазона или его конца) – эти значения будут автоматиче- ски вычислены.
>>> x[9:0:-2] == x[–1:0:-2] == x[::-2] == x[None::2]
True
Слайс – это объект типа
slice, аргументы конструктора которого аналогичны аргументам функции
range:
>>> x[slice(9, 0, –2)] == x[9:0:-2]
True

38
Слайсу можно дать имя и связать его с переменной:
>>> even_indices_slice = slice(None, None, 2)
>>> print(x[even_indices_slice])
Важно! Слайсы можно не только брать, но им можно присваи- вать произвольный iterable с иным количеством элементов:
>>> x = [1, 2, 3]
>>> x[0:2] = [7, 6, 5]
>>> print(x)
[7, 6, 5, 3]
ЗАМЕЧАНИЯ ПО РАБОТЕ СО СПИСКАМИ
Можно рассмотреть три основных способа создания спи- ска, содержащего три списка (аналог двухмерного массива):
>>> x = [[], [], []]
>>> y = [[]] * 3
>>> z = []
>>> for _ in range(3):
>>> z.append([])
>>> print(x, y, z)
[[], [], []], [[], [], []], [[], [], []]
Если далее выполнить следующий код, окажется, что в одном из случаев вложенные списки не скопировались должным обра- зом:
>>> x[0].append(1); y[0].append(2); z[0].append(3)
>>> print(x, y, z)
[[1], [], []], [[2], [2], [2]], [[3], [], []]
Действительно, при умножении списка на число ссылка, указы- вающая на внутренний список, была скопирована три раза, а объект списка, на который она указывает, остался неизменным.
Для более простого однострочного создания такого рода списков используются comprehension- выражения:
>>> y_pretty = [[] for _ in range(3)]
>>> y_pretty[0].append(2)
>>> print(y_pretty)
[[2], [], []]

39
COMPREHENSION- ВЫРАЖЕНИЯ
Comprehension- выражения содержат блок for для итериро- вания по некоторой коллекции, выражение, результат выполнения которого будет сохранен в выходной коллекции, а также допускают произвольное количество
for и if, причем не обязательно поочеред- но: после
for допустимо несколько инструкций if.
Рассмотрим пример получения списка всех нечетных чисел от 0 до 10 (не включая):
>>> def is_odd(x):
>>> return bool(x % 2)
>>>
>>> c = [x for x in range(10) if is_odd(x)]
>>> assert c == [1, 3, 5, 7, 9]
Если квадратные скобки заменить на круглые, получим выражение- генератор
>>> g = (x for x in range(10) if is_odd(x))
Есть comprehension- выражения для создания словарей и мно- жеств:
>>> d = {x: y**2

for x in range(2)

for y in range(x + 1)}
>>> assert d == {0: 0, 1: 1}
>>>
>>> s = {1 for _ in range(10)}
>>> assert s == set([1])
Замечание. Перед for может стоять любое допустимое выраже- ние, в том числе содержащее некоторое преобразование (например возведение в квадрат y**2), или тернарный условный оператор.
ФУНКЦИОНАЛЬНЫЙ ПОДХОД
Помимо comprehension- выражений допустима и функ- циональная обработка коллекций, а именно: преобразование эле- ментов (применение к каждому некоторой функции) и фильтрация элементов (выбор только элементов, которые соответствуют неко- торому условию).

40
Вот основные функции для работы с последовательностями:

map – применить функцию к каждому элементу последова- тельности;

filter – оставить только те элементы, для которых переданная функция возвращает
True (предикатом может быть None);

all – возвращает True, если все элементы преобразуются к True;

any – возвращает True, если хотя бы один элемент True.
Замечание. В Python 2.x функции map и filter возвращают спи- ски, в то время как в Python 3.x – генераторы.
>>> def is_odd(x):
>>>
return bool(x % 2)
>>>
>>> c = filter(is_odd, range(10))
>>> assert list c == [1, 3, 5, 7, 9]
ПРОИЗВОДНЫЕ КОЛЛЕКЦИИ
Помимо базовых коллекций – списка, множества, слова- ря – в Python реализованы некоторые производные коллекции.
Для того чтобы не проверять наличие в словаре элемента при об- ращении по ключу, можно воспользоваться коллекцией
defaultdict.
Конструктор
defaultdict принимает объект, при вызове которого бу- дет возвращаться значение по умолчанию.
>>> import collections
>>> def f():
>>>
return 0
>>> x = collections.defaultdict(f)
>>> print(x[2])
0
Часто из функции требуется вернуть несколько значений. Они ав- томатически упакуются в кортеж, но при вызове функции либо воз- никнет необходимость обращаться к элементам кортежа по индексу, либо распаковывать его каждый раз. Чтобы избежать обоих вариан- тов и оставить код понятным, можно обернуть результат в имено- ванный кортеж и обращаться к его элементам по имени.
В примере ниже создается именованный кортеж
Point с поля- ми «x» и «y»:
>>> from collections import namedtuple
>>> Point = namedtuple(‘Point’, [‘x’, ‘y’])

41
>>> p = Point(1, 2)
>>> print(p.x == p[0] == 1 and p.y == p[1] == 2)
True
У
namedtuple есть некоторые полезные методы:

_fields – вернет имена полей («x», «y»);

_asdict() – вернет OrderedDict (словарь, который гарантирует порядок обхода) с соответствующими ключами и значениями;

_replace(x=new_value, …) – вернет новый namedtuple с заме- ненными значениями.
Помимо
defaultdict и namedtuple в Python реализованы следу- ющие коллекции:

deque – дек, двухсторонняя очередь;

Counter – реализация defaultdict, когда для всех ключей зна- чение по умолчанию – ноль;

OrderedDict – словарь, сохраняющий порядок вставки элементов;

Queue – потокобезопасная очередь;

array – массив, хранящий данные определенного C-совмести- мого типа.
АЛГОРИТМЫ СТАНДАРТНОЙ БИБЛИОТЕКИ
В стандартной библиотеке реализованы алгоритмы по ра- боте с кучей и упорядоченным списком:

heapq – модуль, содержащий функции по созданию кучи (heap), добавлению элементов, взятию k- максимальных;

bisect – модуль, содержащий функцию бинарного поиска эле- мента по списку, а также вставки элемента в упорядоченную после- довательность.
ИНСТРУКЦИЯ DEL
Инструкция
del имеет несколько смысловых нагрузок:
– «разрывает связь» между переменной и объектом (здесь также задействуется счетчик ссылок объекта);
– удаляет элемент, атрибут или слайс (за удаление отвечает сам объект).
>>> class X(object):
>>> a = None
>>>

42
>>> del X.a
>>>
>>> y, z = [1, 2, 3], {‘x’: 0}
>>> del y[0], z[‘x’]
Вопрос: как с помощью
del очистить список, не удалив при этом объект?
2.14. МОДУЛИ И ПАКЕТЫ
СХЕМА ИМПОРТА МОДУЛЕЙ
При вызове «
import x» происходит следующее:
– попытка найти модуль (find module);
– попытка загрузить модуль и создать объект модуля (load module);
– создается объект loaded_module типа ModuleType;
– читается исходный код модуля;
– исходный код компилируется в байткод;
– скомпилированная версия выполняется;
– sys.modules[‘x’] = loaded_module;
.x = loaded_module.
Поскольку при импорте модуля его код выполняется, создают- ся все объекты, которые в нем находятся, в том числе и глобальные функции, а следовательно, и значения по умолчанию функций.
Вопрос: что произойдет в следующем примере?
>>> def f(x=g()):
>>>
pass
>>>
>>> def g():
>>>
return 0
Замечание. Еще раз обратите внимание на тот факт, что зна- чение по умолчанию вычисляется единожды при создании объек- та функции. Этот факт, в частности, был использован для создания значения по умолчанию в случае, если значение
None допустимо.
Для изменения поведения при исполнении модуля от поведения при импорте используется следующее:
>>> if __name__ == ‘__main__’:
>>> # some code

43
Код, расположенный под данным условным блоком, будет выпол- нен, только если этот файл запускается для исполнения.
Узнать имя файла из модуля можно, обратившись к переменной
__file__, имя модуля – к переменной __name__.
ЗАГРУЗКА И ПЕРЕЗАГРУЗКА МОДУЛЯ
При загрузке модуля важно различать загрузку объек- та из модуля и загрузку модуля с последующим доступом к объек- там в нем.
Пример загрузки объекта из модуля:
>>> from module import x
>>> # использовать x напрямую
Пример загрузки модуля с последующим доступом к его атри- буту:
>>> import module
>>> # использовать module.x
Разница в том, что в случае перезагрузки модуля module объект x останется тем же в первом случае и будет всегда актуальным во вто- ром. В частности, по этой причине перезагрузка модуля не рекомен- дуется.
Перезагрузить модуль можно двумя способами:
– удалить объект модуля из sys.modules и выполнить импорт мо- дуля заново;
– вызвать функцию
importlib.reload(loaded_module).
Перезагрузка модуля имеет множество подводных камней. Если воспользоваться первым вариантом, будет создан новый объект мо- дуля, и он не будет обновлен везде, где был загружен.
Если воспользоваться вторым вариантом, новый объект модуля создан не будет, но все объекты в модуле пересоздадутся!
ИМПОРТ МОДУЛЕЙ ПО ИМЕНИ
Модуль можно загружать по имени:
>>> from importlib import import_module
>>> module_instance = import_module(‘module_name’)

44
Помимо указания имени есть возможность загружать модули по полному пути как с исходным кодом (source), так и скомпилиро- ванные (compiled, с расширением
.pyc) и динамические (dynamic, с расширением
.pyd или .so). Требуемые функции расположены в мо- дуле
imp в Python 2.x и importlib.util в Python 3.x.
При поиске запрашиваемого модуля интерпретатор соблюдает следующую очередность загрузки:
– пакет (package);
– модуль (module);
– пространство имен (namespace; PEP 420 1
начиная с Python 3.3).
ПАКЕТЫ И ПРОСТРАНСТВА ИМЕН
Пакет
(package) – папка с модулями, в которой присут- ствует файл __init__.py.
Пространство имен (namespace) – папка с модулями, в которой файл __init__.py отсутствует.
Разница будет для вложенных папок: вложенный пакет обнару- жится интерпретатором, а для простанства имен путь к вложенным пространствам имен нужно явно прописать в
sys.path.
Напоминание. sys.path.append(x) равносилен sys.path += x, но от- личается от sys.path = sys.path +
x
В __init__.py файле можно подготовить пакет: сделать некоторые импорты, ограничить некоторые модули для загрузки. Модули, име- на которых начинаются с подчеркивания, не принято загружать из- вне пакета, в котором они объявлены.
ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ ИМПОРТОВ МОДУЛЕЙ
Объявление переменной __all__ в модуле или пакете по- зволяет ограничить набор доступных для импорта имен переменных в модуле или модулей в пакете конкретным списком имен.
У модуля также может присутствовать
docstring – документация, описание его содержимого. Данную строку следует располагать ввер- ху файла в тройных кавычках.
Модуль
__future__ является директивой компилятору создать .pyc файл, используя другие инструкции.
Модули можно загружать прямо из zip- архива.
1
https
://www.python.org/dev/peps/pep‑0420

45
Также можно использовать относительные импорты (PEP-328)
1
Пусть имеется структура пакетов, указанная в табл. 2. Тогда для
moduleX.py верны указанные там же относительные импорты.
Таблица 2
Пример относительных импортов
Структура пакетов
Допустимые импорты
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
from.moduleY import spam
from.moduleY import spam as ham
from. import moduleY
from ...subpackage1 import moduleY
from ...subpackage2.moduleZ import eggs
from ...moduleA import foo
from …package import bar
from …sys import path
Существуют дополнительные механизмы: path hooks, metapath, module finders и loaders, – позволяющие управлять процессом за- грузки модулей.
2.15. ФУНКЦИИ
СИНТАКСИС ФУНКЦИЙ
Определение функции в Python начинается с инструкции
def и имеет следующий вид:
>>> def f(positional,
>>>
positional_with_default=default_value,
>>>
*variadic_arguments,
>>>
keyword_only,
>>>
**keyword_arguments
>>>):
>>> pass
В Python динамическая типизация и нет перегрузки функций, а потому для того, чтобы функции были максимально гибкими, ис- пользуются значения по умолчанию и разные виды аргументов (по-
1
https
://www.python.org/dev/peps/pep‑0328

46
зиционные, variadic- аргументы и аргументы, передаваемые по клю- чевым словам).
Аргументы бывают следующих видов:
– позиционные (обязательные к определению);
– позиционные со значением по умолчанию (если аргумент не передан, будет установлено значение по умолчанию);
– variadic- аргумент (позволяет поддерживать произвольное ко- личество позиционных аргументов в функции и хранить их в tuple);
– агрументы, передаваемые исключительно по ключевым словам
(такие аргументы обязаны быть переданными с указанием их имени);
– keyword variadic- аргумент (позволяет принимать произвольное количество аргументов, передаваемых по ключевому слову, и хра- нить их в словаре).
Важно! Значение по умолчанию вычисляется единожды при определении функции, а потому должно быть неизменяемым.
ВЫЗОВ ФУНКЦИЙ
Вызов функции происходит с помощью оператора «()» и передачи необходимых аргументов. Если некоторые аргументы отсутствуют или передано более одного значения для некоторого аргумента, будет
TypeError.
>>> def f(x, y=0, *args, **kwargs):
>>> return x, y, args, kwargs
>>>
>>> f() # TypeError
>>> f(1) # x: 1, y: 0, args: tuple(), kwargs: {}
>>> f(1, 2) # x: 1, y: 2, args: tuple(), kwargs: {}
>>> f(1, 2, 3) # x: 1, y: 2, args: tuple(3), kwargs: {}
Допустима распаковка аргументов при вызове функции:
>>> f(*(1, 2, 3, 4))
# x: 1, y: 2, args: tuple(3, 4), kwargs: {}
Начиная с Python 3.5 (PEP-448)
1
допустима передача нескольких аргументов для распаковки:
>>> f(*(1, 2, 3), *(5, 6))
# x: 1, y: 2, args: tuple(3, 5, 6), kwargs: {}
1
https://www.python.org/dev/peps/pep-0448

47
Аргументы можно передавать по ключевым словам (порядок произвольный):
>>> f(y=1, x=2) # x: 2, y: 1, args: tuple(), kwargs: {}
Из плюсов передачи аргументов по ключевым словам можно вы- делить наглядность и независимость от порядка указания. Однако минусы такой передачи тоже есть:
– возможно более медленное выполнение (Issue 27 574)
1
;
– проблемы с переименованием.
Переданные по ключевым словам аргументы, для которых нет имен, помещаются в kwargs:
>>> f(x=1, z=2) # x: 1, y: 0, args: tuple(), kwargs:
{‘z’: 2}
Замечание. Порядок kwargs гарантируется с Python 3.6
(PEP-468)
2
. Допустима распаковка аргументов по ключевым сло- вам:
>>> f(**{‘x’: 1, ‘z’: 2})
# x: 1, y: 0, args: tuple(), kwargs: {‘z’: 2}
В Python 3 функции могут принимать аргументы исключитель- но по ключевому слову (PEP-3102)
3
:
>>> def f(*skipped, value=0):
>>> pass
>>>
>>> f(1, 2, 3) # skipped: (1, 2, 3), value: 0
>>> f(value=100) # skipped: tuple(), value: 100
Важно! Если значение по умолчанию не указано, функция обя- зана вызываться с данным ключевым аргументом, иначе возник- нет
TypeError.
Замечание. Имя variadic- аргумента может быть опущено.
Вопрос: что будет, если имя variadic- аргумента опущено (вместо
*args оставлен просто символ “*”), но в функцию переданы variadic- аргументы?
1
https://bugs.python.org/issue27574 2
https://www.python.org/dev/peps/pep-0468 3
https://www.python.org/dev/peps/pep-3102

48
АЛГОРИТМ МАППИНГА АРГУМЕНТОВ
Значения назначаются аргументам функции по порядку:
– на позиционные слоты;
– на variadic- аргумент (в кортеж неименованных элементов);
– переданные по ключевым словам – либо на позиционные, либо в словарь.
Важно! Если аргумент позиционный и не был передан или ключевой аргумент был передан более одного раза, возникнет
TypeError.
Полный алгоритм маппинга аргументов описан в PEP-3102 1
ДОКУМЕНТАЦИЯ ФУНКЦИЙ
Описание функции и их аргументов производится в
docstring (PEP-257)
2
:
>>> def complex(real=0.0, imag=0.0):
>>>
”””Form a complex number.
>>>
>>>
Keyword arguments:
>>>
real – the real part (default 0.0)
>>>
imag – the imaginary part (default 0.0)
>>>
”””
>>>
# some code here …
Документация может быть получена вызовом функции
help(f) или взятием аргумента f.
__doc__
2.16. ОБЛАСТИ ВИДИМОСТИ ПЕРЕМЕННЫХ
Области видимости переменных определяются функ- циями:
built- in – встроенные общедоступные имена (доступны через модуль builtins или __buitlins__, например,
sum, abs и т. д.);
global – переменные, определенные глобально для модуля;
1
https://www.python.org/dev/peps/pep-3102 2
https://www.python.org/dev/peps/pep-0257

49
enclosing – переменные, определенные в родительской функ- ции;
local – локальные для функции переменные.
Локальные переменные в функциях могут в них свободно изме- няться, enclosing, global и built- in – только читаться (PEP-227)
1
При- мер с использованием переменных разных областей видимости:
>>> abs(2) # built- in
>>> abs = dir # global, overrides
>>> def f():
>>> abs = sum # enclosing
>>>
def g():
>>> abs = max # local
Для справки. Для переопределения
abs из функции g в функции
f используется ключевое слово nonlocal, для переопределения гло- бальной переменной
abs – ключевое слово global (PEP-3104)
2
>>> global abs
>>> abs = max # переопределит abs, глобальный для модуля
ПЕРЕМЕННЫЕ В ЦИКЛАХ
Циклы
не имеют своей области видимости: как толь- ко переменная была создана, она становится доступной и после цикла.
>>> for i in range(10):
>>>
if i > 5:
>>>
break
>>> print(i)
6
Замечание. В Python 3.4 и ниже так же «вытекали» переменные из comprehension- выражений. Баг был исправлен в Python 3.6.
>>> x = [i for i in range(10)]
>>> print(i)
NameError: name ‘i’ is not defined # Python 3.6 1
https://www.python.org/dev/peps/pep-0227 2
https://www.python.org/dev/peps/pep-3104

50
ЛОКАЛЬНЫЕ И ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
В Python можно получить доступ ко всем локальным и гло- бальным переменным:

locals() – словарь видимых локальных переменных;

globals() – аналогичный словарь глобальных переменных.
Словари автоматически обновляются интерпретатором.
Вопрос: можно ли, модифицируя эти словари, добавлять, изме- нять или удалять соответствующие переменные?
ЗАМЫКАНИЯ
В функции доступны переменные; переменные, опреде- ленные уровнями выше, – замыкаются.
>>> def make_adder(x):
>>>
def adder(y):
>>>
return x + y
>>>
return adder
>>>
>>> add_five = make_adder(5)
>>> add_five(10) # 15
Важно! Значение замкнутой переменной получается каждый
раз при вычислении выражения.
Рассмотрим пример замыкания переменной:
>>> x = 2
>>>
>>> def make_adder():
>>> def adder(y):
>>>
return x + y
>>> return adder
>>> add_x = make_adder()
>>> add_x(–2) # 0
>>> del x # delete ‘x’ – unbind variable name with
object
>>> add_x(–2) # NameError: name ‘x’ is not defined
Как можно видеть, переменная «x» была замкнута, вычисляется каждый раз при обращении и при удалении перестает быть доступной.

51
LAMBDA- ФУНКЦИИ
Lambda- функции в Python допускают в себе одно лишь выражение:
lambda arguments: expression
Эквивалентно:
def (arguments):
return expression
Вопрос: как будет выглядеть
lambda, которая ничего не прини- мает и не возвращает?
Важно! С точки зрения bytecode lambda аналогична функции с тем же кодом, но при использовании
def объект- функция еще по- лучает имя.
Функция, возвращающая сумму аргументов:
>>> lambda x, y: x + y
Пример списка lambda- функций:
>>> collection_of_lambdas = [lambda: i*i for i in
range(6)]
>>>
>>> for f in collection_of_lambdas:
>>>
print(f())
Вопрос: что будет выведено в результате выполнения?
Поскольку вычисление происходит run- time, то для всех создан- ных функций значение
i будет равно пяти. Переменная i была «за- хвачена» в comprehension- выражении, хоть и вне этого выражения она недоступна (в Python 3.6).
Для «захвата» значения можно создать локальную для
lambda ко-
пию:
>>> lambdas = [lambda i=i: i*i for i in range(6)]
В модуле
operator (Python 2.x)
1
, (Python 3.x)
2
есть множество функционалов, которыми можно пользоваться наряду с
lambda- функциями:
1
https://docs.python.org/2.7/library/operator.html
2
https://docs.python.org/3.7/library/operator.html

52
>>> import operator
>>> # аналог: lambda x, y: x + y
>>> operator.add # operator.__add__
Помимо операторов арифметических операций и операций срав- нения есть функционалы для работы с атрибутами и элементами коллекций.
f = operator.attrgetter(‘name.first’, ‘name.last’)
# the call f(b) returns (b.name.first, b.name.last)
g = operator.itemgetter(2, 5, 3)
# the call g(r) returns (r[2], r[5], r[3])
h = operator.methodcaller(‘name’, ‘foo’, bar=1)
# the call h(b) returns b.name(‘foo’, bar=1)
Функционалы и lambda- функции наряду с обычными функция- ми используются как аргументы, выполняющие некоторое действие, например, в
map, filter.
2.17. ФОРМАТИРОВАНИЕ СТРОК
В Python подерживается printf- style форматирование:
>>> ‘numberof %.3f values in %s is %d’% (0.1234,
‘some object’, 3) number of 0.123 values in some object is 3
Есть возможность использовать именованные аргументы:
>>> ‘number of %(name)s is %(count)d’% {‘name’:
‘names’, ‘count’: 2} number of names is 2
Помимо printf- style форматирования поддерживается Python- стиль форматирования строк, где аргументы подставляются на ме- сто элементов в фигурных скобках:
>>> ‘number of {0:.3f} values in {1} is {2}’.format
(0.1234, ‘some object’, 3) number of 0.123 values in some object is 3
Помимо указания индекса элемента, который нужно подставить, и формата можно выполнять следующее:

53
– аналогично использовать именованные аргументы: «{name}»;
– индексировать аргументы: «{items[0]}»;
– обращаться к атрибутам: «{point.x}»;
– опускать индексы: «{}{}»;
– повторять и менять местами индексы: «{1}{0}{1}».
Вопрос: что будет, если не совпадает количество аргументов для подстановки? А если нет такого именованного аргумента?
Замечание. Если вам нужно подставить множество локальных переменных, можно использовать словари
locals() и globals(), опре- деленные интерпретатором:
>>> x = 2
>>> “{x}”.format(**locals())
2
Замечание. В Python 3 добавлен метод format_map, чтобы пере- давать словарь, не распаковывая.
2.18. МОДУЛИ СТАНДАРТНОЙ БИБЛИОТЕКИ
МОДУЛЬ РЕГУЛЯРНЫХ ВЫРАЖЕНИЙ
В модуле
re собраны функции для работы с регулярными выражениями:

search, match и finditer – поиск шаблона, возвращают
MatchObject;

split – разбиение строки по шаблону;

sub – замена подстроки.
MatchObject имеет следующие свой ства:

groups – возвращает сматченные группы;

groupdict – возвращает словарь групп;

start, end, span и pos – возвращают информацию о положении вхождения в строке.
МОДУЛИ FUNCTOOLS И ENUM
В модуле
functools содержатся полезные функции:

1   2   3   4   5   6   7   8   9


написать администратору сайта