programming.md
1> **Источник:** https://python-all.ru/3.16/faq/programming.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [ЧЗВ по программированию](https://python-all.ru/3.16/faq/programming.html#id2)89Содержание [Вопросы по программированию](https://python-all.ru/3.16/faq/programming.html#programming-faq) [Общие вопросы](https://python-all.ru/3.16/faq/programming.html#general-questions) [Существует ли отладчик на уровне исходного кода с точками остановки и пошаговым выполнением?](https://python-all.ru/3.16/faq/programming.html#is-there-a-source-code-level-debugger-with-breakpoints-and-single-stepping) [Есть ли инструменты для поиска ошибок или статического анализа?](https://python-all.ru/3.16/faq/programming.html#are-there-tools-to-help-find-bugs-or-perform-static-analysis) [Как создать автономный исполняемый файл из скрипта Python?](https://python-all.ru/3.16/faq/programming.html#how-can-i-create-a-stand-alone-binary-from-a-python-script) [Существуют ли стандарты кодирования или руководство по стилю для программ на Python?](https://python-all.ru/3.16/faq/programming.html#are-there-coding-standards-or-a-style-guide-for-python-programs) [Ядро языка](https://python-all.ru/3.16/faq/programming.html#core-language) [Почему возникает UnboundLocalError, если переменная имеет значение?](https://python-all.ru/3.16/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value) [Каковы правила для локальных и глобальных переменных в Python?](https://python-all.ru/3.16/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python) [Почему лямбда-функции, определённые в цикле с разными значениями, возвращают один и тот же результат?](https://python-all.ru/3.16/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different-values-all-return-the-same-result) [Как разделять глобальные переменные между модулями?](https://python-all.ru/3.16/faq/programming.html#how-do-i-share-global-variables-across-modules) [Каковы «лучшие практики» использования import в модуле?](https://python-all.ru/3.16/faq/programming.html#what-are-the-best-practices-for-using-import-in-a-module) [Почему значения по умолчанию разделяются между объектами?](https://python-all.ru/3.16/faq/programming.html#why-are-default-values-shared-between-objects) [Как передать необязательные или именованные параметры из одной функции в другую?](https://python-all.ru/3.16/faq/programming.html#how-can-i-pass-optional-or-keyword-parameters-from-one-function-to-another) [В чём разница между аргументами и параметрами?](https://python-all.ru/3.16/faq/programming.html#what-is-the-difference-between-arguments-and-parameters) [Почему изменение списка 'y' также изменило список 'x'?](https://python-all.ru/3.16/faq/programming.html#why-did-changing-list-y-also-change-list-x) [Как написать функцию с выходными параметрами (передача по ссылке)?](https://python-all.ru/3.16/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference) [Как создать функцию высшего порядка в Python?](https://python-all.ru/3.16/faq/programming.html#how-do-you-make-a-higher-order-function-in-python) [Как скопировать объект в Python?](https://python-all.ru/3.16/faq/programming.html#how-do-i-copy-an-object-in-python) [Как найти методы или атрибуты объекта?](https://python-all.ru/3.16/faq/programming.html#how-can-i-find-the-methods-or-attributes-of-an-object) [Как моему коду узнать имя объекта?](https://python-all.ru/3.16/faq/programming.html#how-can-my-code-discover-the-name-of-an-object) [Что не так с приоритетом оператора запятой?](https://python-all.ru/3.16/faq/programming.html#what-s-up-with-the-comma-operator-s-precedence) [Существует ли эквивалент тернарного оператора «?:» из C?](https://python-all.ru/3.16/faq/programming.html#is-there-an-equivalent-of-c-s-ternary-operator) [Можно ли писать запутанные однострочники на Python?](https://python-all.ru/3.16/faq/programming.html#is-it-possible-to-write-obfuscated-one-liners-in-python) [Что означает косая черта (/) в списке параметров функции?](https://python-all.ru/3.16/faq/programming.html#what-does-the-slash-in-the-parameter-list-of-a-function-mean) [Числа и строки](https://python-all.ru/3.16/faq/programming.html#numbers-and-strings) [Как указать шестнадцатеричные и восьмеричные целые числа?](https://python-all.ru/3.16/faq/programming.html#how-do-i-specify-hexadecimal-and-octal-integers) [Почему -22 // 10 возвращает -3?](https://python-all.ru/3.16/faq/programming.html#why-does-22-10-return-3) [Как получить атрибут int literal вместо SyntaxError?](https://python-all.ru/3.16/faq/programming.html#how-do-i-get-int-literal-attribute-instead-of-syntaxerror) [Как преобразовать строку в число?](https://python-all.ru/3.16/faq/programming.html#how-do-i-convert-a-string-to-a-number) [Как преобразовать число в строку?](https://python-all.ru/3.16/faq/programming.html#how-do-i-convert-a-number-to-a-string) [Как изменить строку на месте?](https://python-all.ru/3.16/faq/programming.html#how-do-i-modify-a-string-in-place) [Как с помощью строк вызывать функции и методы?](https://python-all.ru/3.16/faq/programming.html#how-do-i-use-strings-to-call-functions-methods) [Есть ли аналог `chomp()` из Perl для удаления завершающих переводов строк?](https://python-all.ru/3.16/faq/programming.html#is-there-an-equivalent-to-perl-s-chomp-for-removing-trailing-newlines-from-strings) [Существует ли аналог `scanf()` или `sscanf()`?](https://python-all.ru/3.16/faq/programming.html#is-there-a-scanf-or-sscanf-equivalent) [Что означает ошибка `UnicodeDecodeError` или `UnicodeEncodeError`?](https://python-all.ru/3.16/faq/programming.html#what-does-unicodedecodeerror-or-unicodeencodeerror-error-mean) [Можно ли завершать сырую строку нечётным количеством обратных слешей?](https://python-all.ru/3.16/faq/programming.html#can-i-end-a-raw-string-with-an-odd-number-of-backslashes) [Производительность](https://python-all.ru/3.16/faq/programming.html#performance) [Моя программа слишком медленная. Как её ускорить?](https://python-all.ru/3.16/faq/programming.html#my-program-is-too-slow-how-do-i-speed-it-up) [Какой способ конкатенации множества строк самый эффективный?](https://python-all.ru/3.16/faq/programming.html#what-is-the-most-efficient-way-to-concatenate-many-strings-together) [Последовательности (кортежи/списки)](https://python-all.ru/3.16/faq/programming.html#sequences-tuples-lists) [Как преобразовывать кортежи в списки и обратно?](https://python-all.ru/3.16/faq/programming.html#how-do-i-convert-between-tuples-and-lists) [Что такое отрицательный индекс?](https://python-all.ru/3.16/faq/programming.html#what-s-a-negative-index) [Как перебрать последовательность в обратном порядке?](https://python-all.ru/3.16/faq/programming.html#how-do-i-iterate-over-a-sequence-in-reverse-order) [Как удалить дубликаты из списка?](https://python-all.ru/3.16/faq/programming.html#how-do-you-remove-duplicates-from-a-list) [Как удалить несколько элементов из списка?](https://python-all.ru/3.16/faq/programming.html#how-do-you-remove-multiple-items-from-a-list) [Как создать массив в Python?](https://python-all.ru/3.16/faq/programming.html#how-do-you-make-an-array-in-python) [Как создать многомерный список?](https://python-all.ru/3.16/faq/programming.html#how-do-i-create-a-multidimensional-list) [Как применить метод или функцию к последовательности объектов?](https://python-all.ru/3.16/faq/programming.html#how-do-i-apply-a-method-or-function-to-a-sequence-of-objects) [Почему a\_tuple\[i\] += \[‘item’\] вызывает исключение, хотя само сложение работает?](https://python-all.ru/3.16/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works) [Я хочу выполнить сложную сортировку: можно ли в Python реализовать преобразование Шварца?](https://python-all.ru/3.16/faq/programming.html#i-want-to-do-a-complicated-sort-can-you-do-a-schwartzian-transform-in-python) [Как отсортировать один список по значениям из другого списка?](https://python-all.ru/3.16/faq/programming.html#how-can-i-sort-one-list-by-values-from-another-list) [Объекты](https://python-all.ru/3.16/faq/programming.html#objects) [Что такое класс?](https://python-all.ru/3.16/faq/programming.html#what-is-a-class) [Что такое метод?](https://python-all.ru/3.16/faq/programming.html#what-is-a-method) [Что такое self?](https://python-all.ru/3.16/faq/programming.html#what-is-self) [Как проверить, является ли объект экземпляром данного класса или его подкласса?](https://python-all.ru/3.16/faq/programming.html#how-do-i-check-if-an-object-is-an-instance-of-a-given-class-or-of-a-subclass-of-it) [Что такое делегирование?](https://python-all.ru/3.16/faq/programming.html#what-is-delegation) [Как из производного класса вызвать метод базового класса, который он расширяет?](https://python-all.ru/3.16/faq/programming.html#how-do-i-call-a-method-defined-in-a-base-class-from-a-derived-class-that-extends-it) [Как организовать код, чтобы было проще изменить базовый класс?](https://python-all.ru/3.16/faq/programming.html#how-can-i-organize-my-code-to-make-it-easier-to-change-the-base-class) [Как создать статические данные класса и статические методы класса?](https://python-all.ru/3.16/faq/programming.html#how-do-i-create-static-class-data-and-static-class-methods) [Как перегрузить конструкторы (или методы) в Python?](https://python-all.ru/3.16/faq/programming.html#how-can-i-overload-constructors-or-methods-in-python) [Я пытаюсь использовать \_\_spam и получаю ошибку о \_SomeClassName\_\_spam.](https://python-all.ru/3.16/faq/programming.html#i-try-to-use-spam-and-i-get-an-error-about-someclassname-spam) [Мой класс определяет \_\_del\_\_, но он не вызывается при удалении объекта.](https://python-all.ru/3.16/faq/programming.html#my-class-defines-del-but-it-is-not-called-when-i-delete-the-object) [Как получить список всех экземпляров данного класса?](https://python-all.ru/3.16/faq/programming.html#how-do-i-get-a-list-of-all-instances-of-a-given-class) [Почему результат `id()` не является уникальным?](https://python-all.ru/3.16/faq/programming.html#why-does-the-result-of-id-appear-to-be-not-unique) [Когда можно полагаться на проверку идентичности оператором *is*?](https://python-all.ru/3.16/faq/programming.html#when-can-i-rely-on-identity-tests-with-the-is-operator) [Как подкласс может контролировать, какие данные сохраняются в неизменяемом экземпляре?](https://python-all.ru/3.16/faq/programming.html#how-can-a-subclass-control-what-data-is-stored-in-an-immutable-instance) [Как кешировать вызовы методов?](https://python-all.ru/3.16/faq/programming.html#how-do-i-cache-method-calls) [Модули](https://python-all.ru/3.16/faq/programming.html#modules) [Как создать .pyc-файл?](https://python-all.ru/3.16/faq/programming.html#how-do-i-create-a-pyc-file) [Как узнать имя текущего модуля?](https://python-all.ru/3.16/faq/programming.html#how-do-i-find-the-current-module-name) [Как сделать так, чтобы модули импортировали друг друга?](https://python-all.ru/3.16/faq/programming.html#how-can-i-have-modules-that-mutually-import-each-other) [\_\_import\_\_(‘x.y.z’) возвращает \<module ‘x’\>; как получить z?](https://python-all.ru/3.16/faq/programming.html#import-x-y-z-returns-module-x-how-do-i-get-z) [При редактировании импортированного модуля и его повторном импорте изменения не отображаются. Почему это происходит?](https://python-all.ru/3.16/faq/programming.html#when-i-edit-an-imported-module-and-reimport-it-the-changes-don-t-show-up-why-does-this-happen)1011## [Общие вопросы](https://python-all.ru/3.16/faq/programming.html#id3)1213### [Существует ли отладчик на уровне исходного кода с точками останова и пошаговым выполнением?](https://python-all.ru/3.16/faq/programming.html#id4)1415Да.1617Ниже описано несколько отладчиков для Python, а встроенная функция [`breakpoint()`](https://python-all.ru/3.16/library/functions.html#breakpoint) позволяет войти в любой из них.1819Модуль pdb – это простой, но достаточный консольный отладчик для Python. Он является частью стандартной библиотеки Python и [`documented in the Library Reference Manual`](https://python-all.ru/3.16/library/pdb.html#module-pdb). Вы также можете написать собственный отладчик, используя код pdb в качестве примера.2021Интерактивная среда разработки IDLE, входящая в стандартную поставку Python (обычно доступна как [`idlelib`](https://python-all.ru/3.16/library/idle.html#module-idlelib)), включает графический отладчик.2223PythonWin – это IDE для Python, включающая графический отладчик на основе pdb. Отладчик PythonWin подсвечивает точки останова и обладает множеством полезных функций, например, отладкой программ, не относящихся к PythonWin. PythonWin доступен в составе проекта [pywin32](https://python-all.ru/3.16/faq/programming.html) и в дистрибутиве [ActivePython](https://python-all.ru/3.16/faq/programming.html).2425[Eric](https://python-all.ru/3.16/faq/programming.html) – это IDE, построенная на PyQt и компоненте редактирования Scintilla.2627[trepan3k](https://python-all.ru/3.16/faq/programming.html) – это отладчик, подобный gdb.2829[Visual Studio Code](https://python-all.ru/3.16/faq/programming.html) – это IDE со средствами отладки, интегрирующаяся с системами управления версиями.3031Существует ряд коммерческих IDE для Python, включающих графические отладчики. Среди них:3233- [Wing IDE](https://python-all.ru/3.16/faq/programming.html)34- [PyCharm](https://python-all.ru/3.16/faq/programming.html)3536### [Существуют ли инструменты для поиска ошибок или статического анализа?](https://python-all.ru/3.16/faq/programming.html#id5)3738Да.3940[Ruff](https://python-all.ru/3.16/faq/programming.html), [Pylint](https://python-all.ru/3.16/faq/programming.html) и [Pyflakes](https://python-all.ru/3.16/faq/programming.html) выполняют базовую проверку, которая поможет быстрее выявить ошибки.4142Статические анализаторы типов, такие как [mypy](https://python-all.ru/3.16/faq/programming.html), [ty](https://python-all.ru/3.16/faq/programming.html), [Pyrefly](https://python-all.ru/3.16/faq/programming.html) и [pytype](https://python-all.ru/3.16/faq/programming.html), могут проверять аннотации типов в исходном коде Python.4344### [Как создать автономный исполняемый файл из скрипта Python?](https://python-all.ru/3.16/faq/programming.html#id6)4546Вам не нужно уметь компилировать Python в C, если ваша цель – создать автономную программу, которую пользователи могут скачать и запустить без предварительной установки дистрибутива Python. Существует ряд инструментов, которые определяют набор модулей, необходимых программе, и связывают эти модули вместе с бинарным файлом Python, создавая единый исполняемый файл.4748Один из них – использовать инструмент freeze, который находится в дереве исходного кода Python как [Tools/freeze](https://python-all.ru/3.16/faq/programming.html). Он преобразует байт-код Python в массивы C; имея компилятор C, вы можете встроить все свои модули в новую программу, которая затем компонуется со стандартными модулями Python.4950Он работает, рекурсивно сканируя ваш исходный код на наличие операторов import (в обеих формах) и ищет модули в стандартном пути Python, а также в каталоге исходного кода (для встроенных модулей). Затем он превращает байт-код модулей, написанных на Python, в код C (инициализаторы массивов, которые можно превратить в объекты кода с помощью модуля marshal) и создает специальный конфигурационный файл, содержащий только те встроенные модули, которые действительно используются в программе. После этого он компилирует сгенерированный код C и компонует его с остальной частью интерпретатора Python, формируя самодостаточный бинарный файл, который ведет себя точно так же, как ваш скрипт.5152Следующие пакеты могут помочь в создании консольных и GUI-исполняемых файлов:5354- [Nuitka](https://python-all.ru/3.16/faq/programming.html) (кроссплатформенный)55- [PyInstaller](https://python-all.ru/3.16/faq/programming.html) (кроссплатформенный)56- [PyOxidizer](https://python-all.ru/3.16/faq/programming.html) (кроссплатформенный)57- [cx\_Freeze](https://python-all.ru/3.16/faq/programming.html) (Кроссплатформенный)58- [py2app](https://python-all.ru/3.16/faq/programming.html) (только macOS)59- [py2exe](https://python-all.ru/3.16/faq/programming.html) (только Windows)6061### [Существуют ли стандарты кодирования или руководство по стилю для программ на Python?](https://python-all.ru/3.16/faq/programming.html#id7)6263Да. Требуемый стиль оформления кода для модулей стандартной библиотеки описан в документе [**PEP 8**](https://python-all.ru/3.16/faq/programming.html).6465## [Основной язык](https://python-all.ru/3.16/faq/programming.html#id8)6667### [Почему возникает UnboundLocalError, если переменная содержит значение?](https://python-all.ru/3.16/faq/programming.html#id9)6869Появление [`UnboundLocalError`](https://python-all.ru/3.16/library/exceptions.html#UnboundLocalError) в ранее работавшем коде может оказаться неожиданным, если код был изменён добавлением оператора присваивания в теле функции.7071Этот код:7273```python74>>> x = 1075>>> def bar():76... print(x)77...78>>> bar()791080```8182работает, но этот код:8384```python85>>> x = 1086>>> def foo():87... print(x)88... x += 189```9091приводит к `UnboundLocalError`:9293```python94>>> foo()95Traceback (most recent call last):96 ...97UnboundLocalError: cannot access local variable 'x' where it is not associated with a value98```99100Это происходит потому, что при присваивании значения переменной в некоторой области видимости эта переменная становится локальной для данной области и затеняет любую одноимённую переменную из внешней области. Поскольку последний оператор в foo присваивает новое значение `x`, компилятор считает её локальной переменной. Следовательно, когда предыдущий `print(x)` пытается вывести на печать неинициализированную локальную переменную, возникает ошибка.101102В приведённом выше примере можно получить доступ к переменной внешней области, объявив её глобальной:103104```python105>>> x = 10106>>> def foobar():107... global x108... print(x)109... x += 1110...111>>> foobar()11210113```114115Такое явное объявление необходимо, чтобы напомнить: в отличие от внешне похожей ситуации с переменными класса и экземпляра, здесь фактически изменяется значение переменной во внешней области видимости:116117```python118>>> print(x)11911120```121122Аналогичное действие можно выполнить во вложенной области видимости с помощью ключевого слова [`nonlocal`](https://python-all.ru/3.16/reference/simple_stmts.html#nonlocal):123124```python125>>> def foo():126... x = 10127... def bar():128... nonlocal x129... print(x)130... x += 1131... bar()132... print(x)133...134>>> foo()1351013611137```138139### [Каковы правила использования локальных и глобальных переменных в Python?](https://python-all.ru/3.16/faq/programming.html#id10)140141В Python переменные, на которые только ссылаются внутри функции, неявно считаются глобальными. Если переменной присваивается значение где-либо в теле функции, она считается локальной, если явно не объявлена как global.142143Хотя поначалу это может показаться удивительным, небольшое размышление объясняет такое поведение. С одной стороны, требование [`global`](https://python-all.ru/3.16/reference/simple_stmts.html#global) для присваиваемых переменных служит барьером против непреднамеренных побочных эффектов. С другой стороны, если бы `global` требовалось для всех глобальных ссылок, пришлось бы постоянно использовать `global`. Пришлось бы объявлять как global каждую ссылку на встроенную функцию или компонент импортированного модуля. Такая избыточность свела бы на нет пользу объявления `global` для выявления побочных эффектов.144145### [Почему лямбды, определённые в цикле с разными значениями, все возвращают один и тот же результат?](https://python-all.ru/3.16/faq/programming.html#id11)146147Допустим, с помощью цикла for определяется несколько разных лямбд (или даже обычных функций), например:148149```python150>>> squares = []151>>> for x in range(5):152... squares.append(lambda: x**2)153```154155Это даёт список, содержащий 5 лямбд, вычисляющих `x**2`. Можно ожидать, что при вызове они вернут соответственно `0`, `1`, `4`, `9` и `16`. Однако при попытке вызова обнаружится, что все они возвращают `16`:156157```python158>>> squares[2]()15916160>>> squares[4]()16116162```163164Это происходит потому, что `x` не является локальной для лямбд, а определена во внешней области видимости, и доступ к ней происходит при вызове лямбды, а не при её определении. В конце цикла значение `x` равно `4`, поэтому все функции теперь возвращают `4**2`, то есть `16`. Это также можно проверить, изменив значение `x` и наблюдая, как изменяются результаты лямбд:165166```python167>>> x = 8168>>> squares[2]()16964170```171172Чтобы избежать этого, необходимо сохранить значения в переменных, локальных для лямбд, чтобы они не зависели от значения глобальной `x`:173174```python175>>> squares = []176>>> for x in range(5):177... squares.append(lambda n=x: n**2)178```179180Здесь `n=x` создаёт новую переменную `n`, локальную для лямбды и вычисляемую при её определении, так что она имеет то же значение, которое `x` имела в этот момент в цикле. Это означает, что значение `n` будет равно `0` в первой лямбде, `1` – во второй, `2` – в третьей и так далее. Следовательно, теперь каждая лямбда будет возвращать правильный результат:181182```python183>>> squares[2]()1844185>>> squares[4]()18616187```188189Обратите внимание: такое поведение присуще не только лямбдам, но и обычным функциям.190191### [Как разделять глобальные переменные между модулями?](https://python-all.ru/3.16/faq/programming.html#id12)192193Общепринятый способ обмена информацией между модулями в рамках одной программы – создать специальный модуль (часто называемый config или cfg). Достаточно импортировать модуль config во все модули приложения, и он станет доступен как глобальное имя. Поскольку у каждого модуля существует только один экземпляр, любые изменения объекта модуля отражаются везде. Например:194195config.py:196197```python198x = 0 # Значение по умолчанию для параметра конфигурации 'x'199```200201mod.py:202203```python204import config205config.x = 1206```207208main.py:209210```python211import config212import mod213print(config.x)214```215216Обратите внимание, что использование модуля также является основой для реализации паттерна проектирования «одиночка» (singleton) по той же причине.217218### [Каковы «лучшие практики» использования import в модуле?](https://python-all.ru/3.16/faq/programming.html#id13)219220В целом не стоит использовать `from modulename import *`. Это захламляет пространство имён импортёра и сильно усложняет линтерам обнаружение неопределённых имён.221222Импортируйте модули в начале файла. Так сразу становится ясно, какие ещё модули требуются вашему коду, и не возникает вопросов, находится ли имя модуля в области видимости. Использование одного импорта на строку упрощает добавление и удаление импортов, а использование нескольких импортов в одной строке экономит место на экране.223224Рекомендуется импортировать модули в следующем порядке:2252261. модули стандартной библиотеки – например, [`sys`](https://python-all.ru/3.16/library/sys.html#module-sys), [`os`](https://python-all.ru/3.16/library/os.html#module-os), [`argparse`](https://python-all.ru/3.16/library/argparse.html#module-argparse), [`re`](https://python-all.ru/3.16/library/re.html#module-re)2272. модули сторонних библиотек (всё, что установлено в каталоге site-packages Python) – например, [dateutil](https://python-all.ru/3.16/faq/programming.html), [requests](https://python-all.ru/3.16/faq/programming.html), [tzdata](https://python-all.ru/3.16/faq/programming.html)2283. локально разработанные модули229230Иногда импорты приходится переносить внутрь функции или класса, чтобы избежать проблем с циклическими импортами. Gordon McMillan говорит:231232> Циклические импорты нормально работают, когда оба модуля используют форму импорта “import \<module\>”. Они перестают работать, когда второй модуль пытается получить имя из первого (“from module import name”), и импорт находится на верхнем уровне. Это происходит потому, что имена в первом модуле ещё недоступны, так как первый модуль занят импортом второго.233234В этом случае, если второй модуль используется только в одной функции, импорт можно легко перенести в эту функцию. К моменту вызова импорта первый модуль уже завершит инициализацию, и второй модуль сможет выполнить свой импорт.235236Также может потребоваться перенести импорты из верхнего уровня кода, если некоторые модули являются платформозависимыми. В таком случае может быть невозможно импортировать все модули в начале файла. Тогда хорошим решением будет импортировать нужные модули в соответствующем платформозависимом коде.237238Переносите импорты в локальную область видимости, например в определение функции, только если это необходимо для решения проблемы – избежания циклического импорта или сокращения времени инициализации модуля. Этот приём особенно полезен, когда многие импорты не нужны в зависимости от того, как выполняется программа. Также можно перенести импорты в функцию, если модули используются только в ней. Обратите внимание: первая загрузка модуля может быть дорогой из-за однократной инициализации, но повторные загрузки практически бесплатны и требуют лишь пары словарных поисков. Даже если имя модуля вышло из области видимости, сам модуль, скорее всего, доступен в [`sys.modules`](https://python-all.ru/3.16/library/sys.html#sys.modules).239240### [Почему значения по умолчанию являются общими для объектов?](https://python-all.ru/3.16/faq/programming.html#id14)241242Подобная ошибка часто подстерегает начинающих программистов. Рассмотрим следующую функцию:243244```python245def foo(mydict={}): # Опасность: общая ссылка на один словарь для всех вызовов246 ... compute something ...247 mydict[key] = value248 return mydict249```250251При первом вызове этой функции `mydict` содержит один элемент. При втором вызове `mydict` содержит уже два элемента, потому что когда `foo()` начинает выполняться, `mydict` уже содержит один элемент.252253Часто ожидается, что при вызове функции для значений по умолчанию создаются новые объекты. Но это не так. Значения по умолчанию создаются ровно один раз, при определении функции. Если этот объект изменяется (как словарь в данном примере), то последующие вызовы функции будут обращаться к этому изменённому объекту.254255По определению, неизменяемые объекты – числа, строки, кортежи и `None` – защищены от изменений. Изменения изменяемых объектов, таких как словари, списки и экземпляры классов, могут приводить к путанице.256257Из-за этой особенности рекомендуется не использовать изменяемые объекты в качестве значений по умолчанию. Вместо этого используйте `None` в качестве значения по умолчанию, а внутри функции проверяйте, равен ли параметр `None`, и при необходимости создавайте новый список, словарь и т.д. Например, не пишите:258259```python260def foo(mydict={}):261 ...262```263264а:265266```python267def foo(mydict=None):268 if mydict is None:269 mydict = {} # создать новый словарь для локального пространства имён270```271272Эта возможность может быть полезной. Если есть функция, вычисление которой требует много времени, распространённый приём – кэшировать параметры и результат каждого вызова функции, а при повторном запросе тех же значений возвращать сохранённый результат. Это называется «мемоизация» и может быть реализовано так:273274```python275# Вызывающие могут передавать только два параметра и опционально _cache по ключевому слову276def expensive(arg1, arg2, *, _cache={}):277 if (arg1, arg2) in _cache:278 return _cache[(arg1, arg2)]279280 # Вычислить значение281 result = ... expensive computation ...282 _cache[(arg1, arg2)] = result # Сохранить результат в кеше283 return result284```285286Вместо значения по умолчанию можно использовать глобальную переменную со словарём; это дело вкуса.287288### [Как передать необязательные или именованные параметры из одной функции в другую?](https://python-all.ru/3.16/faq/programming.html#id15)289290Соберите аргументы с помощью спецификаторов `*` и `**` в списке параметров функции; это даст позиционные аргументы в виде кортежа, а именованные – в виде словаря. Затем вы можете передать эти аргументы при вызове другой функции, используя `*` и `**`:291292```python293def f(x, *args, **kwargs):294 ...295 kwargs['width'] = '14.3c'296 ...297 g(x, *args, **kwargs)298```299300### [В чём разница между аргументами и параметрами?](https://python-all.ru/3.16/faq/programming.html#id16)301302[Параметры](https://python-all.ru/3.16/glossary.html#term-parameter) определяются именами, указанными в определении функции, тогда как [аргументы](https://python-all.ru/3.16/glossary.html#term-argument) – это значения, фактически передаваемые функции при её вызове. Параметры определяют, какого рода аргументы может принимать функция. Например, для определения функции:303304```python305def func(foo, bar=None, **kwargs):306 pass307```308309*foo*, *bar* и *kwargs* являются параметрами функции `func`. Однако при вызове `func`, например:310311```python312func(42, bar=314, extra=somevar)313```314315значения `42`, `314` и `somevar` являются аргументами.316317### [Почему изменение списка ‘y’ также изменило список ‘x’?](https://python-all.ru/3.16/faq/programming.html#id17)318319Если вы написали такой код:320321```python322>>> x = []323>>> y = x324>>> y.append(10)325>>> y326[10]327>>> x328[10]329```330331вас может интересовать, почему добавление элемента к `y` изменило и `x`.332333К этому результату приводят два фактора:3343351. Переменные – это просто имена, ссылающиеся на объекты. Операция `y = x` не создаёт копию списка – она создаёт новую переменную `y`, которая ссылается на тот же объект, что и `x`. Это означает, что существует только один объект (список), и обе переменные `x` и `y` ссылаются на него.3362. Списки являются [изменяемыми](https://python-all.ru/3.16/glossary.html#term-mutable), то есть их содержимое можно изменять.337338После вызова [`append()`](https://python-all.ru/3.16/library/stdtypes.html#sequence.append) содержимое изменяемого объекта\\nизменилось с `[]` на `[10]`. Поскольку обе переменные ссылаются на один и тот же объект, использование любого имени даёт доступ к изменённому значению `[10]`.339340Если же присвоить неизменяемый объект `x`:341342```python343>>> x = 5 # int – неизменяемый тип344>>> y = x345>>> x = x + 1 # 5 нельзя изменить, здесь создаётся новый объект346>>> x3476348>>> y3495350```351352в этом случае `x` и `y` уже не равны. Это\\nпотому, что целые числа [неизменяемы](https://python-all.ru/3.16/glossary.html#term-immutable), и когда мы делаем `x = x + 1`, мы не\\nизменяем int `5`, увеличивая его значение; вместо этого мы создаём\\nновый объект (int `6`) и присваиваем его `x` (то есть изменяем, на какой объект ссылается `x`). После этого присваивания у нас есть два объекта (int `6` и `5`) и две переменные, ссылающиеся на них (`x` теперь ссылается на `6`, а `y` всё ещё ссылается на `5`).353354Некоторые операции (например `y.append(10)` и `y.sort()`) изменяют\\nобъект, тогда как внешне похожие операции (например `y = y + [10]`\\nи [`sorted(y)`](https://python-all.ru/3.16/library/functions.html#sorted)) создают новый объект. В общем случае в Python (и во всех случаях\\nв стандартной библиотеке) метод, изменяющий объект, возвращает `None`,\\nчтобы избежать путаницы между двумя типами операций. Так что если вы\\nошибочно напишете `y.sort()`, думая, что получите отсортированную копию `y`,\\nто вместо этого получите `None`, что, скорее всего, приведёт к легко диагностируемой ошибке в вашей программе.355356Однако есть один класс операций, где одна и та же операция иногда\\nведёт себя по-разному с разными типами: составные операторы присваивания.\\nНапример, `+=` изменяет списки, но не кортежи или целые числа (`a_list += [1, 2, 3]` эквивалентно `a_list.extend([1, 2, 3])` и изменяет\\n`a_list`, тогда как `some_tuple += (1, 2, 3)` и `some_int += 1` создают\\nновые объекты).357358Иными словами:359360- Если у нас есть изменяемый объект (например [`list`](https://python-all.ru/3.16/library/stdtypes.html#list), [`dict`](https://python-all.ru/3.16/library/stdtypes.html#dict), [`set`](https://python-all.ru/3.16/library/stdtypes.html#set)),\\nмы можем использовать определённые операции для его изменения, и все переменные,\\nкоторые на него ссылаются, увидят это изменение.361- Если у нас есть неизменяемый объект (например [`str`](https://python-all.ru/3.16/library/stdtypes.html#str), [`int`](https://python-all.ru/3.16/library/functions.html#int), [`tuple`](https://python-all.ru/3.16/library/stdtypes.html#tuple)),\\nвсе переменные, ссылающиеся на него, всегда будут видеть одно и то же значение,\\nно операции, преобразующие это значение в новое, всегда возвращают новый\\nобъект.362363Чтобы узнать, ссылаются ли две переменные на один и тот же объект, можно\\nиспользовать оператор [`is`](https://python-all.ru/3.16/reference/expressions.html#is) или встроенную функцию [`id()`](https://python-all.ru/3.16/library/functions.html#id).364365### [Как написать функцию с выходными параметрами (передача по ссылке)?](https://python-all.ru/3.16/faq/programming.html#id18)366367Помните, что аргументы в Python передаются по присваиванию. Поскольку присваивание\\nвсего лишь создаёт ссылки на объекты, между именем аргумента в вызывающей и\\nвызываемой функции нет псевдонима, и следовательно, нет передачи по ссылке. Добиться\\nнужного эффекта можно несколькими способами.3683691. Возвращая кортеж результатов:370371 ```python372 >>> def func1(a, b):373 ... a = 'new-value' # a и b – локальные имена374 ... b = b + 1 # присвоены новым объектам375 ... return a, b # вернуть новые значения376 ...377 >>> x, y = 'old-value', 99378 >>> func1(x, y)379 ('new-value', 100)380 ```381382 Это почти всегда самое понятное решение.3832. С помощью глобальных переменных. Это не потокобезопасно и не рекомендуется.3843. Передавая изменяемый (изменяемый на месте) объект:385386 ```python387 >>> def func2(a):388 ... a[0] = 'new-value' # 'a' ссылается на изменяемый список389 ... a[1] = a[1] + 1 # изменяет общий объект390 ...391 >>> args = ['old-value', 99]392 >>> func2(args)393 >>> args394 ['new-value', 100]395 ```3964. Передавая словарь, который будет изменён:397398 ```python399 >>> def func3(args):400 ... args['a'] = 'new-value' # args – изменяемый словарь401 ... args['b'] = args['b'] + 1 # изменить его на месте402 ...403 >>> args = {'a': 'old-value', 'b': 99}404 >>> func3(args)405 >>> args406 {'a': 'new-value', 'b': 100}407 ```4085. Или объединив значения в экземпляре класса:409410 ```python411 >>> class Namespace:412 ... def __init__(self, /, **args):413 ... for key, value in args.items():414 ... setattr(self, key, value)415 ...416 >>> def func4(args):417 ... args.a = 'new-value' # args – изменяемый Namespace418 ... args.b = args.b + 1 # изменить объект на месте419 ...420 >>> args = Namespace(a='old-value', b=99)421 >>> func4(args)422 >>> vars(args)423 {'a': 'new-value', 'b': 100}424 ```425426 Почти никогда нет веской причины усложнять до такой степени.427428Лучший выбор – вернуть кортеж, содержащий несколько результатов.429430### [Как сделать функцию высшего порядка в Python?](https://python-all.ru/3.16/faq/programming.html#id19)431432У вас есть два варианта: использовать вложенные области видимости или вызываемые объекты.\\nНапример, предположим, вы хотите определить `linear(a,b)`, которая возвращает\\nфункцию `f(x)`, вычисляющую значение `a*x+b`. Используя вложенные области видимости:433434```python435def linear(a, b):436 def result(x):437 return a * x + b438 return result439```440441Или используя вызываемый объект:442443```python444class linear:445446 def __init__(self, a, b):447 self.a, self.b = a, b448449 def __call__(self, x):450 return self.a * x + self.b451```452453В обоих случаях454455```python456taxes = linear(0.3, 2)457```458459даёт вызываемый объект, где `taxes(10e6) == 0.3 * 10e6 + 2`.460461Подход с вызываемым объектом имеет недостаток: он немного медленнее и\\nприводит к чуть более длинному коду. Однако обратите внимание, что набор вызываемых объектов\\nможет разделять свою сигнатуру через наследование:462463```python464class exponential(linear):465 # __init__ унаследован466 def __call__(self, x):467 return self.a * (x ** self.b)468```469470Объект может инкапсулировать состояние для нескольких методов:471472```python473class counter:474475 value = 0476477 def set(self, x):478 self.value = x479480 def up(self):481 self.value = self.value + 1482483 def down(self):484 self.value = self.value - 1485486count = counter()487inc, dec, reset = count.up, count.down, count.set488```489490Здесь `inc()`, `dec()` и `reset()` ведут себя как функции, которые разделяют одну\\nи ту же переменную счётчика.491492### [Как скопировать объект в Python?](https://python-all.ru/3.16/faq/programming.html#id20)493494В общем случае для копирования попробуйте [`copy.copy()`](https://python-all.ru/3.16/library/copy.html#copy.copy) или [`copy.deepcopy()`](https://python-all.ru/3.16/library/copy.html#copy.deepcopy).\\nНе все объекты можно копировать, но большинство можно.495496Некоторые объекты можно скопировать проще. У словарей есть метод [`copy()`](https://python-all.ru/3.16/library/stdtypes.html#dict.copy):497498```python499newdict = olddict.copy()500```501502Последовательности можно скопировать срезом:503504```python505new_l = l[:]506```507508### [Как найти методы или атрибуты объекта?](https://python-all.ru/3.16/faq/programming.html#id21)509510Для экземпляра `x` пользовательского класса [`dir(x)`](https://python-all.ru/3.16/library/functions.html#dir) возвращает отсортированный по алфавиту список имён, содержащий атрибуты экземпляра, а также методы и атрибуты, определённые в его классе.511512### [Как код может узнать имя объекта?](https://python-all.ru/3.16/faq/programming.html#id22)513514Вообще говоря, никак, потому что у объектов на самом деле нет имён. По сути, присваивание всегда связывает имя со значением; то же верно для операторов `def` и `class`, но в этом случае значение является вызываемым объектом. Рассмотрим следующий код:515516```python517>>> class A:518... pass519...520>>> B = A521>>> a = B()522>>> b = a523>>> print(b)524<__main__.A object at 0x16D07CC>525>>> print(a)526<__main__.A object at 0x16D07CC>527```528529Можно утверждать, что у класса есть имя: хотя он связан с двумя именами и вызывается через имя `B`, созданный экземпляр всё равно считается экземпляром класса `A`. Однако невозможно сказать, является ли имя экземпляра `a` или `b`, поскольку оба имени связаны с одним и тем же значением.530531Вообще говоря, коду не требуется «знать имена» конкретных значений. Если вы не пишете намеренно интроспективные программы, это обычно указывает на то, что стоит изменить подход.532533В comp.lang.python Фредрик Лунд однажды привёл отличную аналогию в ответ на этот вопрос:534535> Так же, как вы узнаёте имя кота, которого нашли на крыльце: сам кот (объект) не может сказать вам своё имя, да ему всё равно – поэтому единственный способ выяснить, как его зовут, – спросить всех соседей (пространства имён), не их ли это кот (объект)…536>537> …и не удивляйтесь, если окажется, что он известен под многими именами или вообще без имени!538539### [Что не так с приоритетом оператора-запятой?](https://python-all.ru/3.16/faq/programming.html#id23)540541Запятая в Python – не оператор. Рассмотрим такой сеанс:542543```python544>>> "a" in "b", "a"545(False, 'a')546```547548Поскольку запятая – не оператор, а разделитель между выражениями, приведённый выше код выполняется так, как если бы вы ввели:549550```python551("a" in "b"), "a"552```553554а не:555556```python557"a" in ("b", "a")558```559560То же верно для различных операторов присваивания (`=`, `+=` и т.д.). На самом деле они не являются операторами, а представляют собой синтаксические разделители в инструкциях присваивания.561562### [Существует ли аналог тернарного оператора «?:» из C?](https://python-all.ru/3.16/faq/programming.html#id24)563564Да, существует. Синтаксис следующий:565566```python567[on_true] if [expression] else [on_false]568569x, y = 50, 25570small = x if x < y else y571```572573До введения этого синтаксиса в Python 2.5 распространённым приёмом было использование логических операторов:574575```python576[expression] and [on_true] or [on_false]577```578579Однако этот приём небезопасен, поскольку может давать неверные результаты, если *on\_true* имеет ложное булево значение. Поэтому всегда лучше использовать форму `... if ... else ...`.580581### [Можно ли писать запутанные однострочники на Python?](https://python-all.ru/3.16/faq/programming.html#id25)582583Да. Обычно это делается вложением [`lambda`](https://python-all.ru/3.16/reference/expressions.html#lambda) внутрь `lambda`. Вот три примера, немного адаптированных из работ Ульфа Бартельта:584585```python586from functools import reduce587588# Простые числа < 1000589print(list(filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,590map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))))591592# Первые 10 чисел Фибоначчи593print(list(map(lambda x,f=lambda x,f:(f(x-1,f)+f(x-2,f)) if x>1 else 1:594f(x,f), range(10))))595596# Множество Мандельброта597print((lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+'\n'+y,map(lambda y,598Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,599Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,600i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y601>=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr(60264+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy603))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24))604# \___ ___/ \___ ___/ | | |__ линии на экране605# V V | |______ столбцы на экране606# | | |__________ максимум "iterations"607# | |_________________ диапазон по оси Y608# |____________________________ диапазон по оси X609```610611Не пытайтесь повторить это дома, дети!612613### [Что означает косая черта (/) в списке параметров функции?](https://python-all.ru/3.16/faq/programming.html#id26)614615Косая черта в списке аргументов функции означает, что параметры, расположенные до неё, являются только позиционными. Параметры только позиционные – это параметры без внешне используемого имени. При вызове функции, принимающей только позиционные параметры, аргументы сопоставляются с параметрами исключительно по их позиции. Например, [`divmod()`](https://python-all.ru/3.16/library/functions.html#divmod) – это функция, принимающая только позиционные параметры. Её документация выглядит так:616617```python618>>> help(divmod)619Help on built-in function divmod in module builtins:620621divmod(x, y, /)622 Return the tuple (x//y, x%y). Invariant: div*y + mod == x.623```624625Косая черта в конце списка параметров означает, что оба параметра являются только позиционными. Таким образом, вызов [`divmod()`](https://python-all.ru/3.16/library/functions.html#divmod) с именованными аргументами приведёт к ошибке:626627```python628>>> divmod(x=3, y=4)629Traceback (most recent call last):630 File "<stdin>", line 1, in <module>631TypeError: divmod() takes no keyword arguments632```633634## [Числа и строки](https://python-all.ru/3.16/faq/programming.html#id27)635636### [Как задать шестнадцатеричные и восьмеричные целые числа?](https://python-all.ru/3.16/faq/programming.html#id28)637638Чтобы задать восьмеричное число, поставьте перед восьмеричным значением ноль, а затем строчную или прописную букву «o». Например, чтобы присвоить переменной «a» восьмеричное значение «10» (8 в десятичной системе), введите:639640```python641>>> a = 0o10642>>> a6438644```645646Шестнадцатеричные числа задаются так же просто. Просто поставьте перед шестнадцатеричным числом ноль, а затем строчную или прописную «x». Шестнадцатеричные цифры можно указывать в нижнем или верхнем регистре. Например, в интерпретаторе Python:647648```python649>>> a = 0xa5650>>> a651165652>>> b = 0XB2653>>> b654178655```656657### [Почему -22 // 10 возвращает -3?](https://python-all.ru/3.16/faq/programming.html#id29)658659В первую очередь это вызвано желанием, чтобы `i % j` имел тот же знак, что и `j`. Если вы хотите этого, а также хотите:660661```python662i == (i // j) * j + (i % j)663```664665тогда целочисленное деление должно возвращать пол (округление вниз). Язык C также требует выполнения этого тождества, и тогда компиляторы, усекающие `i // j`, должны делать так, чтобы `i % j` имел тот же знак, что и `i`.666667Существует мало реальных применений `i % j`, когда `j` отрицательно. Когда `j` положительно, применений много, и практически во всех из них полезнее, чтобы `i % j` было `>= 0`. Если часы показывают 10 сейчас, что они показывали 200 часов назад? `-190 % 12 == 2` полезно; `-190 % 12 == -10` – это ошибка, которая только и ждёт, чтобы её допустили.668669### [Как получить атрибут целочисленного литерала вместо SyntaxError?](https://python-all.ru/3.16/faq/programming.html#id30)670671Попытка обратиться к атрибуту `int`-литерала обычным способом приводит к ошибке [`SyntaxError`](https://python-all.ru/3.16/library/exceptions.html#SyntaxError), поскольку точка воспринимается как десятичный разделитель:672673```python674>>> 1.__class__675 File "<stdin>", line 1676 1.__class__677 ^678SyntaxError: invalid decimal literal679```680681Решение – отделить литерал от точки пробелом или скобками.682683```python684>>> 1 .__class__685<class 'int'>686>>> (1).__class__687<class 'int'>688```689690### [Как преобразовать строку в число?](https://python-all.ru/3.16/faq/programming.html#id31)691692Для целых чисел используйте встроенный конструктор типа [`int()`](https://python-all.ru/3.16/library/functions.html#int), например `int('144') == 144`. Аналогично, [`float()`](https://python-all.ru/3.16/library/functions.html#float) преобразует в число с плавающей точкой, например `float('144') == 144.0`.693694По умолчанию эти функции считают число десятичным, поэтому `int('0144') == 144` истинно, а `int('0x144')` вызывает [`ValueError`](https://python-all.ru/3.16/library/exceptions.html#ValueError). Функция `int(string, base)` принимает необязательный второй аргумент – основание системы счисления, так что `int( '0x144', 16) == 324`. Если основание указано как 0, число интерпретируется по правилам Python: ведущее «0o» означает восьмеричную, а «0x» – шестнадцатеричную систему.695696Не используйте встроенную функцию [`eval()`](https://python-all.ru/3.16/library/functions.html#eval), если нужно просто преобразовать строку в число. `eval()` будет работать значительно медленнее и создаёт угрозу безопасности: кто-то может передать Python-выражение с нежелательными побочными эффектами. Например, можно передать `__import__('os').system("rm -rf $HOME")`, что приведёт к удалению вашего домашнего каталога.697698Кроме того, [`eval()`](https://python-all.ru/3.16/library/functions.html#eval) интерпретирует числа как Python-выражения, поэтому, например, `eval('09')` вызывает синтаксическую ошибку, поскольку Python не допускает ведущего нуля в десятичном числе (кроме самого «0»).699700### [Как преобразовать число в строку?](https://python-all.ru/3.16/faq/programming.html#id32)701702Например, чтобы преобразовать число `144` в строку `'144'`, используйте встроенный конструктор типа [`str()`](https://python-all.ru/3.16/library/stdtypes.html#str). Если нужна шестнадцатеричная или восьмеричная запись, используйте встроенные функции [`hex()`](https://python-all.ru/3.16/library/functions.html#hex) или [`oct()`](https://python-all.ru/3.16/library/functions.html#oct). Для расширенного форматирования смотрите разделы [f-строки](https://python-all.ru/3.16/reference/lexical_analysis.html#f-strings) и [Синтаксис форматных строк](https://python-all.ru/3.16/library/string.html#formatstrings). Например, `"{:04d}".format(144)` даёт `'0144'`, а `"{:.3f}".format(1.0/3.0)` даёт `'0.333'`.703704### [Как изменить строку на месте?](https://python-all.ru/3.16/faq/programming.html#id33)705706Никак, строки неизменяемы. В большинстве случаев следует просто собрать новую строку из нужных частей. Однако, если требуется изменять на месте Unicode-данные, попробуйте использовать объект [`io.StringIO`](https://python-all.ru/3.16/library/io.html#io.StringIO) или модуль [`array`](https://python-all.ru/3.16/library/array.html#module-array):707708```python709>>> import io710>>> s = "Hello, world"711>>> sio = io.StringIO(s)712>>> sio.getvalue()713'Hello, world'714>>> sio.seek(7)7157716>>> sio.write("there!")7176718>>> sio.getvalue()719'Hello, there!'720721>>> import array722>>> a = array.array('w', s)723>>> print(a)724array('w', 'Hello, world')725>>> a[0] = 'y'726>>> print(a)727array('w', 'yello, world')728>>> a.tounicode()729'yello, world'730```731732### [Как использовать строки для вызова функций/методов?](https://python-all.ru/3.16/faq/programming.html#id34)733734Существует несколько приёмов.735736- Лучший из них – использовать словарь, сопоставляющий строки с функциями. Главное преимущество этого подхода в том, что строки не обязаны совпадать с именами функций. Это также основной способ эмуляции конструкции case:737738 ```python739 def a():740 pass741742 def b():743 pass744745 dispatch = {'go': a, 'stop': b} # Обратите внимание на отсутствие скобок для функций746747 dispatch[get_input()]() # Обратите внимание на завершающие скобки для вызова функции748 ```749- Используйте встроенную функцию [`getattr()`](https://python-all.ru/3.16/library/functions.html#getattr):750751 ```python752 import foo753 getattr(foo, 'bar')()754 ```755756 Обратите внимание: [`getattr()`](https://python-all.ru/3.16/library/functions.html#getattr) работает с любыми объектами, включая классы, экземпляры классов, модули и т.д.757758 Это используется в нескольких местах стандартной библиотеки, например:759760 ```python761 class Foo:762 def do_foo(self):763 ...764765 def do_bar(self):766 ...767768 f = getattr(foo_instance, 'do_' + opname)769 f()770 ```771- Используйте [`locals()`](https://python-all.ru/3.16/library/functions.html#locals) для разрешения имени функции:772773 ```python774 def myFunc():775 print("hello")776777 fname = "myFunc"778779 f = locals()[fname]780 f()781 ```782783### [Существует ли эквивалент Perl-функции `chomp()` для удаления завершающих символов новой строки?](https://python-all.ru/3.16/faq/programming.html#id35)784785Можно использовать `S.rstrip("\r\n")` для удаления всех символов конца строки в конце строки `S`, не затрагивая остальные пробельные символы. Если строка `S` содержит несколько строк с пустыми строками в конце, будут удалены завершающие символы для всех пустых строк:786787```python788>>> lines = ("line 1 \r\n"789... "\r\n"790... "\r\n")791>>> lines.rstrip("\n\r")792'line 1 '793```794795Поскольку такой подход обычно нужен только при чтении текста построчно, `S.rstrip()` в таком виде отлично подходит.796797### [Существует ли аналог `scanf()` или `sscanf()`?](https://python-all.ru/3.16/faq/programming.html#id36)798799Прямого аналога нет.800801Для простого разбора ввода проще всего разбить строку на слова, разделённые пробельными символами, с помощью метода [`split()`](https://python-all.ru/3.16/library/stdtypes.html#str.split) строковых объектов, а затем преобразовать десятичные строки в числа через [`int()`](https://python-all.ru/3.16/library/functions.html#int) или [`float()`](https://python-all.ru/3.16/library/functions.html#float). Функция `split()` поддерживает необязательный параметр «sep», который удобен, если разделителем выступает не пробел.802803Для более сложного разбора ввода регулярные выражения мощнее, чем C-функция `sscanf`, и лучше подходят для этой задачи.804805### [Что означает ошибка `UnicodeDecodeError` или `UnicodeEncodeError`?](https://python-all.ru/3.16/faq/programming.html#id37)806807Смотрите [Unicode HOWTO](https://python-all.ru/3.16/howto/unicode.html#unicode-howto).808809### [Может ли сырая строка заканчиваться нечётным количеством обратных косых?](https://python-all.ru/3.16/faq/programming.html#id38)810811Сырая строка, заканчивающаяся нечётным количеством обратных косых, экранирует кавычку строки:812813```python814>>> r'C:\this\will\not\work\'815 File "<stdin>", line 1816 r'C:\this\will\not\work\'817 ^818SyntaxError: unterminated string literal (detected at line 1)819```820821Есть несколько обходных путей. Один – использовать обычные строки и удвоить обратные косые:822823```python824>>> 'C:\\this\\will\\work\\'825'C:\\this\\will\\work\\'826```827828Другой – конкатенировать обычную строку, содержащую экранированную обратную косую, с сырой строкой:829830```python831>>> r'C:\this\will\work' '\\'832'C:\\this\\will\\work\\'833```834835Также можно воспользоваться [`os.path.join()`](https://python-all.ru/3.16/library/os.path.html#os.path.join), чтобы добавить обратную косую в Windows:836837```python838>>> os.path.join(r'C:\this\will\work', '')839'C:\\this\\will\\work\\'840```841842Обратите внимание: хотя обратная косая черта «экранирует» кавычку для целей определения конца сырой строки, при интерпретации значения сырой строки никакого экранирования не происходит. То есть обратная косая черта остаётся в значении сырой строки:843844```python845>>> r'backslash\'preserved'846"backslash\\'preserved"847```848849См. также спецификацию в [справочнике по языку](https://python-all.ru/3.16/reference/lexical_analysis.html#strings).850851## [Производительность](https://python-all.ru/3.16/faq/programming.html#id39)852853### [Моя программа слишком медленная. Как её ускорить?](https://python-all.ru/3.16/faq/programming.html#id40)854855В целом, это сложный вопрос. Вот список моментов, которые стоит запомнить, прежде чем углубляться:856857- Характеристики производительности различаются в разных реализациях Python. Этот FAQ сосредоточен на [CPython](https://python-all.ru/3.16/glossary.html#term-CPython).858- Поведение может различаться в разных операционных системах, особенно когда речь идёт о вводе-выводе или многопоточности.859- всегда следует находить горячие точки в своей программе *перед* попыткой оптимизировать какой-либо код (см. модуль [`profile`](https://python-all.ru/3.16/library/profile.html#module-profile)).860- Написание эталонных скриптов позволит быстро выполнять итерации при поиске улучшений (см. модуль [`timeit`](https://python-all.ru/3.16/library/timeit.html#module-timeit)).861- Настоятельно рекомендуется иметь хорошее покрытие кода (с помощью модульного тестирования или любой другой методики) перед возможным внесением регрессий, скрытых в сложных оптимизациях.862863Тем не менее, есть много приёмов для ускорения кода на Python. Вот некоторые общие принципы, которые сильно помогают достичь приемлемого уровня производительности:864865- Ускорение алгоритмов (или замена на более быстрые) может принести гораздо большую выгоду, чем попытки рассыпать микрооптимизации по всему коду.866- Используйте правильные структуры данных. Изучите документацию по [Встроенным типам](https://python-all.ru/3.16/library/stdtypes.html#bltin-types) и модулю [`collections`](https://python-all.ru/3.16/library/collections.html#module-collections).867- Когда стандартная библиотека предоставляет примитив для выполнения какой-либо задачи, он, скорее всего (хотя и не гарантированно), будет быстрее любой альтернативы, которую вы можете придумать. Это вдвойне верно для примитивов, написанных на C, таких как встроенные функции и некоторые типы расширений. Например, обязательно используйте либо встроенный метод [`list.sort()`](https://python-all.ru/3.16/library/stdtypes.html#list.sort), либо соответствующую функцию [`sorted()`](https://python-all.ru/3.16/library/functions.html#sorted) для сортировки (и посмотрите [Методы сортировки](https://python-all.ru/3.16/howto/sorting.html#sortinghowto) для примеров умеренно продвинутого использования).868- Абстракции обычно создают косвенность и заставляют интерпретатор работать больше. Если уровни косвенности перевешивают объём полезной работы, программа будет медленнее. Следует избегать чрезмерной абстракции, особенно в виде крошечных функций или методов (которые также часто вредят читаемости).869870Если вы достигли предела возможностей чистого Python, существуют инструменты, которые помогут пойти дальше. Например, [Cython](https://python-all.ru/3.16/faq/programming.html) может скомпилировать слегка изменённую версию кода Python в расширение C и может использоваться на многих разных платформах. Cython может использовать компиляцию (и необязательные аннотации типов), чтобы сделать ваш код значительно быстрее, чем при интерпретации. Если вы уверены в своих навыках программирования на C, вы также можете самостоятельно [написать модуль расширения на C](https://python-all.ru/3.16/extending/index.html#extending-index).871872> **См. также**873>874> Вики-страница, посвящённая [советам по производительности](https://python-all.ru/3.16/faq/programming.html).875876### [Как наиболее эффективно объединить много строк?](https://python-all.ru/3.16/faq/programming.html#id41)877878Объекты [`str`](https://python-all.ru/3.16/library/stdtypes.html#str) и [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) неизменяемы, поэтому объединение множества строк неэффективно, поскольку каждое объединение создаёт новый объект. В общем случае общая стоимость выполнения квадратично зависит от общей длины строк.879880Для накопления множества объектов [`str`](https://python-all.ru/3.16/library/stdtypes.html#str) рекомендуется помещать их в список и в конце вызвать [`str.join()`](https://python-all.ru/3.16/library/stdtypes.html#str.join):881882```python883chunks = []884for s in my_strings:885 chunks.append(s)886result = ''.join(chunks)887```888889(Другой достаточно эффективный приём – использовать [`io.StringIO`](https://python-all.ru/3.16/library/io.html#io.StringIO).)890891Для накопления множества объектов [`bytes`](https://python-all.ru/3.16/library/stdtypes.html#bytes) рекомендуется расширять объект [`bytearray`](https://python-all.ru/3.16/library/stdtypes.html#bytearray) с помощью конкатенации на месте (оператор `+=`):892893```python894result = bytearray()895for b in my_bytes_objects:896 result += b897```898899## [Последовательности (кортежи/списки)](https://python-all.ru/3.16/faq/programming.html#id42)900901### [Как преобразовывать кортежи и списки друг в друга?](https://python-all.ru/3.16/faq/programming.html#id43)902903Конструктор типа `tuple(seq)` преобразует любую последовательность (на самом деле любой итерируемый объект) в кортеж с теми же элементами в том же порядке.904905Например, `tuple([1, 2, 3])` даёт `(1, 2, 3)`, а `tuple('abc')` даёт `('a', 'b', 'c')`. Если аргумент уже является кортежем, копия не создаётся – возвращается тот же объект, поэтому вызов [`tuple()`](https://python-all.ru/3.16/library/stdtypes.html#tuple) обходится дёшево, когда нет уверенности, что объект уже является кортежем.906907Конструктор типа `list(seq)` преобразует любую последовательность или итерируемый объект в список с теми же элементами в том же порядке. Например, `list((1, 2, 3))` даёт `[1, 2, 3]`, а `list('abc')` даёт `['a', 'b', 'c']`. Если аргумент является списком, создаётся копия, как и в случае `seq[:]`.908909### [Что такое отрицательный индекс?](https://python-all.ru/3.16/faq/programming.html#id44)910911Последовательности Python индексируются положительными и отрицательными числами. Для положительных чисел 0 – это первый индекс, 1 – второй и так далее. Для отрицательных индексов -1 – последний индекс, -2 – предпоследний (перед последним) и так далее. Считайте `seq[-n]` тем же, что и `seq[len(seq)-n]`.912913Использование отрицательных индексов может быть очень удобным. Например, `S[:-1]` – это вся строка, кроме последнего символа, что полезно для удаления завершающего перевода строки.914915### [Как перебрать последовательность в обратном порядке?](https://python-all.ru/3.16/faq/programming.html#id45)916917Используйте встроенную функцию [`reversed()`](https://python-all.ru/3.16/library/functions.html#reversed):918919```python920for x in reversed(sequence):921 ... # сделать что-то с x ...922```923924Это не затронет исходную последовательность, а создаст новую копию с обратным порядком для итерации.925926### [Как удалить дубликаты из списка?](https://python-all.ru/3.16/faq/programming.html#id46)927928См. Python Cookbook, где подробно рассматриваются многие способы сделать это:929930> [https://code.activestate.com/recipes/52560/](https://python-all.ru/3.16/faq/programming.html)931932Если перестановка элементов списка не страшна, отсортируйте его, а затем просмотрите с конца, удаляя дубликаты по ходу:933934```python935if mylist:936 mylist.sort()937 last = mylist[-1]938 for i in range(len(mylist)-2, -1, -1):939 if last == mylist[i]:940 del mylist[i]941 else:942 last = mylist[i]943```944945Если все элементы списка могут использоваться как ключи множества (то есть все они [хэшируемы](https://python-all.ru/3.16/glossary.html#term-hashable)), это часто быстрее:946947```python948mylist = list(set(mylist))949```950951Это преобразует список во множество, удаляя дубликаты, а затем обратно в список.952953### [Как удалить несколько элементов из списка?](https://python-all.ru/3.16/faq/programming.html#id47)954955Как и при удалении дубликатов, один из вариантов – явная итерация в обратном порядке с проверкой условия удаления. Однако проще и быстрее использовать замену среза с неявной или явной прямой итерацией. Вот три варианта:956957```python958mylist[:] = filter(keep_function, mylist)959mylist[:] = (x for x in mylist if keep_condition)960mylist[:] = [x for x in mylist if keep_condition]961```962963Скорее всего, быстрее всего работает списковое включение.964965### [Как создать массив в Python?](https://python-all.ru/3.16/faq/programming.html#id48)966967Используйте список:968969```python970["this", 1, "is", "an", "array"]971```972973По временно́й сложности списки эквивалентны массивам C или Pascal; основное отличие в том, что список Python может содержать объекты разных типов.974975Модуль `array` также предоставляет методы для создания массивов фиксированных типов с компактным представлением, но они медленнее при индексации, чем списки. Также обратите внимание, что [NumPy](https://python-all.ru/3.16/faq/programming.html) и другие сторонние пакеты определяют массиво-подобные структуры с различными характеристиками.976977Чтобы получить связные списки в стиле Lisp, можно эмулировать *ячейки cons* с помощью кортежей:978979```python980lisp_list = ("like", ("this", ("example", None) ) )981```982983Если нужна изменяемость, можно использовать списки вместо кортежей. Здесь аналог Lisp-овского *car* – `lisp_list[0]`, аналог *cdr* – `lisp_list[1]`. Делайте так, только если уверены, что это действительно необходимо, потому что обычно это работает намного медленнее, чем использование списков Python.984985### [Как создать многомерный список?](https://python-all.ru/3.16/faq/programming.html#id49)986987Вероятно, вы пытались создать многомерный массив так:988989```python990>>> A = [[None] * 2] * 3991```992993Если вывести его, выглядит правильно:994995```pycon996>>> A997[[None, None], [None, None], [None, None]]998```9991000Но когда вы присваиваете значение, оно появляется в нескольких местах:10011002```pycon1003>>> A[0][0] = 51004>>> A1005[[5, None], [5, None], [5, None]]1006```10071008Причина в том, что размножение списка с помощью `*` не создаёт копии, а только ссылки на существующие объекты. `*3` создаёт список из 3 ссылок на один и тот же список длины два. Изменения в одной строке отразятся во всех строках, что почти наверняка не то, что нужно.10091010Рекомендуемый подход – сначала создать список нужной длины, а затем заполнить каждый элемент заново созданным списком:10111012```python1013A = [None] * 31014for i in range(3):1015 A[i] = [None] * 21016```10171018Это порождает список, содержащий 3 разных списка длины два. Также можно использовать списковое включение:10191020```python1021w, h = 2, 31022A = [[None] * w for i in range(h)]1023```10241025Или можно воспользоваться расширением, предоставляющим тип данных «матрица»; наиболее известен [NumPy](https://python-all.ru/3.16/faq/programming.html).10261027### [Как применить метод или функцию к последовательности объектов?](https://python-all.ru/3.16/faq/programming.html#id50)10281029Для вызова метода или функции с накоплением возвращаемых значений в списке элегантным решением служит [списковое включение](https://python-all.ru/3.16/glossary.html#term-list-comprehension):10301031```python1032result = [obj.method() for obj in mylist]10331034result = [function(obj) for obj in mylist]1035```10361037Если нужно просто выполнить метод или функцию без сохранения возвращаемых значений, достаточно обычного цикла [`for`](https://python-all.ru/3.16/reference/compound_stmts.html#for):10381039```python1040for obj in mylist:1041 obj.method()10421043for obj in mylist:1044 function(obj)1045```10461047### [Почему a\_tuple\[i\] += \['item'\] вызывает исключение, хотя сложение работает?](https://python-all.ru/3.16/faq/programming.html#id51)10481049Это связано с тем, что операторы расширенного присваивания являются *операторами присваивания*, а также с различием между изменяемыми и неизменяемыми объектами в Python.10501051Это обсуждение в целом применимо, когда операторы расширенного присваивания применяются к элементам кортежа, указывающим на изменяемые объекты, но в качестве примера мы используем `list` и `+=`.10521053Если написать:10541055```python1056>>> a_tuple = (1, 2)1057>>> a_tuple[0] += 11058Traceback (most recent call last):1059 ...1060TypeError: 'tuple' object does not support item assignment1061```10621063Причина исключения сразу становится ясна: `1` добавляется к объекту, на который указывает `a_tuple[0]` (`1`), в результате получается объект `2`, но когда мы пытаемся присвоить результат вычисления `2` элементу `0` кортежа, возникает ошибка, потому что нельзя изменить, на что указывает элемент кортежа.10641065На самом деле то, что делает этот расширенный оператор присваивания, примерно таково:10661067```python1068>>> result = a_tuple[0] + 11069>>> a_tuple[0] = result1070Traceback (most recent call last):1071 ...1072TypeError: 'tuple' object does not support item assignment1073```10741075Ошибку вызывает именно часть присваивания операции, поскольку кортеж неизменяем.10761077Если написать что-то вроде:10781079```python1080>>> a_tuple = (['foo'], 'bar')1081>>> a_tuple[0] += ['item']1082Traceback (most recent call last):1083 ...1084TypeError: 'tuple' object does not support item assignment1085```10861087Исключение несколько более неожиданно, и еще более удивительно то, что, несмотря на ошибку, append сработал:10881089```python1090>>> a_tuple[0]1091['foo', 'item']1092```10931094Чтобы понять, почему это происходит, нужно знать, что (a) если объект реализует магический метод [`__iadd__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__iadd__), он вызывается при выполнении `+=` расширенного присваивания, и его возвращаемое значение используется в операторе присваивания; и (b) для списков `__iadd__()` эквивалентно вызову [`extend()`](https://python-all.ru/3.16/library/stdtypes.html#sequence.extend) для списка и возврату этого списка. Именно поэтому говорят, что для списков `+=` – это «сокращение» для [`list.extend()`](https://python-all.ru/3.16/library/stdtypes.html#list.extend):10951096```python1097>>> a_list = []1098>>> a_list += [1]1099>>> a_list1100[1]1101```11021103Это эквивалентно:11041105```python1106>>> result = a_list.__iadd__([1])1107>>> a_list = result1108```11091110Объект, на который указывает a\_list, был изменён, и указатель на изменённый объект присваивается обратно `a_list`. Конечный результат присваивания – холостая операция (no-op), поскольку это указатель на тот же объект, на который `a_list` указывал ранее, но само присваивание всё равно происходит.11111112Таким образом, в нашем примере с кортежем происходит то же самое, что и в:11131114```python1115>>> result = a_tuple[0].__iadd__(['item'])1116>>> a_tuple[0] = result1117Traceback (most recent call last):1118 ...1119TypeError: 'tuple' object does not support item assignment1120```11211122`__iadd__()` выполняется успешно, и список расширяется, но, хотя `result` указывает на тот же объект, на который уже указывает `a_tuple[0]`, финальное присваивание всё равно вызывает ошибку, поскольку кортежи неизменяемы.11231124### [Я хочу выполнить сложную сортировку: можно ли сделать преобразование Шварца в Python?](https://python-all.ru/3.16/faq/programming.html#id52)11251126Этот метод, приписываемый Рэндалу Шварцу из сообщества Perl, сортирует элементы списка по метрике, которая сопоставляет каждому элементу его «сортировочное значение». В Python используйте аргумент `key` для метода [`list.sort()`](https://python-all.ru/3.16/library/stdtypes.html#list.sort):11271128```python1129Isorted = L[:]1130Isorted.sort(key=lambda s: int(s[10:15]))1131```11321133### [Как отсортировать один список по значениям из другого списка?](https://python-all.ru/3.16/faq/programming.html#id53)11341135Объедините их в итератор кортежей, отсортируйте полученный список, а затем извлеките нужный элемент.11361137```python1138>>> list1 = ["what", "I'm", "sorting", "by"]1139>>> list2 = ["something", "else", "to", "sort"]1140>>> pairs = zip(list1, list2)1141>>> pairs = sorted(pairs)1142>>> pairs1143[("I'm", 'else'), ('by', 'sort'), ('sorting', 'to'), ('what', 'something')]1144>>> result = [x[1] for x in pairs]1145>>> result1146['else', 'sort', 'to', 'something']1147```11481149## [Объекты](https://python-all.ru/3.16/faq/programming.html#id54)11501151### [Что такое класс?](https://python-all.ru/3.16/faq/programming.html#id55)11521153Класс – это конкретный тип объекта, создаваемый при выполнении инструкции class. Объекты классов используются как шаблоны для создания объектов-экземпляров, которые содержат как данные (атрибуты), так и код (методы), характерные для данного типа данных.11541155Класс может быть основан на одном или нескольких других классах, называемых его базовыми классами. Он наследует атрибуты и методы своих базовых классов. Это позволяет последовательно уточнять объектную модель с помощью наследования. Например, можно иметь общий класс `Mailbox`, предоставляющий базовые методы доступа к почтовому ящику, и подклассы `MboxMailbox`, `MaildirMailbox`, `OutlookMailbox`, обрабатывающие различные форматы почтовых ящиков.11561157### [Что такое метод?](https://python-all.ru/3.16/faq/programming.html#id56)11581159Метод – это функция некоторого объекта `x`, которая обычно вызывается как `x.name(arguments...)`. Методы определяются как функции внутри определения класса:11601161```python1162class C:1163 def meth(self, arg):1164 return arg * 2 + self.attribute1165```11661167### [Что такое self?](https://python-all.ru/3.16/faq/programming.html#id57)11681169Self – это просто условное имя для первого аргумента метода. Метод, определённый как `meth(self, a, b, c)`, должен вызываться как `x.meth(a, b, c)` для некоторого экземпляра `x` класса, в котором находится определение; вызванный метод будет считать, что его вызвали как `meth(x, a, b, c)`.11701171См. также [Почему self должно явно использоваться в определениях и вызовах методов?](https://python-all.ru/3.16/faq/design.html#why-self).11721173### [Как проверить, является ли объект экземпляром данного класса или его подкласса?](https://python-all.ru/3.16/faq/programming.html#id58)11741175Используйте встроенную функцию [`isinstance(obj, cls)`](https://python-all.ru/3.16/library/functions.html#isinstance). Можно проверить, является ли объект экземпляром любого из нескольких классов, передав кортеж вместо одного класса, например `isinstance(obj, (class1, class2, ...))`, а также можно проверить, является ли объект одним из встроенных типов Python, например `isinstance(obj, str)` или `isinstance(obj, (int, float, complex))`.11761177Обратите внимание, что [`isinstance()`](https://python-all.ru/3.16/library/functions.html#isinstance) также проверяет виртуальное наследование от [абстрактного базового класса](https://python-all.ru/3.16/glossary.html#term-abstract-base-class). Таким образом, проверка вернёт `True` для зарегистрированного класса, даже если он не наследует от него прямо или косвенно. Чтобы проверить «истинное наследование», просмотрите [порядок разрешения методов](https://python-all.ru/3.16/glossary.html#term-method-resolution-order) (MRO) класса:11781179```python1180from collections.abc import Mapping11811182class P:1183 pass11841185class C(P):1186 pass11871188Mapping.register(P)1189```11901191```pycon1192>>> c = C()1193>>> isinstance(c, C) # прямой1194True1195>>> isinstance(c, P) # косвенный1196True1197>>> isinstance(c, Mapping) # виртуальный1198True11991200# Actual inheritance chain1201>>> type(c).__mro__1202(<class 'C'>, <class 'P'>, <class 'object'>)12031204# Test for "true inheritance"1205>>> Mapping in type(c).__mro__1206False1207```12081209Обратите внимание, что большинство программ не используют [`isinstance()`](https://python-all.ru/3.16/library/functions.html#isinstance) для пользовательских классов очень часто. Если вы разрабатываете классы сами, более правильным объектно-ориентированным стилем будет определение методов в классах, инкапсулирующих определённое поведение, вместо проверки класса объекта и выполнения разных действий в зависимости от того, какой это класс. Например, если есть функция, которая делает что-то:12101211```python1212def search(obj):1213 if isinstance(obj, Mailbox):1214 ... # код для поиска почтового ящика1215 elif isinstance(obj, Document):1216 ... # код для поиска документа1217 elif ...1218```12191220Лучше определить метод `search()` во всех классах и просто вызывать его:12211222```python1223class Mailbox:1224 def search(self):1225 ... # код для поиска почтового ящика12261227class Document:1228 def search(self):1229 ... # код для поиска документа12301231obj.search()1232```12331234### [Что такое делегирование?](https://python-all.ru/3.16/faq/programming.html#id59)12351236Делегирование – это объектно-ориентированный приём (также называемый шаблоном проектирования). Предположим, у вас есть объект `x`, и вы хотите изменить поведение только одного из его методов. Можно создать новый класс, который предоставляет новую реализацию интересующего метода, а все остальные методы делегирует соответствующим методам `x`.12371238Программисты на Python могут легко реализовать делегирование. Например, следующий класс реализует класс, который ведёт себя как файл, но преобразует все записываемые данные в верхний регистр:12391240```python1241class UpperOut:12421243 def __init__(self, outfile):1244 self._outfile = outfile12451246 def write(self, s):1247 self._outfile.write(s.upper())12481249 def __getattr__(self, name):1250 return getattr(self._outfile, name)1251```12521253Here the `UpperOut` class redefines the `write()` method to convert the argument string to uppercase before calling the underlying `self._outfile.write()` method. All other methods are delegated to the underlying `self._outfile` object. The delegation is accomplished via the [`__getattr__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__getattr__) method; consult [the language reference](https://python-all.ru/3.16/reference/datamodel.html#attribute-access) for more information about controlling attribute access.12541255Обратите внимание, что в более общих случаях делегирование может усложниться. Если атрибуты нужно не только получать, но и устанавливать, класс должен также определить метод [`__setattr__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__setattr__), и делать это нужно аккуратно. Базовая реализация `__setattr__()` примерно эквивалентна следующему:12561257```python1258class X:1259 ...1260 def __setattr__(self, name, value):1261 self.__dict__[name] = value1262 ...1263```12641265Многие реализации [`__setattr__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__setattr__) вызывают `object.__setattr__()`, чтобы установить атрибут на self, не вызывая бесконечной рекурсии:12661267```python1268class X:1269 def __setattr__(self, name, value):1270 # Пользовательская логика...1271 object.__setattr__(self, name, value)1272```12731274В качестве альтернативы можно устанавливать атрибуты, вставляя записи непосредственно в [`self.__dict__`](https://python-all.ru/3.16/reference/datamodel.html#object.__dict__).12751276### [Как вызвать метод, определённый в базовом классе, из производного класса, который его расширяет?](https://python-all.ru/3.16/faq/programming.html#id60)12771278Используйте встроенную функцию [`super()`](https://python-all.ru/3.16/library/functions.html#super):12791280```python1281class Derived(Base):1282 def meth(self):1283 super().meth() # вызывает Base.meth1284```12851286В этом примере [`super()`](https://python-all.ru/3.16/library/functions.html#super) автоматически определит экземпляр, из которого он был вызван (значение `self`), выполнит поиск [порядка разрешения методов](https://python-all.ru/3.16/glossary.html#term-method-resolution-order) (MRO) с помощью `type(self).__mro__`, и вернёт следующий по порядку после `Derived` в MRO: `Base`.12871288### [Как организовать код, чтобы было проще изменить базовый класс?](https://python-all.ru/3.16/faq/programming.html#id61)12891290Можно присвоить базовый класс псевдониму и наследоваться от псевдонима. Тогда всё, что нужно изменить – это значение, присвоенное псевдониму. Кстати, этот трюк удобен и если требуется динамически решать (например, в зависимости от доступности ресурсов), какой базовый класс использовать. Пример:12911292```python1293class Base:1294 ...12951296BaseAlias = Base12971298class Derived(BaseAlias):1299 ...1300```13011302### [Как создать статические данные класса и статические методы класса?](https://python-all.ru/3.16/faq/programming.html#id62)13031304В Python поддерживаются как статические данные, так и статические методы (в смысле C++ или Java).13051306Для статических данных просто определите атрибут класса. Чтобы присвоить атрибуту новое значение, необходимо явно указать имя класса в присваивании:13071308```python1309class C:1310 count = 0 # количество вызовов C.__init__13111312 def __init__(self):1313 C.count = C.count + 113141315 def getcount(self):1316 return C.count # или вернуть self.count1317```13181319`c.count` также ссылается на `C.count` для любого `c`, для которого `isinstance(c, C)` истинно, если только оно не переопределено самим `c` или каким-либо классом на пути поиска базового класса от `c.__class__` до `C`.13201321Внимание: внутри метода C присваивание вида `self.count = 42` создаёт новый и не связанный экземпляр с именем «count» в собственном словаре `self`. Повторное связывание имени статических данных класса всегда должно указывать класс, как внутри метода, так и вне его:13221323```python1324C.count = 3141325```13261327Статические методы возможны:13281329```python1330class C:1331 @staticmethod1332 def static(arg1, arg2, arg3):1333 # Нет параметра 'self'!1334 ...1335```13361337Однако гораздо более прямолинейный способ получить эффект статического метода – это простая функция уровня модуля:13381339```python1340def getcount():1341 return C.count1342```13431344Если код организован так, что на каждый модуль определён один класс (или тесно связанная иерархия классов), это обеспечивает нужную инкапсуляцию.13451346### [Как перегрузить конструкторы (или методы) в Python?](https://python-all.ru/3.16/faq/programming.html#id63)13471348Этот ответ на самом деле применим ко всем методам, но вопрос обычно возникает в первую очередь в контексте конструкторов.13491350В C++ вы бы написали:13511352```c++1353class C {1354 C() { cout << "No arguments\n"; }1355 C(int i) { cout << "Argument is " << i << "\n"; }1356}1357```13581359В Python нужно написать один конструктор, который обрабатывает все случаи с помощью аргументов по умолчанию. Например:13601361```python1362class C:1363 def __init__(self, i=None):1364 if i is None:1365 print("No arguments")1366 else:1367 print("Argument is", i)1368```13691370Это не полностью эквивалентно, но на практике достаточно близко.13711372Можно также попробовать список аргументов переменной длины, например:13731374```python1375def __init__(self, *args):1376 ...1377```13781379Тот же подход работает для всех определений методов.13801381### [Я пытаюсь использовать \_\_spam и получаю ошибку про \_SomeClassName\_\_spam.](https://python-all.ru/3.16/faq/programming.html#id64)13821383Имена переменных с двойным подчёркиванием в начале «искажаются» – это простой, но эффективный способ определения приватных переменных класса. Любой идентификатор вида `__spam` (не менее двух начальных подчёркиваний и не более одного конечного) текстуально заменяется на `_classname__spam`, где `classname` – это имя текущего класса без начальных подчёркиваний.13841385Идентификатор можно использовать без изменений внутри класса, но для доступа к нему вне класса необходимо использовать искажённое имя:13861387```python1388class A:1389 def __one(self):1390 return 11391 def two(self):1392 return 2 * self.__one()13931394class B(A):1395 def three(self):1396 return 3 * self._A__one()13971398four = 4 * A()._A__one()1399```14001401В частности, это не гарантирует приватность, поскольку внешний пользователь всё ещё может намеренно обратиться к приватному атрибуту; многие программисты Python вообще не утруждают себя использованием приватных имён переменных.14021403> **См. также**1404>1405> См. [спецификации искажения приватных имён](https://python-all.ru/3.16/reference/expressions.html#private-name-mangling) с подробностями и особыми случаями.14061407### [Мой класс определяет \_\_del\_\_, но он не вызывается, когда я удаляю объект.](https://python-all.ru/3.16/faq/programming.html#id65)14081409Для этого есть несколько возможных причин.14101411Оператор [`del`](https://python-all.ru/3.16/reference/simple_stmts.html#del) не обязательно вызывает [`__del__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__del__) – он просто уменьшает счётчик ссылок объекта, и если он достигает нуля, вызывается `__del__()`.14121413Если структуры данных содержат циклические ссылки (например, дерево, где каждый потомок имеет ссылку на родителя, а у каждого родителя есть список потомков), счётчики ссылок никогда не обнулятся. Время от времени Python запускает алгоритм для обнаружения таких циклов, но сборщик мусора может сработать спустя некоторое время после исчезновения последней ссылки на структуру данных, поэтому метод `__del__()` может быть вызван в неудобный и случайный момент. Это неудобно, если вы пытаетесь воспроизвести проблему. Хуже того, порядок выполнения методов `__del__()` объектов произволен. Можно запустить [`gc.collect()`](https://python-all.ru/3.16/library/gc.html#gc.collect) для принудительной сборки, но *существуют* патологические случаи, когда объекты никогда не будут собраны.14141415Несмотря на сборщик циклов, всё равно рекомендуется определить явный метод `close()` для объектов, который будет вызываться, когда они больше не нужны. Метод `close()` может затем удалить атрибуты, ссылающиеся на подобъекты. Не вызывайте `__del__()` напрямую – `__del__()` должен вызывать `close()`, а `close()` должен гарантировать, что его можно вызвать более одного раза для одного и того же объекта.14161417Другой способ избежать циклических ссылок – использовать модуль [`weakref`](https://python-all.ru/3.16/library/weakref.html#module-weakref), который позволяет указывать на объекты без увеличения их счётчика ссылок. Например, структуры данных деревьев должны использовать слабые ссылки для ссылок на родительские и дочерние элементы (если они нужны!).14181419Наконец, если метод `__del__()` вызывает исключение, предупреждение выводится в [`sys.stderr`](https://python-all.ru/3.16/library/sys.html#sys.stderr).14201421### [Как получить список всех экземпляров данного класса?](https://python-all.ru/3.16/faq/programming.html#id66)14221423Python не отслеживает все экземпляры класса (или встроенного типа). Можно запрограммировать конструктор класса так, чтобы он отслеживал все экземпляры, сохраняя список слабых ссылок на каждый экземпляр.14241425### [Почему результат `id()` кажется неуникальным?](https://python-all.ru/3.16/faq/programming.html#id67)14261427Встроенная функция [`id()`](https://python-all.ru/3.16/library/functions.html#id) возвращает целое число, которое гарантированно уникально в течение времени жизни объекта. Поскольку в CPython это адрес памяти объекта, часто бывает, что после удаления объекта из памяти следующий свежесозданный объект выделяется по тому же адресу. Это показано на следующем примере:14281429```python1430>>> id(1000)1431139012721432>>> id(2000)1433139012721434```14351436Два идентификатора принадлежат разным целочисленным объектам, которые создаются до и сразу же удаляются после выполнения вызова `id()`. Чтобы убедиться, что объекты, чей id нужно проверить, всё ещё живы, создайте ещё одну ссылку на объект:14371438```python1439>>> a = 1000; b = 20001440>>> id(a)1441139012721442>>> id(b)1443138912961444```14451446### [Когда можно полагаться на проверки идентичности с оператором *is*?](https://python-all.ru/3.16/faq/programming.html#id68)14471448Оператор `is` проверяет идентичность объектов. Выражение `a is b` эквивалентно `id(a) == id(b)`.14491450Важнейшее свойство проверки идентичности: объект всегда идентичен сам себе, поэтому `a is a` всегда возвращает `True`. Проверки идентичности обычно быстрее проверок на равенство. И в отличие от проверок на равенство, проверки идентичности гарантированно возвращают булево значение `True` или `False`.14511452Однако проверки идентичности можно *только* заменять проверки на равенство, когда идентичность объекта гарантирована. В общем случае есть три ситуации, когда идентичность гарантирована:145314541. Присваивания создают новые имена, но не меняют идентичность объекта. После присваивания `new = old` гарантируется, что `new is old`.14552. Помещение объекта в контейнер, хранящий ссылки на объекты, не меняет идентичность объекта. После присваивания списку `s[0] = x` гарантируется, что `s[0] is x`.14563. Если объект является синглтоном, это значит, что может существовать только один его экземпляр. После присваиваний `a = None` и `b = None` гарантируется, что `a is b`, потому что `None` – синглтон.14571458В большинстве других случаев проверки идентичности нежелательны, а предпочтительны проверки на равенство. В частности, не следует использовать проверки идентичности для таких констант, как [`int`](https://python-all.ru/3.16/library/functions.html#int) и [`str`](https://python-all.ru/3.16/library/stdtypes.html#str), которые не гарантированно являются синглтонами:14591460```python1461>>> a = 10_000_0001462>>> b = 5_000_0001463>>> c = b + 5_000_0001464>>> a is c1465False14661467>>> a = 'Python'1468>>> b = 'Py'1469>>> c = b + 'thon'1470>>> a is c1471False1472```14731474Аналогично, новые экземпляры изменяемых контейнеров никогда не идентичны:14751476```python1477>>> a = []1478>>> b = []1479>>> a is b1480False1481```14821483В коде стандартной библиотеки можно увидеть несколько распространённых шаблонов правильного использования проверок идентичности:148414851. Как рекомендуется в [**PEP 8**](https://python-all.ru/3.16/faq/programming.html), проверка идентичности – предпочтительный способ проверки на `None`. Это читается как обычный английский в коде и позволяет избежать путаницы с другими объектами, чьи булевы значения могут быть ложными.14862. Обнаружение необязательных аргументов может быть затруднительным, когда `None` является допустимым входным значением. В таких ситуациях можно создать синглтон-маркер, гарантированно отличный от других объектов. Например, вот как реализовать метод, ведущий себя как [`dict.pop()`](https://python-all.ru/3.16/library/stdtypes.html#dict.pop):14871488 ```python1489 _sentinel = sentinel('_sentinel')14901491 def pop(self, key, default=_sentinel):1492 if key in self:1493 value = self[key]1494 del self[key]1495 return value1496 if default is _sentinel:1497 raise KeyError(key)1498 return default1499 ```15003. Реализации контейнеров иногда требуют дополнить проверки на равенство проверками идентичности. Это предотвращает путаницу в коде с такими объектами, как `float('NaN')`, которые не равны сами себе.15011502Например, вот реализация `collections.abc.Sequence.__contains__()`:15031504```python1505def __contains__(self, value):1506 for v in self:1507 if v is value or v == value:1508 return True1509 return False1510```15111512### [Как подкласс может управлять данными, хранящимися в неизменяемом экземпляре?](https://python-all.ru/3.16/faq/programming.html#id69)15131514При наследовании от неизменяемого типа переопределяйте метод [`__new__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__new__) вместо метода [`__init__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__init__). Последний выполняется *после* создания экземпляра, что слишком поздно для изменения данных в неизменяемом экземпляре.15151516Все эти неизменяемые классы имеют сигнатуру, отличную от родительского класса:15171518```python1519import datetime as dt15201521class FirstOfMonthDate(dt.date):1522 "Always choose the first day of the month"1523 def __new__(cls, year, month, day):1524 return super().__new__(cls, year, month, 1)15251526class NamedInt(int):1527 "Allow text names for some numbers"1528 xlat = {'zero': 0, 'one': 1, 'ten': 10}1529 def __new__(cls, value):1530 value = cls.xlat.get(value, value)1531 return super().__new__(cls, value)15321533class TitleStr(str):1534 "Convert str to name suitable for a URL path"1535 def __new__(cls, s):1536 s = s.lower().replace(' ', '-')1537 s = ''.join([c for c in s if c.isalnum() or c == '-'])1538 return super().__new__(cls, s)1539```15401541Классы можно использовать так:15421543```pycon1544>>> FirstOfMonthDate(2012, 2, 14)1545FirstOfMonthDate(2012, 2, 1)1546>>> NamedInt('ten')1547101548>>> NamedInt(20)1549201550>>> TitleStr('Blog: Why Python Rocks')1551'blog-why-python-rocks'1552```15531554### [Как кешировать вызовы методов?](https://python-all.ru/3.16/faq/programming.html#id70)15551556Два основных инструмента для кеширования методов – [`@functools.cached_property`](https://python-all.ru/3.16/library/functools.html#functools.cached_property) и [`@functools.lru_cache`](https://python-all.ru/3.16/library/functools.html#functools.lru_cache). Первый хранит результаты на уровне экземпляра, второй – на уровне класса.15571558Подход `cached_property` работает только с методами, не принимающими аргументов. Он не создаёт ссылку на экземпляр. Результат кешированного метода будет храниться, пока жив экземпляр.15591560Преимущество в том, что когда экземпляр больше не используется, результат кешированного метода освобождается сразу. Недостаток: если экземпляры накапливаются, то накапливаются и результаты методов. Они могут расти без ограничения.15611562Подход `lru_cache` работает с методами, имеющими [хешируемые](https://python-all.ru/3.16/glossary.html#term-hashable) аргументы. Он создаёт ссылку на экземпляр, если не приложить специальных усилий для передачи слабых ссылок.15631564Преимущество алгоритма наименее недавно использованного (LRU) в том, что размер кеша ограничен указанным *maxsize*. Недостаток: экземпляры остаются живыми, пока не устареют в кеше или пока кеш не будет очищен.15651566Этот пример показывает различные техники:15671568```python1569class Weather:1570 "Lookup weather information on a government website"15711572 def __init__(self, station_id):1573 self._station_id = station_id1574 # _station_id является приватным и неизменяемым15751576 def current_temperature(self):1577 "Latest hourly observation"1578 # Не кэшировать это, потому что старые результаты1579 # могут быть устаревшими.15801581 @cached_property1582 def location(self):1583 "Return the longitude/latitude coordinates of the station"1584 # Результат зависит только от station_id15851586 @lru_cache(maxsize=20)1587 def historic_rainfall(self, date, units='mm'):1588 "Rainfall on a given date"1589 # Зависит от station_id, даты и единиц измерения.1590```15911592Приведённый выше пример предполагает, что *station\_id* никогда не меняется. Если соответствующие атрибуты экземпляра изменяемы, подход `cached_property` не сработает, поскольку он не может обнаружить изменения атрибутов.15931594Чтобы подход `lru_cache` работал, когда *station\_id* изменяем, класс должен определить методы [`__eq__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__eq__) и [`__hash__()`](https://python-all.ru/3.16/reference/datamodel.html#object.__hash__), чтобы кеш мог обнаруживать соответствующие обновления атрибутов:15951596```python1597class Weather:1598 "Example with a mutable station identifier"15991600 def __init__(self, station_id):1601 self.station_id = station_id16021603 def change_station(self, station_id):1604 self.station_id = station_id16051606 def __eq__(self, other):1607 return self.station_id == other.station_id16081609 def __hash__(self):1610 return hash(self.station_id)16111612 @lru_cache(maxsize=20)1613 def historic_rainfall(self, date, units='cm'):1614 'Rainfall on a given date'1615 # Зависит от station_id, даты и единиц измерения.1616```16171618## [Модули](https://python-all.ru/3.16/faq/programming.html#id71)16191620### [Как создать .pyc-файл?](https://python-all.ru/3.16/faq/programming.html#id72)16211622Когда модуль импортируется впервые (или когда исходный файл изменился после создания текущего скомпилированного файла), в подкаталоге `__pycache__` каталога, содержащего файл `.py`, должен быть создан файл `.pyc` со скомпилированным кодом. Файл `.pyc` будет иметь имя, начинающееся с того же имени, что и файл `.py`, и заканчивающееся на `.pyc`, со средней частью, зависящей от конкретной двоичной сборки `python`, которая его создала. (Подробнее см. [**PEP 3147**](https://python-all.ru/3.16/faq/programming.html).)16231624Одна из причин, по которой файл `.pyc` может не создаваться, – проблема с правами доступа к каталогу, содержащему исходный файл: подкаталог `__pycache__` не может быть создан. Это может произойти, например, если вы разрабатываете от одного пользователя, а запускаете от другого, например, при тестировании с помощью веб-сервера.16251626Если не установлена переменная окружения [`PYTHONDONTWRITEBYTECODE`](https://python-all.ru/3.16/using/cmdline.html#envvar-PYTHONDONTWRITEBYTECODE), создание .pyc-файла происходит автоматически при импорте модуля, если у Python есть возможность (права, свободное место и т.д.) создать подкаталог `__pycache__` и записать в него скомпилированный модуль.16271628Запуск Python на скрипте верхнего уровня не считается импортом, и файл `.pyc` не будет создан. Например, если есть модуль верхнего уровня `foo.py`, который импортирует другой модуль `xyz.py`, то при запуске `foo` (командой `python foo.py` в оболочке) файл `.pyc` будет создан для `xyz`, поскольку `xyz` импортируется, но файл `.pyc` не будет создан для `foo`, так как `foo.py` не импортируется.16291630Если нужно создать файл `.pyc` для `foo`, то есть создать файл `.pyc` для модуля, который не импортируется, это можно сделать с помощью модулей [`py_compile`](https://python-all.ru/3.16/library/py_compile.html#module-py_compile) и [`compileall`](https://python-all.ru/3.16/library/compileall.html#module-compileall).16311632Модуль [`py_compile`](https://python-all.ru/3.16/library/py_compile.html#module-py_compile) может вручную скомпилировать любой модуль. Один из способов – интерактивно использовать функцию `compile()` в этом модуле:16331634```python1635>>> import py_compile1636>>> py_compile.compile('foo.py')1637```16381639Это запишет `.pyc` в подкаталог `__pycache__` в том же месте, где находится `foo.py` (или это можно переопределить с помощью необязательного параметра *cfile*).16401641Также можно автоматически скомпилировать все файлы в каталоге или каталогах с помощью модуля [`compileall`](https://python-all.ru/3.16/library/compileall.html#module-compileall). Для этого из командной оболочки выполните `compileall.py` и укажите путь к каталогу, содержащему файлы Python для компиляции:16421643```python1644python -m compileall .1645```16461647### [Как узнать имя текущего модуля?](https://python-all.ru/3.16/faq/programming.html#id73)16481649Модуль может узнать своё собственное имя, обратившись к предопределённой глобальной переменной `__name__`. Если она равна `'__main__'`, программа выполняется как скрипт. Многие модули, которые обычно используются через импорт, также предоставляют интерфейс командной строки или самопроверку и выполняют этот код только после проверки `__name__`:16501651```python1652def main():1653 print('Running test...')1654 ...16551656if __name__ == '__main__':1657 main()1658```16591660### [Как сделать модули, которые импортируют друг друга?](https://python-all.ru/3.16/faq/programming.html#id74)16611662Предположим, у вас есть следующие модули:16631664`foo.py`:16651666```python1667from bar import bar_var1668foo_var = 11669```16701671`bar.py`:16721673```python1674from foo import foo_var1675bar_var = 21676```16771678Проблема в том, что интерпретатор выполнит следующие шаги:16791680- main импортирует `foo`1681- Создаются пустые глобальные переменные для `foo`1682- `foo` компилируется и начинает выполняться1683- `foo` импортирует `bar`1684- Создаются пустые глобальные переменные для `bar`1685- `bar` компилируется и начинает выполняться1686- `bar` импортирует `foo` (это пустая операция, так как модуль с именем `foo` уже существует)1687- Механизм импорта пытается прочитать `foo_var` из глобальных переменных `foo`, чтобы установить `bar.foo_var = foo.foo_var`16881689Последний шаг завершается неудачей, потому что Python ещё не закончил интерпретацию `foo`, и словарь глобальных символов для `foo` всё ещё пуст.16901691То же самое происходит при использовании `import foo` и последующей попытке обратиться к `foo.foo_var` в глобальном коде.16921693Существует (как минимум) три возможных обходных решения этой проблемы.16941695Гвидо ван Россум рекомендует избегать любых использований `from <module> import ...` и размещать весь код внутри функций. Инициализация глобальных переменных и переменных класса должна использовать только константы или встроенные функции. Это означает, что всё из импортированного модуля должно ссылаться как `<module>.<name>`.16961697Джим Роскинд предлагает выполнять шаги в следующем порядке в каждом модуле:16981699- экспорт (глобальные переменные, функции и классы, которым не нужны импортированные базовые классы)1700- инструкции `import`1701- активный код (включая глобальные переменные, инициализируемые из импортированных значений).17021703Ван Россуму не очень нравится такой подход, потому что импорты оказываются в странном месте, но он работает.17041705Маттиас Урлихс рекомендует перестроить код так, чтобы рекурсивный импорт вообще не требовался.17061707Эти решения не являются взаимоисключающими.17081709### [\_\_import\_\_(‘x.y.z’) возвращает \<module ‘x’\>; как получить z?](https://python-all.ru/3.16/faq/programming.html#id75)17101711Рассмотрите возможность использования удобной функции [`import_module()`](https://python-all.ru/3.16/library/importlib.html#importlib.import_module) из [`importlib`](https://python-all.ru/3.16/library/importlib.html#module-importlib) вместо этого.17121713```python1714z = importlib.import_module('x.y.z')1715```17161717### [Когда я редактирую импортированный модуль и повторно импортирую его, изменения не отображаются. Почему это происходит?](https://python-all.ru/3.16/faq/programming.html#id76)17181719Из соображений эффективности и согласованности Python читает файл модуля только при первом импорте модуля. Если бы это было не так, в программе, состоящей из многих модулей, каждый из которых импортирует один и тот же базовый модуль, этот базовый модуль разбирался бы и переразбирался много раз. Чтобы принудительно перечитать изменённый модуль, сделайте следующее:17201721```python1722import importlib1723import modname1724importlib.reload(modname)1725```17261727Предупреждение: этот метод не является полностью надёжным. В частности, модули, содержащие операторы вида:17281729```python1730from modname import some_objects1731```17321733будут продолжать работать со старой версией импортированных объектов. Если модуль содержит определения классов, существующие экземпляры классов *не* будут обновлены для использования нового определения класса. Это может привести к следующему парадоксальному поведению:17341735```python1736>>> import importlib1737>>> import cls1738>>> c = cls.C() # Создать экземпляр C1739>>> importlib.reload(cls)1740<module 'cls' from 'cls.py'>1741>>> isinstance(c, cls.C) # isinstance ложно?!?1742False1743```17441745Суть проблемы становится ясна, если вывести «идентичность» объектов классов:17461747```python1748>>> hex(id(c.__class__))1749'0x7352a0'1750>>> hex(id(cls.C))1751'0x4198d0'1752```1753