Как создать модуль с функциями
Перейти к содержимому

Как создать модуль с функциями

Модули

Встроенные в язык программирования функции доступны сразу. Чтобы их вызвать, не надо выполнять никаких дополнительных действий. Однако за время существования любого популярного языка на нем было написано столько функций и классов, которые оказались востребованными множеством программистов и в разных областях, что включить весь этот объем кода в сам язык если возможно, то нецелесообразно.

Чтобы разрешить проблему доступа к дополнительным возможностям языка, в программировании стало общепринятой практикой использовать так называемые модули, пакеты и библиотеки. Каждый модуль содержит коллекцию функций и классов, предназначенных для решения задач из определенной области. Так в модуле math языка Python содержатся математические функции, модуль random позволяет генерировать псевдослучайные числа, в модуле datetime содержатся классы для работы с датами и временем, модуль sys предоставляет доступ к системным переменным и т. д.

Количество модулей для языка Python огромно, что связано с популярностью языка. Часть модулей собрана в так называемую стандартную библиотеку. Стандартная она потому, что поставляется вместе с установочным пакетом. Однако существуют сторонние библиотеки. Они скачиваются и устанавливаются отдельно.

Для доступа к функционалу модуля, его надо импортировать в программу. После импорта интерпретатор «знает» о существовании дополнительных классов и функций и позволяет ими пользоваться.

В Питоне импорт осуществляется командой import . При этом существует несколько способов импорта. Рассмотрим работу с модулем на примере math . Итак,

Ничего не произошло. Однако в глобальной области видимости появилось имя math . Если до импорта вы упомянули бы имя math , то возникла бы ошибка NameError . Теперь же

В программе завелся объект math , относящийся к классу module .

Чтобы увидеть перечень функций, входящих в этот модуль, воспользуемся встроенной в Python функцией dir() , передав ей в качестве аргумента имя модуля:

Проигнорируем имена с двойными подчеркиваниями. Все остальное – имена функций и констант (переменных, которые не меняют своих значений), включенных в модуль math. Чтобы вызвать функцию из модуля, надо впереди написать имя модуля, поставить точку, далее указать имя функции, после чего в скобках передать аргументы, если они требуются. Например, чтобы вызвать функцию pow из math, надо написать так:

Обратите внимание, эта другая функция pow() , не та, что встроена в сам язык. «Обычная» функция pow() возвращает целое, если аргументы целые числа:

Для обращения к константе скобки не нужны:

Если мы не знаем, что делает та или иная функция, то можем получить справочную информацию о ней с помощью встроенной в язык Python функции help() :

Для выхода из интерактивной справки надо нажать клавишу q. В данном случае сообщается, что функция возвращает целое число, и это наибольший общий делитель для чисел x и y . Описание модулей и их содержания также можно посмотреть в официальной документации на сайте python.org.

Второй способ импорта – это когда импортируется не сам модуль, а только необходимые функции из него.

Перевести можно как «из модуля math импортировать функции gcd , sqrt и hypot «.

В таком случае при их вызове не надо перед именем функции указывать имя модуля:

Чтобы импортировать сразу все функции из модуля:

Импорт через from не лишен недостатка. В программе уже может быть идентификатор с таким же именем, как имя одной из импортируемых функций или констант. Ошибки не будет, но одно из них окажется «затерто»:

Здесь исчезает значение 3.14, присвоенное переменной pi . Это имя теперь указывает на число из модуля math . Если импорт сделать раньше, чем присвоение значения pi , то будет все наоборот:

В этой связи более опасен именно импорт всех функций. Так как в этом случае очень легко не заметить подмены значений идентификаторов.

Однако можно изменить имя идентификатора из модуля на какое угодно:

В данном случае константа pi из модуля импортируется под именем P . Смысл подобных импортов в сокращении имен, так как есть модули с длинными именами, а имена функций и классов в них еще длиннее. Если в программу импортируется всего пара сущностей, и они используются в ней часто, то имеет смысл переименовать их на более короткий вариант. Сравните:

Во всех остальных случаях лучше оставлять идентификаторы содержимого модуля в пространстве имен самого модуля и получать доступ к ним через имя модуля, то есть выполнять импорт командой import имя_модуля , а вызывать, например, функции через имя_модуля.имя_функции() .

Практическая работа. Создание собственного модуля

Программист на Python всегда может создать собственный модуль, чтобы использовать его в нескольких своих программах или даже предоставить в пользование всему миру. В качестве тренировки создадим модуль с функциями для вычисления площадей прямоугольника, треугольника и круга:

Здесь также иллюстрируется принцип, что один модуль может импортировать другие. В данном случае импортируются функции из модуля math .

Поместите данный код в отдельный файл square.py . Однако куда поместить сам файл?

Когда интерпретатор Питона встречает команду импорта, то просматривает на наличие файла-модуля определенные каталоги. Их перечень можно увидеть по содержимому sys.path :

Это список адресов в Linux. В Windows он будет несколько другим. Первый элемент – пустая строка, что обозначает текущий каталог, то есть то место, где сохранена сама программа, импортирующая модуль. Если вы сохраните файл-модуль и файл-программу в одном каталоге, то интерпретатор без труда найдет модуль.

Также модуль можно положить в любой другой из указанных в списке каталогов. Тогда он будет доступен для всех программ на Python, а также его можно будет импортировать в интерактивном режиме.

Можно добавить в sys.path свой каталог. Однако в этом случае либо код программы должен содержать команды изменения значения sys.path , либо надо править конфигурационный файл операционной системы. В большинстве случаев лучше так не делать.

Поместите файл square.py в тот же каталог, где будет исполняемая программа. Ее код должен включать инструкцию импорта модуля square (при импорте расширение файла не указывается) и вызов той функции и с теми параметрами, которые ввел пользователь. То есть у пользователя надо спросить, площадь какой фигуры он хочет вычислить. Далее запросить у него аргументы для соответствующей функции. Передать их в функцию из модуля square , а полученный оттуда результат вывести на экран.

Примечание. Исполнение модуля как самостоятельного скрипта, а также создание строк документации, которые отображает встроенная в Python функция help() , будут рассмотрены в курсе объектно-ориентированного программирования.

Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса

Модули, введение

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

Долгое время в JavaScript отсутствовал синтаксис модулей на уровне языка. Это не было проблемой, потому что первые скрипты были маленькими и простыми. В модулях не было необходимости.

Но со временем скрипты становились всё более и более сложными, поэтому сообщество придумало несколько вариантов организации кода в модули. Появились библиотеки для динамической подгрузки модулей.

    – одна из самых старых модульных систем, изначально реализована библиотекой require.js. – модульная система, созданная для сервера Node.js. – ещё одна модульная система, предлагается как универсальная, совместима с AMD и CommonJS.

Теперь все они постепенно становятся частью истории, хотя их и можно найти в старых скриптах.

Система модулей на уровне языка появилась в стандарте JavaScript в 2015 году и постепенно эволюционировала. На данный момент она поддерживается большинством браузеров и Node.js. Далее мы будем изучать именно её.

Что такое модуль?

Модуль – это просто файл. Один скрипт – это один модуль.

Модули могут загружать друг друга и использовать директивы export и import , чтобы обмениваться функциональностью, вызывать функции одного модуля из другого:

  • export отмечает переменные и функции, которые должны быть доступны вне текущего модуля.
  • import позволяет импортировать функциональность из других модулей.

Например, если у нас есть файл sayHi.js , который экспортирует функцию:

…Тогда другой файл может импортировать её и использовать:

Директива import загружает модуль по пути ./sayHi.js относительно текущего файла и записывает экспортированную функцию sayHi в соответствующую переменную.

Давайте запустим пример в браузере.

Так как модули поддерживают ряд специальных ключевых слов, и у них есть ряд особенностей, то необходимо явно сказать браузеру, что скрипт является модулем, при помощи атрибута <script type="module"> .

Браузер автоматически загрузит и запустит импортированный модуль (и те, которые он импортирует, если надо), а затем запустит скрипт.

Если вы попытаетесь открыть веб-страницу локально, через протокол file:// , вы обнаружите, что директивы import/export не работают. Для тестирования модулей используйте локальный веб-сервер, например, static-server или используйте возможности «живого сервера» вашего редактора, например, расширение Live Server для VS Code.

Основные возможности модулей

Чем отличаются модули от «обычных» скриптов?

Есть основные возможности и особенности, работающие как в браузере, так и в серверном JavaScript.

Всегда «use strict»

В модулях всегда используется режим use strict . Например, присваивание к необъявленной переменной вызовет ошибку.

Своя область видимости переменных

Каждый модуль имеет свою собственную область видимости. Другими словами, переменные и функции, объявленные в модуле, не видны в других скриптах.

В следующем примере импортированы 2 скрипта, и hello.js пытается использовать переменную user , объявленную в user.js . В итоге ошибка:

Модули должны экспортировать функциональность, предназначенную для использования извне. А другие модули могут её импортировать.

Так что нам надо импортировать user.js в hello.js и взять из него нужную функциональность, вместо того чтобы полагаться на глобальные переменные.

В браузере также существует независимая область видимости для каждого скрипта <script type="module"> :

Если нам нужно сделать глобальную переменную уровня всей страницы, можно явно присвоить её объекту window , тогда получить значение переменной можно обратившись к window.user . Но это должно быть исключением, требующим веской причины.

Код в модуле выполняется только один раз при импорте

Если один и тот же модуль используется в нескольких местах, то его код выполнится только один раз, после чего экспортируемая функциональность передаётся всем импортёрам.

Это очень важно для понимания работы модулей. Давайте посмотрим примеры.

Во-первых, если при запуске модуля возникают побочные эффекты, например выдаётся сообщение, то импорт модуля в нескольких местах покажет его только один раз – при первом импорте:

На практике, задача кода модуля – это обычно инициализация, создание внутренних структур данных, а если мы хотим, чтобы что-то можно было использовать много раз, то экспортируем это.

Теперь более продвинутый пример.

Давайте представим, что модуль экспортирует объект:

Если модуль импортируется в нескольких файлах, то код модуля будет выполнен только один раз, объект admin будет создан и в дальнейшем будет передан всем импортёрам.

Все импортёры получат один-единственный объект admin :

Ещё раз заметим – модуль выполняется только один раз. Генерируется экспорт и после передаётся всем импортёрам, поэтому, если что-то изменится в объекте admin , то другие модули тоже увидят эти изменения.

Такое поведение позволяет конфигурировать модули при первом импорте. Мы можем установить его свойства один раз, и в дальнейших импортах он будет уже настроенным.

Например, модуль admin.js предоставляет определённую функциональность, но ожидает передачи учётных данных в объект admin извне:

В init.js , первом скрипте нашего приложения, мы установим admin.name . Тогда все это увидят, включая вызовы, сделанные из самого admin.js :

Другой модуль тоже увидит admin.name :

import.meta

Объект import.meta содержит информацию о текущем модуле.

Содержимое зависит от окружения. В браузере он содержит ссылку на скрипт или ссылку на текущую веб-страницу, если модуль встроен в HTML:

В модуле «this» не определён

Это незначительная особенность, но для полноты картины нам нужно упомянуть об этом.

В модуле на верхнем уровне this не определён (undefined).

Сравним с не-модульными скриптами, там this – глобальный объект:

Особенности в браузерах

Есть и несколько других, именно браузерных особенностей скриптов с type="module" по сравнению с обычными скриптами.

Если вы читаете материал в первый раз или, если не собираетесь использовать модули в браузерах, то сейчас можете пропустить эту секцию.

Модули являются отложенными (deferred)

Модули всегда выполняются в отложенном (deferred) режиме, точно так же, как скрипты с атрибутом defer (описан в главе Скрипты: async, defer). Это верно и для внешних и встроенных скриптов-модулей.

  • загрузка внешних модулей, таких как <script type="module" src=". "> , не блокирует обработку HTML.
  • модули, даже если загрузились быстро, ожидают полной загрузки HTML документа, и только затем выполняются.
  • сохраняется относительный порядок скриптов: скрипты, которые идут раньше в документе, выполняются раньше.

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

Пожалуйста, обратите внимание: второй скрипт выполнится раньше, чем первый! Поэтому мы увидим сначала undefined , а потом object .

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

При использовании модулей нам стоит иметь в виду, что HTML-страница будет показана браузером до того, как выполнятся модули и JavaScript-приложение будет готово к работе. Некоторые функции могут ещё не работать. Нам следует разместить «индикатор загрузки» или что-то ещё, чтобы не смутить этим посетителя.

Атрибут async работает во встроенных скриптах

Для не-модульных скриптов атрибут async работает только на внешних скриптах. Скрипты с ним запускаются сразу по готовности, они не ждут другие скрипты или HTML-документ.

Для модулей атрибут async работает на любых скриптах.

Например, в скрипте ниже есть async , поэтому он выполнится сразу после загрузки, не ожидая других скриптов.

Скрипт выполнит импорт (загрузит ./analytics.js ) и сразу запустится, когда будет готов, даже если HTML документ ещё не будет загружен, или если другие скрипты ещё загружаются.

Это очень полезно, когда модуль ни с чем не связан, например для счётчиков, рекламы, обработчиков событий.

Внешние скрипты

Внешние скрипты с атрибутом type="module" имеют два отличия:

Внешние скрипты с одинаковым атрибутом src запускаются только один раз:

Внешний скрипт, который загружается с другого домена, требует указания заголовков CORS. Другими словами, если модульный скрипт загружается с другого домена, то удалённый сервер должен установить заголовок Access-Control-Allow-Origin означающий, что загрузка скрипта разрешена.

Это обеспечивает лучшую безопасность по умолчанию.

Не допускаются «голые» модули

В браузере import должен содержать относительный или абсолютный путь к модулю. Модули без пути называются «голыми» (bare). Они не разрешены в import .

Например, этот import неправильный:

Другие окружения, например Node.js, допускают использование «голых» модулей, без путей, так как в них есть свои правила, как работать с такими модулями и где их искать. Но браузеры пока не поддерживают «голые» модули.

Совместимость, «nomodule»

Старые браузеры не понимают атрибут type="module" . Скрипты с неизвестным атрибутом type просто игнорируются. Мы можем сделать для них «резервный» скрипт при помощи атрибута nomodule :

Инструменты сборки

В реальной жизни модули в браузерах редко используются в «сыром» виде. Обычно, мы объединяем модули вместе, используя специальный инструмент, например Webpack и после выкладываем код на рабочий сервер.

Одно из преимуществ использования сборщика – он предоставляет больший контроль над тем, как модули ищутся, позволяет использовать «голые» модули и многое другое «своё», например CSS/HTML-модули.

Сборщик делает следующее:

  1. Берёт «основной» модуль, который мы собираемся поместить в <script type="module"> в HTML.
  2. Анализирует зависимости (импорты, импорты импортов и так далее)
  3. Собирает один файл со всеми модулями (или несколько файлов, это можно настроить), перезаписывает встроенный import функцией импорта от сборщика, чтобы всё работало. «Специальные» типы модулей, такие как HTML/CSS тоже поддерживаются.
  4. В процессе могут происходить и другие трансформации и оптимизации кода:
    • Недостижимый код удаляется.
    • Неиспользуемые экспорты удаляются («tree-shaking»).
    • Специфические операторы для разработки, такие как console и debugger , удаляются.
    • Современный синтаксис JavaScript также может быть трансформирован в предыдущий стандарт, с похожей функциональностью, например, с помощью Babel.
    • Полученный файл можно минимизировать (удалить пробелы, заменить названия переменных на более короткие и т.д.).

Если мы используем инструменты сборки, то они объединяют модули вместе в один или несколько файлов, и заменяют import/export на свои вызовы. Поэтому итоговую сборку можно подключать и без атрибута type="module" , как обычный скрипт:

Хотя и «как есть» модули тоже можно использовать, а сборщик настроить позже при необходимости.

Итого

Подводя итог, основные понятия:

  1. Модуль – это файл. Чтобы работал import/export , нужно для браузеров указывать атрибут <script type="module"> . У модулей есть ряд особенностей:
    • Отложенное (deferred) выполнение по умолчанию.
    • Атрибут async работает во встроенных скриптах.
    • Для загрузки внешних модулей с другого источника, он должен ставить заголовки CORS.
    • Дублирующиеся внешние скрипты игнорируются.
  2. У модулей есть своя область видимости, обмениваться функциональностью можно через import/export .
  3. В модулях всегда включена директива use strict .
  4. Код в модулях выполняется только один раз. Экспортируемая функциональность создаётся один раз и передаётся всем импортёрам.

Когда мы используем модули, каждый модуль реализует свою функциональность и экспортирует её. Затем мы используем import , чтобы напрямую импортировать её туда, куда необходимо. Браузер загружает и анализирует скрипты автоматически.

В реальной жизни часто используется сборщик Webpack, чтобы объединить модули: для производительности и других «плюшек».

В следующей главе мы увидим больше примеров и вариантов импорта/экспорта.

№21 Модули Python / Уроки по Python для начинающих

Модуль — это файл, содержащий код python, который вы хотите включить в проект.

Документацию по модулям python на русском мы собрали в разделе Модули.

Создание модуля

Для того, чтобы создать модуль достаточно просто сохранить код в файл с расширением .py :
Сохраним этот код в файл под названием mymodule.py

Использование модуля

Теперь мы можем использовать только что созданный модуль, с помощью оператора import :

Импортируем модуль под названием mymodule, и вызовем функцию приветствия:

Примечание: Во время использования функции из модуля, синтаксис: module_name.function_name .

Переменные в модуле

Модуль может содержать функции, как уже описано, но также и переменные всех типов (массивы, словари, объекты и т. д.).
Сохраним этот код в файл mymodule.py

Импортируем модуль с названием mymodule, и получим доступ к словарю person1 :

Имя модуля

Вы можете назвать файл модуля, как вам нравится, но важно, указать расширение файла .py

Переименование модуля

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

Встроенные модули

В Python есть несколько встроенных модулей, которые вы можете импортировать, когда захотите.

Использование функции dir()

Существует встроенная функция для перечисления всех имен функций (или имен переменных) в модуле. Функция dir() .

Примечание: Функцию dir() можно использовать на всех модулях, включая те, которые вы создаете сами.

Импорт из модуля

Вы можете импортировать модуль только частично, используя ключевое слово from

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *