Язык Python
Стандартные модули python, часть I
Стандартная библиотека python очень обширна. В ней есть инструменты для работы с файловой системой, сервисами операционной системы, поддержка многопоточности, инструменты для работы с сетью и многие другое. В этом разделе мы рассмотрим несколько стандартных модулей python.
Работа с операционной системой
Модуль sys
Модуль sys обеспечивает доступ к параметрам и функциям операционной системы.
Список sys.argv
хранит имя запущенного скрипта и аргументы командной строки, переданные при его запуске:
# test.py
import sys
for idx, item in enumerate(sys.argv):
print(f'Arg {idx}: {item:8} {type(item)}')
user@host:~$ python test.py arg1 arg2 345
Arg 0: test.py <class 'str'>
Arg 1: arg1 <class 'str'>
Arg 2: arg2 <class 'str'>
Arg 3: 345 <class 'str'>
Переменная sys.executable
позволяет узнать какой именно интерпретатор python используется:
print(sys.executable)
# /home/vitaly/miniconda3/envs/tf2/bin/python
Функция sys.exit
позволяет завершить выполнение программы. Эта функция принимает один аргумент — код выхода, который по умолчанию равен нулю. Большинство систем будет считать код 0 признаком успешного завершения программы, а любое другое число от 1 до 127 будет считать признаком ненормального завершения. Если передан объект другого типа, то он будет выведен в стандартный поток вывода, а код выхода будет равен 1. Функция sys.exit
всегда генерирует исключение SystemExit, поэтому не стоит рассматривать ее как стандартный способ завершения программы. Используйте ее только в подходящих случаях, которые чаще всего связаны с невозможностью продолжения работы программы.
Переменная sys.path
обеспечивает доступ к переменной окружения PYTHONPATH
. Эта переменная содержит список путей, в которых выполняется поиск модулей. Если необходимый модуль расположен в директории, которая не входит в PYTHONPATH
, то перед подключением этого модуля необходимо добавить эту директорию в переменную sys.path
:
# 'path/to/my/facorite/module/dir/mymodule.py'
sys.path.append('path/to/my/facorite/module/dir')
import mymodule
Можно указывать абсолютный или относительный путь. Модуль sys имеет еще много инструментов, которые описаны в документации.
Модуль os
Модуль os предоставляет инструменты для работы с операционной системой и файловой системой.
Функции os.getenv и os.putenv позволяют получать и изменять значения переменных окружения. Функция os.system позволяет выполнять консольные команды, запуская при этом дочерний процесс. Рассмотрим следующий скрипт:
# test.py
import os
import sys
print(f' HOME: {os.getenv("HOME")}')
os.putenv('NEWENV', 'value')
print(f'NEWENV: {os.getenv("NEWENV")}')
if os.getenv('NEWENV') is not None:
sys.exit(0)
os.system('python test.py')
При работе скрипта можно получить вывод, подобный такому:
HOME: /home/vitaly
NEWENV: None
HOME: /home/vitaly
NEWENV: value
Разберемся с тем что произошло. Переменная окружения HOME
содержит путь к домашней директории пользователя. Мы получили значение этой переменной с помощью os.genenv
(в данном случае /home/vitaly
) и вывели его в консоль. Затем, c помощью sys.putenv
, мы задали значение value
новой переменной окружения NEWENV
и сразу прочитали его. Функция os.getenv
вернула None
, поскольку функция sys.putenv
оказывает влияние только на окружение дочерних процессов. Чтобы это проверить, мы снова запустили интерпретатор python с нашим скриптом test.py
, используя os.system
. В дочернем процессе снова были выведены переменные окружения HOME
и NEWENV
. В дочернем процессе переменная NEWENV
определена, поэтому сработало условие для выхода из программы с помощью sys.exit(0)
.
Функция os.listdir
возвращает список названий объектов, лежащий в заданной директории.
Модуль os.path
Модуль os.path содержит полезные инструменты для работы с путями файловой системы. Функция os.path.exists проверяет указывает ли путь на существующий объект в файловой системе. Функция os.path.isfile имеет схожий смысл, но возвращает True
только в том случае, если объект является обычным файлом (не директория и не ссылка):
os.path.exists('/home/vitaly') # True
os.path.exists('/home/david') # False
os.path.isfile('/home/vitaly') # False
Функции os.path.join
, os.path.split
и os.path.splitext
выполняют часто встречающиеся манипуляции со строками путей:
path = os.path.join('/home', 'vitaly', 'test.py')
# /home/vitaly/test.py
head, tail = os.path.split(path) # ['/home/vitaly', 'test.py']
root, ext = os.path.splitext(path) # ['/home/vitaly/test', '.py']
Модуль shutil
Модуль shutil
предоставляет высокоуровневые инструменты для операций с файлами. Вот несколько примеров:
# копирование файла в директорию
shutil.copy('filename', 'path/to/dir')
# копирование файла в файл с другим именем
shutil.copyfile('filename1', 'filename2')
# рекурсивное копирование директории dir1 в директорию dir2
shutil.copytree('path/to/dir1', 'path/to/dir2')
# рекурсивное удаление содержимого директории dir
shutil.rmtree('path/to/dir')
# рекурсивное перемещение файла или директории
shutil.move(src, dst)
Модуль glob
Модуль glob
позволяет выполнять поиск объектов в файловой системе, имена которых удовлетворяют заданному паттерну:
# список текстовых файлов в текущей директории
text_files = glob.glob('./*.txt')
# рекурсивный поиск файлов с расширением .py,
# начиная с текущей директории
text_files_all = glob.glob('./**/*.py', recursive=True)
Работа со строками
Модуль string
Модуль string
содержит различные инструменты для работы со строками, многие из которых дублируют возможности стандартного типа str
. Модуль string
содержит набор констант, которые часто оказываются полезны:
string.ascii_lowercase # 'abcdefghijklmnopqrstuvwxyz'
string.ascii_uppercase # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
string.ascii_letters
# 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
string.digits # '0123456789'
string.punctuation # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Модуль re
Модуль re
содержит инструменты для работы с регулярными выражениями. Обсуждение регулярных выражений выходит за рамки этого курса. Мы рекомендуем читателю самостоятельно изучить базовые приемы работы с регулярными выражениями.
Вычисления с произвольной точностью
Модуль decimal
Модуль decimal
позволяет выполнять арифметические операции с плавающей точной с фиксированной точностью:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7) # Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7) # Decimal('0.1428571428571428571428571429')
Объекты Decimal
представлены в памяти точно. Это значит, что числа Decimal
можно сравнивать с помощью операторов ==
и !=
, не опасаясь погрешности из-за округления двоичного представления (как это происходит в случае с типом float
).
В модуле decimal
доступны некоторые математические функции:
getcontext().prec = 28
Decimal(2).sqrt() # Decimal('1.414213562373095048801688724')
Decimal(1).exp() # Decimal('2.718281828459045235360287471')
Decimal('10').ln() # Decimal('2.302585092994045684017991455')
Decimal('10').log10() # Decimal('1')
Модуль fractions
Тип Fraction
из модуля fractions
описывает рациональные числа — числа, которые можно представить в виде обыкновенной дроби:
from fractions import Fraction
from math import pi, cos
Fraction(16, -10) # Fraction(-8, 5)
Fraction('3.1415926535897932').limit_denominator(1000)
# Fraction(355, 113)
Fraction(cos(pi/3)) # Fraction(4503599627370497, 9007199254740992)
В последнем примере мы воспользовались модулем math
, который мы не будем обсуждать, поскольку его возможности перекрываются модулем numpy
. Модуль numpy
будет рассмотрен в следующих частях.
Продвинутые структуры данных и эффективное итерирование
Модуль queue
Модуль queue
содержит реализацию нескольких структур данных, среди которых FIFO-очередь queue.Queue
и очередь с приоритетом queue.PriorityQueue
. Очередь с приоритетом возвращает не первый добавленный элемент, а наименьший:
from queue import Queue, PriorityQueue
arr = [3, 6, 1, 9, 4, 7, 2, 5, 8, 1]
q = Queue()
for i in arr:
q.put_nowait(i)
while not q.empty():
print(q.get_nowait(), end=' ')
# 3 6 1 9 4 7 2 5 8 1
pq = PriorityQueue()
for i in arr:
pq.put_nowait(i)
while not pq.empty():
print(pq.get_nowait(), end=' ')
# 1 1 2 3 4 5 6 7 8 9
Типы модуля queue
созданы для работы в многопоточной среде исполнения. С особенностями многопоточной работы, которые мы не будем обсуждать, связано использование методов get_nowait
и put_nowait
вместо get
и put
.
Модуль collections
Модуль collections
расширяет набор стандартных контейнеров python. Рассмотрим три типа данных из этого модуля.
Функция namedtuple()
позволяет создавать типы данных с именованными полями:
from collections import namedtuple
Vector = namedtuple('Vector', ['x', 'y', 'z'])
v1 = Vector(1., 0.5, 0.6)
v1.x # 1.
v1.y # 0.5
v1.z # 0.6
Тип deque
реализует контейнер двусторонняя очередь, или дек. Это последовательный контейнер, который позволяет эффективно добавлять и удалять элементы в начало и в конец:
from collections import deque
deq = deque([1, 3, 5])
deq.append('a') # [1, 3, 5, 'a']
deq.appendleft(False) # [False, 1, 3, 5, 'a']
a = deq.pop() # a = 'a', deq = ['False', 1, 3, 5]
b = deq.popleft() # b = False, deq = [1, 3, 5]
Тип Counter
является подклассом типа dict
и позволяет удобно подсчитывать количество вхождений элементов в контейнере, например:
from collections import Counter
the_longest_word_in_english\
= 'pneumonoultramicroscopicsilicovolcanoconiosis'
cnt = Counter(the_longest_word_in_english)
for key, val in cnt.items():
print(f'{key}: {val}', end=', ')
# p: 2, n: 4, e: 1, u: 2, m: 2, o: 9, l: 3, t: 1, r: 2, a: 2, i: 6, c: 6, s: 4, v: 1
cnt.most_common(1) # [('o', 9)]
Модуль itertools
Модуль itertools
содержит множество инструментов для эффективного итерирования по элементам контейнеров. Эффективное в данном случае означает, что необходимое следующее значение генерируется на лету, без хранения всех значений, количество которых может быть очень большое. Рассмотрим несколько инструментов из этого модуля:
import itertools
arr = list(range(5)) # arr = [0, 1, 2, 3, 4]
for item in itertools.accumulate(arr):
print(item, end=' ')
# 0 1 3 6 10
for perm in itertools.permutations(arr):
print(''.join(map(str, perm)), end=' ')
# 01234 01243 01324 01342 01423 01432 ...
for comb in itertools.combinations(arr, 3):
print(''.join(map(str, comb)), end=' ')
# 012 013 014 023 024 034 123 124 134 234
Время и дата с модулем datetime
Модуль datetime
позволяет полноценно работать с объектами даты и времени:
from datetime import date, timedelta
d1 = date.fromisoformat('2019-12-04')
d2 = date(2002, 12, 31)
d1 < d2 # False
delta = d1 - d2
delta.days # 6182
type(delta) # <class 'datetime.timedelta'>
delta2 = timedelta(days=15)
d3 = d1 + delta2 # 2019-12-19
d3.weekday() # 3 (Среда)
d4 = date.today() # 2020-07-15
import time
from datetime import datetime
dt1 = datetime.fromtimestamp(time.time()) # 2020-07-15 21:47:09.036145
dt2 = datetime.fromisoformat('2020-07-15 21:47:09.036145')
dt2.timestamp() # 1594824429.036145 (секунд прошло с 1970-01-01)
Резюме
В этом разделе мы выполнили краткий обзор возможностей некоторых стандартных модулей языка python. На этаме планирования нового проекта на python разумно изучить возможности существующих модулей (не только стандартных). Большое сообщество разработчиков и разнообразие доступных модулей являются сильными сторонами python.