{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Скрипты и модули\n", "\n", "Создадим два файла.\n", "\n", "Файл `mymodule.py`.\n", "```python\n", "print(\"Начало импортирования модуля mymodule.py\")\n", "\n", "def f():\n", " print(\"Вызов функции f из модуля mymodule.py\" )\n", "\n", "print(\"Конец импортирования модуля mymodule.py\")\n", "```\n", "\n", "Файл `myscript.py`\n", "```python\n", "import mymodule \n", "\n", "print(type(mymodule))\n", "\n", "mymodule.f()\n", "```\n", "\n", "\n", "Если эти файлы лежат в одной папке, то запуск myscript.py приведет к следующему результату.\n", "```sh\n", ">>> python myscript.py\n", "Начало импортирования модуля mymodule.py\n", "Конец импортирования модуля mymodule.py\n", "\n", "Вызов функции f из модуля mymodule.py\n", ">>> \n", "```\n", "\n", "Разберем, что здесь происходит.\n", "- `import mymodule` импортирует функцию `f` из модуля с именем `mymodule`. Т.к. такого модуля нет в стандартной библиотеке и среди установленных внешних библиотек, то python ищет модуль в текущей папке, находит файл `mymodule.py` и импортирует его. При импортировании модуля, его файл с исходным кодом интерпретируется. Чтобы сократить время повторных импортирований `byte code` сохраняется в папке `__pycache__`, что позволяет пропустить этап компиляции в байт код, если уже существует актуальная версия в кэше. \n", "- По завершении импортирование управление возвращается импортирующему модулю (скрипт `myscript.py` в данном случае). Результатом импортирования является объект типа `module`, который связывается с именем `mymodule` в пространстве имен `myscript.py`. Если бы строка импортирования выглядела `from mymodule import f`, то в пространство имен `myscript.py` заводится имя `f`, которое связывается с объектом по имени `f` из пространства имен `mymodule`. \n", "- Выражение `mymodule.f` говорит интерпретатору искать имя `f` в пространстве имен модуля `mymodule`; \n", "\n", "## Пространства имен модулей\n", "\n", "Более подробно пространства имён буду обсуждаться позже, а здесь обратим внимания на пространства имён модулей. Пространство имён --- таблица имен и связанных с ними объектов. Таких таблицы в любой момент в программе несколько, например, таблица `globals` \"глобальных\" переменных и таблица `locals` локальных переменных, например, для функции, а также пространство [__builtins__](https://docs.python.org/3/library/builtins.html#module-builtins) встроенных функций, которое доступно абсолютно везде и в любой момент времени интерпретации.\n", "\n", "У каждого модуля своё пространство имён `globals`, т.е. глобальность пространства имён распространяется только на текущий модуль (файл). Это значит, что имена созданные в импортированном модуле напрямую не доступны в импортирующем модуле, если не были явно импортированы (`from mymodule import *`). Встроенная функция [globals](https://docs.python.org/3/library/functions.html#globals) возвращает словарь переменных (ключ --- имя, значение --- объект) из глобального пространства имён. Чтобы продемонстрировать это изменим содержимое предыдущих файлов следующим образом. \n", "\n", "Файл `mymodule.py`.\n", "```python\n", "print(\"Начало импортирования модуля mymodule.py\")\n", "\n", "x = 0\n", "\n", "print(globals().keys())\n", "\n", "print(\"Конец импортирования модуля mymodule.py\")\n", "```\n", "\n", "Файл `myscript.py`\n", "```python\n", "import mymodule \n", "\n", "y = 1\n", "\n", "print(globals().keys())\n", "```\n", "\n", "Тогда запуск файла `myscript.py` привет к чему-то похожему\n", "```sh\n", ">>> python myscript.py\n", "Начало импортирования модуля mymodule.py \n", "dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', 'x'])\n", "Конец импортирования модуля mymodule.py \n", "dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'mymodule', 'y'])\n", "\n", ">>> \n", "```\n", "\n", "Можно заметить, что глобальные пространства имён не только имёют уникальные друг для друга переменные `x` и `y`, но имеются и некоторые другие отличия, связанные с тем, что `myscript.py` запущен непосредственно, а `mymodyle.py` загружается при импортировании.\n", "\n", "## Модуль и скрипт\n", "\n", "Чтобы выяснить, запущен ли данный файл непосредственно или импортирован в другом файле используется выражение `__name__ == \"__main__\"`. Такой подход основывается на том, что python автоматически создаёт имя \"\\_\\_name\\_\\_\" в глобально пространстве имен каждого модуля и скрипта в момент начала их обработки, и связывает это имя с строкой \"\\_\\_main\\_\\_\", если файл запущен в качестве скрипта и с именем файла (за исключением расширения `.py`), если файл запускается при импортировании. \n", "\n", "Продемонстрируем это на следующих файлах\n", "\n", "Файл `mymodule.py`.\n", "```python\n", "print(\"Начало импортирования модуля mymodule.py\")\n", "\n", "print(__name__)\n", "\n", "if __name__ == \"__main__\":\n", " print(\"Я был непосредственно запущен\")\n", "\n", "print(\"Конец импортирования модуля mymodule.py\")\n", "```\n", "\n", "Файл `myscript.py`\n", "```python\n", "import mymodule \n", "\n", "print(__name__)\n", "\n", "if __name__ == \"__main__\":\n", " print(\"Я был непосредственно запущен\")\n", "```\n", "\n", "Тогда запуск файла `myscript.py` привет к чему-то похожему\n", "```sh\n", ">>> python myscript.py\n", "Начало импортирования модуля mymodule.py\n", "mymodule\n", "Конец импортирования модуля mymodule.py\n", "__main__ Я был непосредственно запущен\n", "\n", ">>> \n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "language_info": { "name": "python" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }