10. Коротка екскурсія Стандартною бібліотекою

10.1. Інтерфейс операційної системи

Модуль os надає десятки функцій для взаємодії з операційною системою:

>>> import os
>>> os.getcwd()      # Return the current working directory
'C:\\Python313'
>>> os.chdir('/server/accesslogs')   # Change current working directory
>>> os.system('mkdir today')   # Run the command mkdir in the system shell
0

Обов’язково використовуйте стиль import os замість from os import *. Це не дасть os.open() затіняти вбудовану функцію open(), яка працює значно інакше.

Вбудовані функції dir() і help() корисні як інтерактивні допоміжні засоби для роботи з великими модулями, такими як os:

>>> import os
>>> dir(os)
<returns a list of all module functions>
>>> help(os)
<returns an extensive manual page created from the module's docstrings>

Для щоденних завдань керування файлами та каталогами модуль shutil надає інтерфейс вищого рівня, який легше використовувати:

>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
'archive.db'
>>> shutil.move('/build/executables', 'installdir')
'installdir'

10.2. Символи підстановки файлів

Модуль glob надає функцію для створення списків файлів із пошуку в каталозі за символами підстановки:

>>> import glob
>>> glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']

10.3. Аргументи командного рядка

Common utility scripts often need to process command line arguments. These arguments are stored in the sys module’s argv attribute as a list. For instance, let’s take the following demo.py file:

# File demo.py
import sys
print(sys.argv)

Here is the output from running python demo.py one two three at the command line:

['demo.py', 'one', 'two', 'three']

Модуль argparse забезпечує більш складний механізм обробки аргументів командного рядка. Наступний сценарій витягує одне або кілька імен файлів і необов’язкову кількість рядків для відображення:

import argparse

parser = argparse.ArgumentParser(
    prog='top',
    description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)

Якщо запустити в командному рядку з python top.py --lines=5 alpha.txt beta.txt, сценарій встановлює args.lines значення 5 і args.filenames до ['alpha.txt', 'beta.txt'].

10.4. Перенаправлення виводу помилки та завершення програми

Модуль sys також має атрибути для stdin, stdout і stderr. Останній корисний для видачі попереджень і повідомлень про помилки, щоб зробити їх видимими, навіть якщо stdout було перенаправлено:

>>> sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one

Найпряміший спосіб завершити сценарій – це використати sys.exit().

10.5. Відповідність шаблону рядка

Модуль re надає інструменти регулярних виразів для розширеної обробки рядків. Для складних відповідностей і маніпуляцій регулярні вирази пропонують короткі, оптимізовані рішення:

>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'

Коли потрібні лише прості можливості, краще використовувати рядкові методи, оскільки їх легше читати та налагоджувати:

>>> 'tea for too'.replace('too', 'two')
'tea for two'

10.6. Математика

The math module gives access to the underlying C library functions for floating-point math:

>>> import math
>>> math.cos(math.pi / 4)
0.70710678118654757
>>> math.log(1024, 2)
10.0

Модуль random надає інструменти для випадкового вибору:

>>> import random
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.sample(range(100), 10)   # sampling without replacement
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
>>> random.random()    # random float from the interval [0.0, 1.0)
0.17970987693706186
>>> random.randrange(6)    # random integer chosen from range(6)
4

Модуль statistics обчислює основні статистичні властивості (середнє, медіана, дисперсія тощо) числових даних:

>>> import statistics
>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> statistics.mean(data)
1.6071428571428572
>>> statistics.median(data)
1.25
>>> statistics.variance(data)
1.3720238095238095

Проект SciPy <https://scipy.org> має багато інших модулів для чисельних обчислень.

10.7. Доступ в інтернет

Існує ряд модулів для доступу до Інтернету та обробки Інтернет-протоколів. Двома найпростішими є urllib.request для отримання даних з URL-адрес і smtplib для надсилання пошти:

>>> from urllib.request import urlopen
>>> with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response:
...     for line in response:
...         line = line.decode()             # Convert bytes to a str
...         if line.startswith('datetime'):
...             print(line.rstrip())         # Remove trailing newline
...
datetime: 2022-01-01T01:36:47.689215+00:00

>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
... """To: jcaesar@example.org
... From: soothsayer@example.org
...
... Beware the Ides of March.
... """)
>>> server.quit()

(Зверніть увагу, що для другого прикладу потрібен поштовий сервер, який працює на локальному хості.)

10.8. Дати та час

Модуль datetime містить класи для обробки дат і часу як простими, так і складними способами. Хоча арифметика дати й часу підтримується, основна увага при реалізації зосереджена на ефективному вилученні членів для форматування виводу та маніпуляції. Модуль також підтримує об’єкти, які знають часовий пояс.

>>> # dates are easily constructed and formatted
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2003, 12, 2)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

>>> # dates support calendar arithmetic
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
14368

10.9. Стиснення даних

Загальні формати архівування та стиснення даних безпосередньо підтримуються такими модулями, як: zlib, gzip, bz2, lzma, zipfile і tarfile.

>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41
>>> t = zlib.compress(s)
>>> len(t)
37
>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979

10.10. Вимірювання ефективності

Деякі користувачі Python відчувають глибокий інтерес до знання відносної ефективності різних підходів до однієї проблеми. Python надає інструмент вимірювання, який миттєво відповідає на ці запитання.

Наприклад, може виникнути спокуса використовувати функцію пакування та розпакування кортежів замість традиційного підходу до заміни аргументів. Модуль timeit швидко демонструє помірну перевагу продуктивності:

>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.57535828626024577
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.54962537085770791

На відміну від високого рівня деталізації timeit, модулі profile і pstats надають інструменти для ідентифікації критичних за часом розділів у великих блоках коду.

10.11. Контроль якості

Одним із підходів до розробки високоякісного програмного забезпечення є написання тестів для кожної функції в міру її розробки та часте виконання цих тестів у процесі розробки.

Модуль doctest надає інструмент для сканування модуля та перевірки тестів, вбудованих у рядки документів програми. Побудова тесту така ж проста, як вирізання та вставлення типового виклику разом із його результатами в рядок документації. Це покращує документацію, надаючи користувачеві приклад, і це дозволяє модулю doctest переконатися, що код залишається вірним документації:

def average(values):
    """Computes the arithmetic mean of a list of numbers.

    >>> print(average([20, 30, 70]))
    40.0
    """
    return sum(values) / len(values)

import doctest
doctest.testmod()   # automatically validate the embedded tests

Модуль unittest не такий легкий, як модуль doctest, але він дозволяє підтримувати більш повний набір тестів в окремому файлі:

import unittest

class TestStatisticalFunctions(unittest.TestCase):

    def test_average(self):
        self.assertEqual(average([20, 30, 70]), 40.0)
        self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
        with self.assertRaises(ZeroDivisionError):
            average([])
        with self.assertRaises(TypeError):
            average(20, 30, 70)

unittest.main()  # Calling from the command line invokes all tests

10.12. Батарейки в комплекті

Python має філософію «батареї включені». Це найкраще видно через складні та надійні можливості його більших пакетів. Наприклад:

  • Модулі xmlrpc.client і xmlrpc.server роблять реалізацію викликів віддалених процедур майже тривіальним завданням. Незважаючи на назви модулів, не потрібні прямі знання або робота з XML.

  • Пакет email — це бібліотека для керування повідомленнями електронної пошти, включаючи MIME та інші документи повідомлень на основі RFC 2822. На відміну від smtplib і poplib, які фактично надсилають і отримують повідомлення, пакет електронної пошти має повний набір інструментів для побудови або декодування складних структур повідомлень (включно з вкладеннями) і для реалізації інтернет-кодування та протоколів заголовків.

  • Пакет json забезпечує надійну підтримку аналізу цього популярного формату обміну даними. Модуль csv підтримує пряме читання та запис файлів у форматі значень, розділених комами, який зазвичай підтримується базами даних і електронними таблицями. Обробка XML підтримується пакетами xml.etree.ElementTree, xml.dom і xml.sax. Разом ці модулі та пакети значно спрощують обмін даними між програмами Python та іншими інструментами.

  • Модуль sqlite3 — це оболонка для бібліотеки бази даних SQLite, яка забезпечує постійну базу даних, яку можна оновлювати та отримати до якої можна отримати доступ за допомогою дещо нестандартного синтаксису SQL.

  • Інтернаціоналізація підтримується кількома модулями, зокрема gettext, locale і пакетом codecs.