> **Источник:** https://python-all.ru/3.2/faq/library.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# [Часто задаваемые вопросы по библиотекам и расширениям](https://python-all.ru/3.2/faq/library.html#id1)

Содержание

- [FAQ по библиотекам и расширениям](https://python-all.ru/3.2/faq/library.html#library-and-extension-faq)

  - [Общие вопросы по библиотекам](https://python-all.ru/3.2/faq/library.html#general-library-questions)

    - [Как найти модуль или приложение для выполнения задачи X?](https://python-all.ru/3.2/faq/library.html#how-do-i-find-a-module-or-application-to-perform-task-x)
    - [Где находится исходный файл math.py (socket.py, regex.py и т.д.)?](https://python-all.ru/3.2/faq/library.html#where-is-the-math-py-socket-py-regex-py-etc-source-file)
    - [Как сделать скрипт Python исполняемым в Unix?](https://python-all.ru/3.2/faq/library.html#how-do-i-make-a-python-script-executable-on-unix)
    - [Существует ли пакет curses/termcap для Python?](https://python-all.ru/3.2/faq/library.html#is-there-a-curses-termcap-package-for-python)
    - [Есть ли в Python эквивалент onexit() из C?](https://python-all.ru/3.2/faq/library.html#is-there-an-equivalent-to-c-s-onexit-in-python)
    - [Почему не работают мои обработчики сигналов?](https://python-all.ru/3.2/faq/library.html#why-don-t-my-signal-handlers-work)
  - [Типовые задачи](https://python-all.ru/3.2/faq/library.html#common-tasks)

    - [Как протестировать программу или компонент Python?](https://python-all.ru/3.2/faq/library.html#how-do-i-test-a-python-program-or-component)
    - [Как создать документацию из строк документации?](https://python-all.ru/3.2/faq/library.html#how-do-i-create-documentation-from-doc-strings)
    - [Как получить одиночное нажатие клавиши?](https://python-all.ru/3.2/faq/library.html#how-do-i-get-a-single-keypress-at-a-time)
  - [Потоки](https://python-all.ru/3.2/faq/library.html#threads)

    - [Как программировать с использованием потоков?](https://python-all.ru/3.2/faq/library.html#how-do-i-program-using-threads)
    - [Ни один из моих потоков не запускается: почему?](https://python-all.ru/3.2/faq/library.html#none-of-my-threads-seem-to-run-why)
    - [Как распределить работу между несколькими рабочими потоками?](https://python-all.ru/3.2/faq/library.html#how-do-i-parcel-out-work-among-a-bunch-of-worker-threads)
    - [Какие виды изменения глобальных значений являются потокобезопасными?](https://python-all.ru/3.2/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe)
    - [Нельзя ли избавиться от глобальной блокировки интерпретатора (GIL)?](https://python-all.ru/3.2/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock)
  - [Ввод и вывод](https://python-all.ru/3.2/faq/library.html#input-and-output)

    - [Как удалить файл? (И другие вопросы о файлах...)](https://python-all.ru/3.2/faq/library.html#how-do-i-delete-a-file-and-other-file-questions)
    - [Как скопировать файл?](https://python-all.ru/3.2/faq/library.html#how-do-i-copy-a-file)
    - [Как читать (или записывать) двоичные данные?](https://python-all.ru/3.2/faq/library.html#how-do-i-read-or-write-binary-data)
    - [Не удаётся использовать os.read() на канале, созданном с помощью os.popen(); почему?](https://python-all.ru/3.2/faq/library.html#i-can-t-seem-to-use-os-read-on-a-pipe-created-with-os-popen-why)
    - [Как получить доступ к последовательному порту (RS232)?](https://python-all.ru/3.2/faq/library.html#how-do-i-access-the-serial-rs232-port)
    - [Почему закрытие sys.stdout (stdin, stderr) на самом деле не закрывает его?](https://python-all.ru/3.2/faq/library.html#why-doesn-t-closing-sys-stdout-stdin-stderr-really-close-it)
  - [Сетевое и интернет-программирование](https://python-all.ru/3.2/faq/library.html#network-internet-programming)

    - [Какие существуют инструменты для работы с WWW в Python?](https://python-all.ru/3.2/faq/library.html#what-www-tools-are-there-for-python)
    - [Как имитировать отправку CGI-формы (METHOD=POST)?](https://python-all.ru/3.2/faq/library.html#how-can-i-mimic-cgi-form-submission-method-post)
    - [Какой модуль использовать для генерации HTML?](https://python-all.ru/3.2/faq/library.html#what-module-should-i-use-to-help-with-generating-html)
    - [Как отправить письмо из скрипта Python?](https://python-all.ru/3.2/faq/library.html#how-do-i-send-mail-from-a-python-script)
    - [Как избежать блокировки в методе connect() сокета?](https://python-all.ru/3.2/faq/library.html#how-do-i-avoid-blocking-in-the-connect-method-of-a-socket)
  - [Базы данных](https://python-all.ru/3.2/faq/library.html#databases)

    - [Существуют ли интерфейсы к пакетам баз данных в Python?](https://python-all.ru/3.2/faq/library.html#are-there-any-interfaces-to-database-packages-in-python)
    - [Как реализовать постоянные объекты в Python?](https://python-all.ru/3.2/faq/library.html#how-do-you-implement-persistent-objects-in-python)
  - [Математика и численные методы](https://python-all.ru/3.2/faq/library.html#mathematics-and-numerics)

    - [Как генерировать случайные числа в Python?](https://python-all.ru/3.2/faq/library.html#how-do-i-generate-random-numbers-in-python)

## [Общие вопросы по библиотекам](https://python-all.ru/3.2/faq/library.html#id2)

### [Как найти модуль или приложение для выполнения задачи X?](https://python-all.ru/3.2/faq/library.html#id3)

Проверьте [*справочник библиотеки*](https://python-all.ru/3.2/library/index.html#library-index), чтобы узнать, есть ли подходящий модуль в стандартной библиотеке. (Со временем вы запомните, что входит в стандартную библиотеку, и сможете пропустить этот шаг.)

Для сторонних пакетов выполните поиск в [Python Package Index](https://python-all.ru/3.2/faq/library.html) или воспользуйтесь [Google](https://python-all.ru/3.2/faq/library.html) или другой поисковой системой. Обычно поиск по «Python» с одним-двумя ключевыми словами по вашей теме находит что-нибудь полезное.

### [Где находится исходный файл math.py (socket.py, regex.py и т. д.)?](https://python-all.ru/3.2/faq/library.html#id4)

Если не удаётся найти исходный файл модуля, возможно, это встроенный или динамически загружаемый модуль, реализованный на C, C++ или другом компилируемом языке. В таком случае исходного файла может не быть, или он может находиться где-то вроде `mathmodule.c` в каталоге исходного кода на C (а не в путях Python).

В Python существует (как минимум) три вида модулей:

1. модули, написанные на Python (.py);
2. модули, написанные на C и динамически загружаемые (.dll, .pyd, .so, .sl и т. д.);
3. модули, написанные на C и связанные с интерпретатором; чтобы получить их список, введите:

   ```python
   import sys
   print(sys.builtin_module_names)
   ```

### [Как сделать скрипт Python исполняемым в Unix?](https://python-all.ru/3.2/faq/library.html#id5)

Нужно сделать две вещи: установить исполняемый режим для файла скрипта и убедиться, что первая строка начинается с `#!`, за которым следует путь к интерпретатору Python.

Первый способ: выполнить `chmod +x scriptfile` или, возможно, `chmod 755 scriptfile`.

Второе можно сделать несколькими способами. Самый простой – написать

```python
#!/usr/local/bin/python
```

в самой первой строке файла, указав путь к установленному на вашей платформе интерпретатору Python.

Если нужно, чтобы скрипт не зависел от расположения интерпретатора Python, можно воспользоваться программой **env**. Почти все варианты Unix поддерживают следующее (при условии, что интерпретатор Python находится в каталоге, указанном в переменной `PATH` пользователя):

```python
#!/usr/bin/env python
```

*Не делайте* этого для CGI-скриптов. Переменная `PATH` для CGI-скриптов часто очень ограничена, поэтому нужно указывать фактический абсолютный путь к интерпретатору.

Иногда окружение пользователя настолько переполнено, что программа **/usr/bin/env** завершается с ошибкой; или программы env вообще нет. В таком случае можно попробовать следующий трюк (благодаря Алексу Резински):

```python
#! /bin/sh
""":"
exec python $0 ${1+"$@"}
"""
```

Небольшой недостаток в том, что при этом определяется строка документации \_\_doc\_\_ скрипта. Однако это можно исправить, добавив

```python
__doc__ = """...Whatever..."""
```

### [Существует ли пакет curses/termcap для Python?](https://python-all.ru/3.2/faq/library.html#id6)

Для вариантов Unix: стандартный дистрибутив исходного кода Python поставляется с модулем curses в подкаталоге [Modules](https://python-all.ru/3.2/faq/library.html), хотя по умолчанию он не компилируется. (Обратите внимание, что в дистрибутиве Windows его нет – модуля curses для Windows не существует.)

Модуль [`curses`](https://python-all.ru/3.2/library/curses.html#module-curses) поддерживает базовые возможности curses, а также множество дополнительных функций из ncurses и SYSV curses: цвет, поддержку альтернативных наборов символов, панели (pads) и поддержку мыши. Это означает, что модуль несовместим с операционными системами, в которых есть только BSD curses, но, по-видимому, в настоящее время нет ни одной поддерживаемой ОС из этой категории.

Для Windows: используйте [модуль consolelib](https://python-all.ru/3.2/faq/library.html).

### [Есть ли в Python аналог onexit() из C?](https://python-all.ru/3.2/faq/library.html#id7)

Модуль [`atexit`](https://python-all.ru/3.2/library/atexit.html#module-atexit) предоставляет функцию register, аналогичную C-функции `onexit()`.

### [Почему не работают мои обработчики сигналов?](https://python-all.ru/3.2/faq/library.html#id8)

Самая распространённая проблема – обработчик сигнала объявлен с неправильным списком аргументов. Он вызывается как

```python
handler(signum, frame)
```

поэтому он должен быть объявлен с двумя аргументами:

```python
def handler(signum, frame):
    ...
```

## [Типовые задачи](https://python-all.ru/3.2/faq/library.html#id9)

### [Как тестировать программу или компонент Python?](https://python-all.ru/3.2/faq/library.html#id10)

В состав Python входят два фреймворка для тестирования. Модуль [`doctest`](https://python-all.ru/3.2/library/doctest.html#module-doctest) находит примеры в строках документации модуля и запускает их, сравнивая вывод с ожидаемым результатом, указанным в docstring.

Модуль [`unittest`](https://python-all.ru/3.2/library/unittest.html#module-unittest) – это более продвинутый фреймворк для тестирования, созданный по образцу фреймворков Java и Smalltalk.

Чтобы упростить тестирование, используйте в программе хорошую модульную архитектуру. Почти вся функциональность должна быть инкапсулирована в функции или методы классов – и это иногда неожиданно и приятно ускоряет работу программы (потому что доступ к локальным переменным быстрее, чем к глобальным). Кроме того, программа не должна зависеть от изменения глобальных переменных, поскольку это сильно усложняет тестирование.

«Глобальная основная логика» вашей программы может быть такой же простой, как

```python
if __name__ == "__main__":
    main_logic()
```

в конце главного модуля программы.

Когда программа организована как управляемая коллекция функций и поведений классов, следует написать тестовые функции, которые проверяют эти поведения. Тестовый набор, автоматизирующий последовательность тестов, можно связать с каждым модулем. Это звучит как большая работа, но, поскольку Python так краток и гибок, это оказывается удивительно легко. Писать код становится гораздо приятнее и веселее, если создавать тестовые функции параллельно с «рабочим кодом», поскольку это позволяет раньше находить ошибки и даже проектные недостатки.

«Вспомогательные модули», не предназначенные для роли главного модуля программы, могут включать самопроверку модуля.

```python
if __name__ == "__main__":
    self_test()
```

Даже программы, взаимодействующие со сложными внешними интерфейсами, могут быть протестированы в отсутствие этих интерфейсов с помощью «фиктивных» интерфейсов, реализованных на Python.

### [Как создавать документацию из строк документации?](https://python-all.ru/3.2/faq/library.html#id11)

Модуль [`pydoc`](https://python-all.ru/3.2/library/pydoc.html#module-pydoc) умеет создавать HTML из строк документации в исходном коде Python. Альтернатива для создания API-документации исключительно из docstrings – [epydoc](https://python-all.ru/3.2/faq/library.html). [Sphinx](https://python-all.ru/3.2/faq/library.html) также может включать содержимое docstring.

### [Как получить нажатие одной клавиши за раз?](https://python-all.ru/3.2/faq/library.html#id12)

Для Unix-подобных систем есть несколько решений. Это несложно сделать с помощью curses, но curses – довольно большой модуль для изучения.

## [Потоки](https://python-all.ru/3.2/faq/library.html#id13)

### [Как программировать с помощью потоков?](https://python-all.ru/3.2/faq/library.html#id14)

Обязательно используйте модуль [`threading`](https://python-all.ru/3.2/library/threading.html#module-threading), а не модуль [`_thread`](https://python-all.ru/3.2/library/_thread.html#module-_thread). Модуль [`threading`](https://python-all.ru/3.2/library/threading.html#module-threading) предоставляет удобные абстракции поверх низкоуровневых примитивов, реализованных в модуле [`_thread`](https://python-all.ru/3.2/library/_thread.html#module-_thread).

У Aahz есть набор слайдов из его руководства по многопоточности, которые могут быть полезны; см. [http://www.pythoncraft.com/OSCON2001/](https://python-all.ru/3.2/faq/library.html).

### [Почему ни один из моих потоков не выполняется?](https://python-all.ru/3.2/faq/library.html#id15)

Как только главный поток завершается, все потоки уничтожаются. Главный поток выполняется слишком быстро, не давая потокам времени на работу.

Простое исправление – добавить в конец программы задержку, достаточно длинную для завершения всех потоков:

```python
import threading, time

def thread_task(name, n):
    for i in range(n): print(name, i)

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10)  # <---------------------------!
```

Но теперь (на многих платформах) потоки не выполняются параллельно, а, похоже, выполняются последовательно, один за другим! Причина в том, что планировщик потоков ОС не запускает новый поток, пока предыдущий не заблокирован.

Простое исправление – добавить небольшую задержку в начало функции run:

```python
def thread_task(name, n):
    time.sleep(0.001)  # <--------------------!
    for i in range(n): print(name, i)

for i in range(10):
    T = threading.Thread(target=thread_task, args=(str(i), i))
    T.start()

time.sleep(10)
```

Вместо того чтобы пытаться угадать подходящее значение задержки для [`time.sleep()`](https://python-all.ru/3.2/library/time.html#time.sleep), лучше использовать какой-нибудь механизм семафора. Одна из идей – воспользоваться модулем [`queue`](https://python-all.ru/3.2/library/queue.html#module-queue) для создания объекта очереди: пусть каждый поток по завершении добавляет в очередь токен, а главный поток читает из очереди столько токенов, сколько было потоков.

### [Как распределить работу между несколькими рабочими потоками?](https://python-all.ru/3.2/faq/library.html#id16)

The easiest way is to use the new [`concurrent.futures`](https://python-all.ru/3.2/library/concurrent.futures.html#module-concurrent.futures) module, especially the [`ThreadPoolExecutor`](https://python-all.ru/3.2/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor) class.

Или, если требуется тонкий контроль над алгоритмом диспетчеризации, можно написать собственную логику вручную. Используйте модуль [`queue`](https://python-all.ru/3.2/library/queue.html#module-queue) для создания очереди, содержащей список заданий. Класс [`Queue`](https://python-all.ru/3.2/library/queue.html#queue.Queue) хранит список объектов, имеет метод `.put(obj)` для добавления элементов в очередь и метод `.get()` для их получения. Класс позаботится о блокировках, необходимых для того, чтобы каждое задание было выдано ровно один раз.

Вот простой пример:

```python
import threading, queue, time

# Рабочий поток забирает задания из очереди. Когда очередь пуста, он
# предполагает, что больше работы не будет, и завершается.
# (На практике рабочие потоки работают до принудительного завершения.)
def worker():
    print('Running worker')
    time.sleep(0.1)
    while True:
        try:
            arg = q.get(block=False)
        except queue.Empty:
            print('Worker', threading.currentThread(), end=' ')
            print('queue empty')
            break
        else:
            print('Worker', threading.currentThread(), end=' ')
            print('running with argument', arg)
            time.sleep(0.5)

# Создать очередь
q = queue.Queue()

# Запустить пул из 5 рабочих потоков
for i in range(5):
    t = threading.Thread(target=worker, name='worker %i' % (i+1))
    t.start()

# Начать добавление заданий в очередь
for i in range(50):
    q.put(i)

# Дать потокам время на выполнение
print('Main thread sleeping')
time.sleep(5)
```

При запуске это выдаст следующий вывод:

```text
Running worker
Running worker
Running worker
Running worker
Running worker
Main thread sleeping
Worker <Thread(worker 1, started 130283832797456)> running with argument 0
Worker <Thread(worker 2, started 130283824404752)> running with argument 1
Worker <Thread(worker 3, started 130283816012048)> running with argument 2
Worker <Thread(worker 4, started 130283807619344)> running with argument 3
Worker <Thread(worker 5, started 130283799226640)> running with argument 4
Worker <Thread(worker 1, started 130283832797456)> running with argument 5
...
```

Обратитесь к документации модуля за подробностями; класс [`Queue`](https://python-all.ru/3.2/library/queue.html#queue.Queue) предоставляет богатый интерфейс.

### [Какие виды изменения глобальных значений потокобезопасны?](https://python-all.ru/3.2/faq/library.html#id17)

Внутренне используется [*глобальная блокировка интерпретатора*](https://python-all.ru/3.2/glossary.html#term-global-interpreter-lock) (GIL), чтобы гарантировать, что в виртуальной машине Python в каждый момент времени выполняется только один поток. В целом Python может переключаться между потоками только между инструкциями байт-кода; частота переключения задаётся через [`sys.setswitchinterval()`](https://python-all.ru/3.2/library/sys.html#sys.setswitchinterval). Каждая инструкция байт-кода, а следовательно, и весь код на C, вызываемый из неё, является атомарным с точки зрения программы на Python.

Теоретически это означает, что точный учёт требует точного понимания реализации байткода виртуальной машины Python. На практике это означает, что операции над совместно используемыми переменными встроенных типов (int, list, dict и т.д.), которые «выглядят атомарными», действительно атомарны.

Например, следующие операции атомарны (L, L1, L2 – списки, D, D1, D2 – словари, x, y – объекты, i, j – целые числа):

```python
L.append(x)
L1.extend(L2)
x = L[i]
x = L.pop()
L1[i:j] = L2
L.sort()
x = y
x.field = y
D[x] = y
D1.update(D2)
D.keys()
```

А эти – нет:

```python
i = i+1
L.append(L[-1])
L[i] = L[j]
D[x] = D[x] + 1
```

Операции, замещающие другие объекты, могут вызвать метод [`__del__()`](https://python-all.ru/3.2/reference/datamodel.html#object.__del__) этих объектов, когда их счётчик ссылок достигает нуля, и это может повлиять на выполнение. Особенно это касается массовых обновлений словарей и списков. В сомнительных случаях используйте мьютекс!

### [Нельзя ли избавиться от глобальной блокировки интерпретатора?](https://python-all.ru/3.2/faq/library.html#id18)

[*Глобальная блокировка интерпретатора*](https://python-all.ru/3.2/glossary.html#term-global-interpreter-lock) (GIL) часто считается помехой для развёртывания Python на высокопроизводительных многопроцессорных серверных машинах, поскольку многопоточная программа на Python фактически использует только один процессор из-за требования, что (почти) весь код Python может выполняться только при удерживаемом GIL.

Во времена Python 1.5 Грег Стайн реализовал обширный набор патчей (так называемые «free threading» патчи), который удалял GIL и заменял его более мелкозернистой блокировкой. Недавно Адам Олсен провёл похожий эксперимент в своём проекте [python-safethread](https://python-all.ru/3.2/faq/library.html). К сожалению, оба эксперимента продемонстрировали резкое падение производительности в однопоточном режиме (как минимум на 30%), из-за большого количества мелкозернистых блокировок, необходимых для компенсации удаления GIL.

Это не значит, что Python нельзя эффективно использовать на многопроцессорных машинах! Просто нужно творчески подойти к разделению работы между несколькими *процессами*, а не несколькими *потоками*. Класс [`ProcessPoolExecutor`](https://python-all.ru/3.2/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) из нового модуля [`concurrent.futures`](https://python-all.ru/3.2/library/concurrent.futures.html#module-concurrent.futures) предоставляет простой способ сделать это; модуль [`multiprocessing`](https://python-all.ru/3.2/library/multiprocessing.html#module-multiprocessing) предоставляет API более низкого уровня, если требуется больше контроля над диспетчеризацией задач.

Разумное использование расширений на C также помогает: если с помощью расширения на C выполняется трудоёмкая задача, расширение может освободить GIL, пока поток выполнения находится в коде C, и позволить другим потокам поработать. Некоторые модули стандартной библиотеки, такие как [`zlib`](https://python-all.ru/3.2/library/zlib.html#module-zlib) и [`hashlib`](https://python-all.ru/3.2/library/hashlib.html#module-hashlib), уже так делают.

Высказывались предложения сделать GIL блокировкой на уровне состояния интерпретатора, а не глобальной; тогда интерпретаторы не смогли бы обмениваться объектами. К сожалению, это тоже вряд ли произойдёт. Это потребовало бы огромного объёма работы, поскольку многие реализации объектов в настоящее время используют глобальное состояние. Например, небольшие целые числа и короткие строки кэшируются; эти кэши пришлось бы перенести в состояние интерпретатора. Другие типы объектов имеют свои собственные списки свободной памяти; эти списки также пришлось бы перенести. И так далее.

И я сомневаюсь, что это вообще можно сделать за конечное время, потому что та же проблема существует и для сторонних расширений. Скорее всего, сторонние расширения пишутся быстрее, чем вы успеваете переделывать их для хранения всего глобального состояния в состоянии интерпретатора.

И наконец, если у вас есть несколько интерпретаторов, не разделяющих состояние, что вы выигрываете по сравнению с запуском каждого интерпретатора в отдельном процессе?

## [Ввод и вывод](https://python-all.ru/3.2/faq/library.html#id19)

### [Как удалить файл? (И другие вопросы о файлах...)](https://python-all.ru/3.2/faq/library.html#id20)

Используйте `os.remove(filename)` или `os.unlink(filename)`; документацию см. в модуле [`os`](https://python-all.ru/3.2/library/os.html#module-os). Эти две функции идентичны; [`unlink()`](https://python-all.ru/3.2/library/os.html#os.unlink) – это просто имя системного вызова Unix для данной функции.

Для удаления каталога используйте [`os.rmdir()`](https://python-all.ru/3.2/library/os.html#os.rmdir); чтобы создать каталог – [`os.mkdir()`](https://python-all.ru/3.2/library/os.html#os.mkdir). `os.makedirs(path)` создаст все промежуточные каталоги в `path`, которые отсутствуют. `os.removedirs(path)` удалит промежуточные каталоги, если они пусты; если нужно удалить всё дерево каталогов вместе с содержимым, используйте [`shutil.rmtree()`](https://python-all.ru/3.2/library/shutil.html#shutil.rmtree).

Для переименования файла используйте `os.rename(old_path, new_path)`.

Чтобы обрезать файл, откройте его с помощью `f = open(filename, "rb+")`, а затем используйте `f.truncate(offset)`; offset по умолчанию равен текущей позиции. Также есть `os.ftruncate(fd, offset)` для файлов, открытых через [`os.open()`](https://python-all.ru/3.2/library/os.html#os.open), где *fd* – это файловый дескриптор (небольшое целое число).

Модуль [`shutil`](https://python-all.ru/3.2/library/shutil.html#module-shutil) также содержит ряд функций для работы с файлами, включая [`copyfile()`](https://python-all.ru/3.2/library/shutil.html#shutil.copyfile), [`copytree()`](https://python-all.ru/3.2/library/shutil.html#shutil.copytree) и [`rmtree()`](https://python-all.ru/3.2/library/shutil.html#shutil.rmtree).

### [Как скопировать файл?](https://python-all.ru/3.2/faq/library.html#id21)

Модуль [`shutil`](https://python-all.ru/3.2/library/shutil.html#module-shutil) содержит функцию [`copyfile()`](https://python-all.ru/3.2/library/shutil.html#shutil.copyfile). Обратите внимание: в MacOS 9 она не копирует ветвь ресурсов (resource fork) и информацию Finder.

### [Как читать (или записывать) двоичные данные?](https://python-all.ru/3.2/faq/library.html#id22)

Для чтения и записи сложных двоичных форматов данных лучше всего использовать модуль [`struct`](https://python-all.ru/3.2/library/struct.html#module-struct). Он позволяет взять строку, содержащую двоичные данные (обычно числа), и преобразовать её в объекты Python; и наоборот.

Например, следующий код читает из файла два 2-байтовых целых числа и одно 4-байтовое целое число в формате big-endian:

```python
import struct

with open(filename, "rb") as f:
   s = f.read(8)
   x, y, z = struct.unpack(">hhl", s)
```

Символ ‘\>’ в строке формата указывает на порядок байтов big-endian; буква ‘h’ читает одно «короткое целое» (2 байта), а ‘l’ – одно «длинное целое» (4 байта) из строки.

Для более регулярных данных (например, однородного списка целых чисел или чисел с плавающей запятой) можно также использовать модуль [`array`](https://python-all.ru/3.2/library/array.html#module-array).

> **Примечание**
>
> Для чтения и записи двоичных данных файл необходимо открывать в двоичном режиме (в данном случае передавая `"rb"` в [`open()`](https://python-all.ru/3.2/library/functions.html#open)). Если вместо этого использовать `"r"` (режим по умолчанию), файл откроется в текстовом режиме, и `f.read()` будет возвращать объекты [`str`](https://python-all.ru/3.2/library/functions.html#str), а не [`bytes`](https://python-all.ru/3.2/library/functions.html#bytes).

### [Не удаётся использовать os.read() для канала, созданного с помощью os.popen(); почему?](https://python-all.ru/3.2/faq/library.html#id23)

[`os.read()`](https://python-all.ru/3.2/library/os.html#os.read) – низкоуровневая функция, принимающая файловый дескриптор – небольшое целое число, представляющее открытый файл. `os.popen()` создаёт высокоуровневый файловый объект того же типа, что и встроенная функция [`open()`](https://python-all.ru/3.2/library/functions.html#open). Таким образом, чтобы прочитать *n* байт из канала *p*, созданного с помощью `os.popen()`, нужно использовать `p.read(n)`.

### [Как получить доступ к последовательному порту (RS232)?](https://python-all.ru/3.2/faq/library.html#id24)

Для Win32, POSIX (Linux, BSD и т. д.), Jython:

> [http://pyserial.sourceforge.net](https://python-all.ru/3.2/faq/library.html)

Для Unix смотрите сообщение в Usenet от Митча Чепмена:

> [http://groups.google.com/groups?selm=34A04430.CF9@ohioee.com](https://python-all.ru/3.2/faq/library.html)

### [Почему закрытие sys.stdout (stdin, stderr) на самом деле не закрывает его?](https://python-all.ru/3.2/faq/library.html#id25)

Python [*file objects*](https://python-all.ru/3.2/glossary.html#term-file-object) are a high-level layer of abstraction on low-level C file descriptors.

Для большинства файловых объектов, создаваемых в Python с помощью встроенной функции [`open()`](https://python-all.ru/3.2/library/functions.html#open), вызов `f.close()` помечает файловый объект Python как закрытый с точки зрения Python, а также обеспечивает закрытие нижележащего дескриптора файла C. Это также происходит автоматически в деструкторе `f`, когда `f` становится мусором.

Но stdin, stdout и stderr обрабатываются Python особым образом из-за особого статуса, который им присваивается в C. Вызов `sys.stdout.close()` помечает файловый объект на уровне Python как закрытый, но *не* закрывает соответствующий дескриптор файла C.

Чтобы закрыть нижележащий дескриптор файла C для одного из этих трёх, сначала следует убедиться, что это действительно нужно сделать (например, это может запутать модули расширения, пытающиеся выполнять ввод-вывод). Если это так, следует использовать [`os.close()`](https://python-all.ru/3.2/library/os.html#os.close):

```python
os.close(stdin.fileno())
os.close(stdout.fileno())
os.close(stderr.fileno())
```

Или можно использовать числовые константы 0, 1 и 2 соответственно.

## [Сетевое и интернет-программирование](https://python-all.ru/3.2/faq/library.html#id26)

### [Какие WWW-инструменты есть для Python?](https://python-all.ru/3.2/faq/library.html#id27)

Смотрите главы [*Интернет-протоколы и поддержка*](https://python-all.ru/3.2/library/internet.html#internet) и [*Обработка интернет-данных*](https://python-all.ru/3.2/library/netdata.html#netdata) в Справочном руководстве по библиотеке Python. В Python есть много модулей, которые помогут создать веб-системы как на стороне сервера, так и на стороне клиента.

Сводка доступных фреймворков поддерживается Полом Бодди на [http://wiki.python.org/moin/WebProgramming](https://python-all.ru/3.2/faq/library.html).

Кэмерон Лэрд поддерживает полезный набор страниц о веб-технологиях Python по адресу [http://phaseit.net/claird/comp.lang.python/web\_python](https://python-all.ru/3.2/faq/library.html).

### [Как имитировать отправку CGI-формы (METHOD=POST)?](https://python-all.ru/3.2/faq/library.html#id28)

Мне нужно получать веб-страницы, которые появляются после отправки формы. Существует ли готовый код, позволяющий это сделать?

Да. Вот простой пример, использующий urllib.request:

```python
#!/usr/local/bin/python

import urllib.request

### сформировать строку запроса
qs = "First=Josephine&MI=Q&Last=Public"

### подключиться и отправить серверу путь
req = urllib.request.urlopen('http://www.some-server.out-there'
                             '/cgi-bin/some-cgi-script', data=qs)
msg, hdrs = req.read(), req.info()
```

Обратите внимание, что в общем случае для POST-операций с процентным кодированием строки запроса должны быть закодированы с помощью [`urllib.parse.urlencode()`](https://python-all.ru/3.2/library/urllib.parse.html#urllib.parse.urlencode). Например, чтобы отправить `name=Guy Steele, Jr.`:

```python
>>> import urllib.parse
>>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'})
'name=Guy+Steele%2C+Jr.'
```

> **См. также**
>
> [*Руководство по получению интернет-ресурсов с помощью пакета urllib*](https://python-all.ru/3.2/howto/urllib2.html#urllib-howto) с многочисленными примерами.

### [Какой модуль использовать для генерации HTML?](https://python-all.ru/3.2/faq/library.html#id29)

Вы можете найти подборку полезных ссылок на [вики-странице Web Programming](https://python-all.ru/3.2/faq/library.html).

### [Как отправить письмо из скрипта Python?](https://python-all.ru/3.2/faq/library.html#id30)

Используйте модуль стандартной библиотеки [`smtplib`](https://python-all.ru/3.2/library/smtplib.html#module-smtplib).

Вот очень простой интерактивный отправитель почты, использующий этот модуль. Этот метод будет\\nработать на любом хосте, поддерживающем SMTP-слушатель.

```python
import sys, smtplib

fromaddr = input("From: ")
toaddrs  = input("To: ").split(',')
print("Enter message, end with ^D:")
msg = ''
while True:
    line = sys.stdin.readline()
    if not line:
        break
    msg += line

# Непосредственная отправка письма
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
```

Альтернатива только для Unix использует sendmail. Расположение программы sendmail различается в разных системах; иногда это `/usr/lib/sendmail`, иногда `/usr/sbin/sendmail`. Страница руководства sendmail поможет разобраться. Вот пример кода:

```python
SENDMAIL = "/usr/sbin/sendmail"  # Расположение sendmail
import os
p = os.popen("%s -t -i" % SENDMAIL, "w")
p.write("To: receiver@example.com\n")
p.write("Subject: test\n")
p.write("\n")  # Пустая строка, отделяющая заголовки от тела
p.write("Some text\n")
p.write("some more text\n")
sts = p.close()
if sts != 0:
    print("Sendmail exit status", sts)
```

### [Как избежать блокировки в методе connect() сокета?](https://python-all.ru/3.2/faq/library.html#id31)

Модуль [`select`](https://python-all.ru/3.2/library/select.html#module-select) обычно применяется для поддержки асинхронного ввода-вывода на сокетах.

Чтобы предотвратить блокировку при TCP-подключении, можно перевести сокет в неблокирующий режим. Затем при вызове `connect()` соединение либо установится сразу (маловероятно), либо будет получено исключение, содержащее номер ошибки в виде `.errno`. `⟦`errno.EINPROGRESS указывает, что соединение устанавливается, но ещё не завершено. Разные ОС возвращают разные значения, поэтому необходимо проверить, что возвращается в вашей системе.

Можно использовать метод `connect_ex()`, чтобы избежать создания исключения. Он просто вернёт значение errno. Для опроса можно позже снова вызвать `connect_ex()` – `0` или `errno.EISCONN` указывают, что соединение установлено – или можно передать этот сокет в select, чтобы проверить, доступен ли он для записи.

> **Примечание**
>
> Модуль [`asyncore`](https://python-all.ru/3.2/library/asyncore.html#module-asyncore) предлагает подход, напоминающий фреймворк, к проблеме написания неблокирующего сетевого кода. Сторонняя библиотека [Twisted](https://python-all.ru/3.2/faq/library.html) является популярной и многофункциональной альтернативой.

## [Базы данных](https://python-all.ru/3.2/faq/library.html#id32)

### [Существуют ли интерфейсы к пакетам баз данных в Python?](https://python-all.ru/3.2/faq/library.html#id33)

Да.

Интерфейсы к дисковым хеш-таблицам, таким как [`DBM`](https://python-all.ru/3.2/library/dbm.html#module-dbm.ndbm) и [`GDBM`](https://python-all.ru/3.2/library/dbm.html#module-dbm.gnu), также включены в стандартную библиотеку Python. Также есть модуль [`sqlite3`](https://python-all.ru/3.2/library/sqlite3.html#module-sqlite3), который предоставляет лёгкую дисковую реляционную базу данных.

Доступна поддержка большинства реляционных баз данных. Подробнее см. на [вики-странице DatabaseProgramming](https://python-all.ru/3.2/faq/library.html).

### [Как реализовать постоянные объекты в Python?](https://python-all.ru/3.2/faq/library.html#id34)

Модуль библиотеки [`pickle`](https://python-all.ru/3.2/library/pickle.html#module-pickle) решает эту проблему очень общим способом (хотя по-прежнему нельзя хранить такие вещи, как открытые файлы, сокеты или окна), а модуль библиотеки [`shelve`](https://python-all.ru/3.2/library/shelve.html#module-shelve) использует pickle и (g)dbm для создания постоянных отображений, содержащих произвольные объекты Python.

## [Математика и численные методы](https://python-all.ru/3.2/faq/library.html#id35)

### [Как генерировать случайные числа в Python?](https://python-all.ru/3.2/faq/library.html#id36)

Стандартный модуль [`random`](https://python-all.ru/3.2/library/random.html#module-random) реализует генератор случайных чисел. Использование простое:

```python
import random
random.random()
```

Возвращает случайное число с плавающей запятой в диапазоне \[0, 1).

В этом модуле также есть много других специализированных генераторов, например:

- `randrange(a, b)` выбирает целое число в диапазоне \[a, b).
- `uniform(a, b)` выбирает число с плавающей точкой в диапазоне \[a, b).
- `normalvariate(mean, sdev)` возвращает случайное число из нормального (гауссова) распределения.

Некоторые функции более высокого уровня работают непосредственно с последовательностями, например:

- `choice(S)` выбирает случайный элемент из заданной последовательности
- `shuffle(L)` перемешивает список на месте, т.е. переставляет его элементы случайным образом

Также существует класс `Random`, который можно инстанцировать для создания нескольких независимых генераторов случайных чисел.
