Как разделить код на несколько файлов Python

Обновлено: 21.11.2024

На предыдущем уроке мы анализировали значения из выходных файлов. Хотя вы, возможно, видели полезность такой вещи, вы также могли задаться вопросом, почему мы просто не искали файл, вырезали и вставляли нужные значения в электронную таблицу. Если у вас есть только 1 или 2 файла, это может быть очень разумным решением. Но что, если бы вам нужно было проанализировать 100 файлов? А если бы у вас было 1000? В таком случае метод вырезания и вставки будет очень утомительным и трудоемким.

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

Для анализа нескольких файлов нам потребуется импортировать библиотеку Python. Библиотека — это набор модулей, содержащих функции. Функции внутри библиотеки или модуля обычно связаны друг с другом. Использование библиотек и Python уменьшает объем кода, который вам нужно написать. На прошлом уроке мы импортировали os.path — модуль, обрабатывающий для нас пути к файлам.

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

Мы собираемся импортировать две библиотеки. Одной из них является библиотека os, которая управляет функциями, связанными с операционной системой вашего компьютера. Мы использовали эту библиотеку в прошлом уроке для обработки путей к файлам. Другая — это библиотека glob, которая содержит функции, помогающие нам анализировать несколько файлов. Если мы собираемся анализировать несколько файлов, нам сначала нужно указать, где эти файлы расположены.

Упражнение

Как бы вы использовали модуль os.path, чтобы указать каталог, в котором находятся ваши выходные файлы?

Решение

Чтобы получить все файлы, соответствующие определенному шаблону, мы будем использовать подстановочный знак * .

Приносят ли вам радость ваши функции Python? Лукас Реслер делится своими советами о том, как разделить функции Python на несколько модулей, чтобы помочь развитию вашего проекта

Как основной участник OpenFaaS, вы найдете меня в OpenFaaS Slack, где я всегда готов помочь новым пользователям и участникам. Вы можете присоединиться к сообществу здесь. Этот пост был вдохновлен вопросом от нового пользователя, который только что присоединился к сообществу. Он спросил:

"Как написать на Python функцию, использующую несколько исходных файлов, чтобы основной файл handler.py мог импортировать вспомогательные функции из отдельных исходных файлов".

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

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

Сегодня я покажу, как это сделать в OpenFaaS, создав функцию подсчета слов Python 3, разделенную на несколько файлов.

У вас должны быть базовые знания OpenFaaS и Python, но если вы новичок, вы можете ускориться, используя семинар. Я хочу сосредоточиться на том, как превратить «однострочную» функцию в более крупный многомодульный проект.

Запустить функцию

Далее, чтобы запустить новую функцию Python 3, я предпочитаю использовать шаблон flask, потому что я собираюсь загрузить в память статический список «стоп-слов» при запуске функции. Использование шаблонов фляг позволяет функции делать это только один раз, а не при каждом вызове.

Введите логин в docker

Измените --prefix на свою учетную запись Docker Hub или личный реестр

Теперь подключите шаблон python3-flask и создайте новую функцию с именем wordcount

Теперь проект должен выглядеть так

Относительный импорт

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

Начнем с создания еще двух файлов:

Теперь проект должен выглядеть так

Стоп-слова — это обычный текстовый файл со словами, которые будут исключены из подсчета слов. Это короткие общеупотребительные слова, которые вы не хотели бы включать в визуализацию подсчета слов, например:

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

Весь код для обработки текста и создания счетчиков находится в wordcount.py:

Обратите внимание, что обработка STOPWORDS в начале файла означает, что он будет загружаться в память сразу после импорта пакета, а не при каждом запросе, что приведет к дополнительной задержке и накладным расходам ввода-вывода.

Используя относительный импорт, мы можем очень легко использовать метод process_text для создания очень простого handler.py:

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

Развернуть и протестировать функцию

У вас должен быть развернут OpenFaaS и уже запущен faas-cli для входа.

Примечание об использовании Python 2

Используя пакет __future__, вы можете получить такое же поведение в своих функциях Python 2. Добавьте from __future__ import absolute_import в качестве первого импорта в handler.py и wordcount.py, чтобы обеспечить правильное разрешение относительного импорта.

Обратите внимание, что в этом году срок службы Python 2 истекает, и после 2020 г. выпуски с исправлениями ошибок не будут выпускаться. Если вы все еще переходите на Python 3, используйте пакет __future__, чтобы упростить переход.

Подведение итогов

Когда мы используем относительный импорт, мы можем легко разделить наш код на несколько файлов для лучшей организации. Мы могли бы пойти дальше и импортировать из подпапок или подпапок подпапок. Дополнительным преимуществом этого является то, что код действителен как в вашей локальной среде, так и в конечном контейнере Docker. Попробуйте готовый пример кода в этом репозитории.

Ознакомьтесь с OpenFaas Workshop для получения пошагового руководства по написанию и развертыванию функции Python с подробным описанием других функций OpenFaas: асинхронных функций, тайм-аутов, автоматического масштабирования и управления секретными значениями.

Если у вас есть вопросы, комментарии и предложения, следите за нами в Твиттере @openfaas и присоединяйтесь к сообществу Slack.

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

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

Это особенно полезно, когда ваши программы становятся больше и сложнее.

Одна программа, два файла

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

arithmetic.py на вкладке Тонни.

use_arithmetic.py на вкладке Тонни.

арифметика.py

def subtract_numbers(число1, число2):
print(' - = '.format(число1, число2, число1 - число2))

use_arithmetic.py

число1 = 1,5
число2 = 6,3

arithmetic.add_numbers(число1, число2)
arithmetic.subtract_numbers(число1, число2)

арифметика.py

Первый файл называется "arithmetic.py" и содержит две функции.

Первый — это add_numbers, который получает два числовых параметра, добавляет их и выводит результат в оболочку.

Вторая функция называется "subtract_numbers". Эта функция также получает два параметра, вычитает их и выводит результат в оболочку.

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

use_arithmetic.py

Второй файл называется "use_arithmetic.py".

В первой строке мы используем ключевое слово import для импорта содержимого файла «arithmetic.py». С помощью этого импорта мы теперь можем использовать две функции, определенные в arithmetic.py, без необходимости их повторного написания.

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

Чтобы импортировать модуль, мы используем ключевое слово import, за которым следует имя файла, содержащего код, который мы хотим импортировать, без расширения ".py".

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

Наконец, я вызываю функции вычисления, существующие в арифметическом модуле, для выполнения сложения и вычитания между этими числами.

Выполнить программу

Чтобы запустить любую программу MicroPython в Thonny, просто нажмите кнопку воспроизведения.

Моя модульная программа выполнена. Вывод находится в оболочке.

Зачем разделять программу?

Файлы в этом примере очень маленькие. Но представьте, что ваши программы становятся все больше и больше по мере того, как вы совершенствуетесь в языке. Возможность разделить их на несколько файлов делает программы более эффективными, более простыми в управлении, более легкими для изменения и более легкими для совместного использования. Каждый файл может быть посвящен одной задаче или набору тесно связанных задач.

У меня есть длинный скрипт на Python, сейчас он содержит более 1000 строк и продолжает расти. Я подумал, было бы разумно начать разбивать эту большую программу на более мелкие файлы Python. У меня два вопроса:

1) увеличит ли это время, необходимое для запуска скрипта. Допустим, ему нужно было загрузить 10 отдельных скриптов Python.

2) как вы это делаете? Может ли кто-нибудь объяснить это на простом примере?

Джастин Исраэль

У меня есть длинный скрипт на Python, сейчас он содержит более 1000 строк и продолжает расти. Я подумал, было бы разумно начать разбивать эту большую программу на более мелкие файлы Python. У меня два вопроса:

1) увеличит ли это время, необходимое для запуска скрипта. Допустим, ему нужно было загрузить 10 отдельных скриптов Python.

С технической точки зрения было бы неверно утверждать, что это не добавило хотя бы какой-то дополнительной работы, поскольку при первом импорте Python должен был бы выполнять больше операций с файловой системой. Но это не то, о чем вам действительно следует беспокоиться с точки зрения структурирования вашего приложения. Тем более, что все они будут находиться в одном и том же PYTHONPATH, и вы выиграете от кэширования файловой системы.


2) как вы это делаете?, может ли кто-нибудь объяснить это на простом примере?

Дело не в том, чтобы начать писать сценарий и сказать: «Ну, я набрал 1000 строк, так что пора разделяться!». На чем вам, вероятно, следует сосредоточиться, так это на объединении общей функциональности в модули. Это позволит вам продолжать выполнять связанную работу внутри данного модуля, а не переключаться между логикой, которая просто разделена ради ее разделения. Кроме того, это способствует повторному использованию, потому что у вас могут быть некоторые интересные операции, которые могут быть импортированы каким-либо другим приложением, без необходимости зависимостей, которые могут потребоваться некоторым другим вашим модулям. Допустим, вам требуется определенная библиотека графического интерфейса в части вашего приложения, но у вас также есть куча отличной логики разбора файлов. Если бы вы сохранили их оба в одном модуле, другие приложения зависели бы от наличия доступной библиотеки графического интерфейса даже для импорта кода для анализа файла. И они могут быть совершенно не связаны.

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

Джо Вайденбах

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

Второй частью системы импорта являются пакеты, которые представляют собой папку модулей, содержащую специальный файл с именем __init__.py. Этот файл может не иметь содержимого, и все это будет работать как единый модуль. Если вам нужен специальный контент в __init__.py, вы можете поместить его, и этот код будет выполняться при импорте пакета. Я лично использую эту функциональность, чтобы явно показать классы, которые я намереваюсь использовать вне пакета. Главное, что нужно помнить о пакете, это то, что с точки зрения Python все это в основном представляет собой один загруженный модуль. Помня об этом, пакеты также должны быть самодостаточными.

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

Возьмите, к примеру, C++. В C++ я могу создать два класса, которые зависят друг от друга. Хороший дизайн? Скорее всего нет. Я окружаю заголовки защитой компиляции, чтобы убедиться, что каждый из них загружается в память только один раз, и я готов к работе.Это не значит, что у меня хороший дизайн, и у меня, вероятно, будут головные боли в будущем, когда я попытаюсь поддерживать это как большой проект, но он, вероятно, скомпилируется и запустится, что на стадии прототипа — это все, что мне нужно.

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

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

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

Причина, по которой я показываю это, заключается в том, что это уровень мысли, который вы должны вложить, когда начинаете разбивать сложные проекты. Я одержим чистым, легко читаемым, поддерживаемым кодом, поэтому, как я уже упоминал ранее, мне нравится разбивать его на части. Но, когда вы делаете это, это приводит к сложности, которая не имеет тенденции поднимать свою уродливую голову в однофайловых программах. С учетом сказанного, этот проект имеет сложность, которой у вас может не быть — это гибкая среда разработки с автоматическим монтажом, которая поддерживает динамические модули и абстрагируется от многих технических аспектов процесса монтажа. В настоящее время он содержит около 15 000 строк кода в 40–50 файлах, и я ожидаю, что когда я «закончу» с ним, это будет ближе к 30–40 000 строк кода. Короче говоря, это огромный проект для одного человека.

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

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

Читайте также: