Модули и пакеты¶
Mojo предоставляет систему упаковки, которая позволяет вам организовывать и компилировать библиотеки кода в импортируемые файлы. На этой странице представлены необходимые понятия о том, как организовать ваш код в модули и пакеты (что во многом похоже на Python), и показано, как создать упакованный двоичный файл с помощью команды `mojo package.
Модули Mojo¶
Чтобы разобраться в пакетах Mojo, вам сначала нужно разобраться в модулях Mojo. Модуль Mojo - это отдельный исходный файл Mojo, содержащий код, пригодный для использования другими файлами, которые его импортируют. Например, вы можете создать модуль для определения структуры, подобной этой:
mymodule.mojo:
struct MyPair:
var first: Int
var second: Int
fn __init__(out self, first: Int, second: Int):
self.first = first
self.second = second
fn dump(self):
print(self.first, self.second)
Обратите внимание, что в этом коде нет функции main(), поэтому вы не можете выполнить mymodule.mojo. Однако вы можете импортировать это в другой файл с помощью функции main() и использовать ее там.
Например, вот как вы можете импортировать MyPair в файл с именем main.mojo, который находится в том же каталоге, что и mymodule.mojo:
main.mojo:
from mymodule import MyPair
fn main():
var mine = MyPair(2, 4)
mine.dump()
В качестве альтернативы вы можете импортировать весь модуль целиком, а затем получить доступ к его элементам по имени модуля. Например:
main.mojo:
import mymodule
fn main():
var mine = mymodule.MyPair(2, 4)
mine.dump()
Вы также можете создать псевдоним для импортированного элемента с помощью as, например, следующим образом:
main.mojo:
import mymodule as my
fn main():
var mine = my.MyPair(2, 4)
mine.dump()
В этом примере это работает только тогда, когда mymodule.mojo находится в том же каталоге, что и main.mojo. В настоящее время вы не можете импортировать файлы .mojo в качестве модулей, если они находятся в других каталогах. То есть, если только вы не рассматриваете каталог как пакет Mojo, как описано в следующем разделе.
Модуль Mojo может включать в себя функцию
main()и также может быть исполняемым, но обычно это не практикуется, и модули обычно включают API, которые можно импортировать и использовать в других программах Mojo.
Пакеты Mojo¶
Пакет Mojo - это просто набор модулей Mojo в каталоге, который содержит файл __init__.mojo. Объединив модули в каталоге, вы можете импортировать все модули вместе или по отдельности. При желании вы также можете скомпилировать пакет в файл .mojopkg или .📦, который проще использовать совместно и который по-прежнему совместим с другими системными архитектурами.
Вы можете импортировать пакет и его модули либо непосредственно из исходных файлов, либо из скомпилированного файла .mojopkg/.📦. Для Mojo не имеет особого значения, каким способом вы импортируете пакет. При импорте из исходных файлов имя каталога используется как имя пакета, тогда как при импорте из скомпилированного пакета именем файла является имя пакета (которое вы указываете с помощью команды mojo package — оно может отличаться от имени каталога).
Например, рассмотрим проект с этими файлами:
main.mojo:
mypackage/
__init__.mojo
mymodule.mojo
mymodule.mojo - это тот же код, что и в примерах выше (со структурой MyPair), а __init__.mojo пуст.
Файл
__init__.mojoнеобходим. Если у вас его нет, Mojo не распознает каталог как пакет, и вы не сможете импортироватьmymodule.
В этом случае основной файл main.mojo теперь может импортировать MyPair через имя пакета следующим образом:
main.mojo:
from mypackage.mymodule import MyPair
fn main():
var mine = MyPair(2, 4)
mine.dump()
This immediately works:
mojo main.mojo
2 4
Однако, если вы не хотите, чтобы исходный код mypackage находился в том же месте, что и main.mojo, вы можете скомпилировать его в файл пакета, подобный этому:
mojo package mypackage -o mypack.mojopkg
Файл
.mojopkgсодержит незавершенный код, поэтому вы можете использовать его совместно в разных системах. Код становится исполняемым файлом, зависящим от архитектуры, только после того, как он импортируется в программу Mojo, которая затем компилируется с помощьюmojo build.
Теперь вы можете переместить исходный код mypackage в другое место, и файлы проекта теперь будут выглядеть следующим образом:
main.mojo
mypack.mojopkg
Поскольку мы назвали пакет mypack, нам нужно исправить инструкцию import:
main.mojo:
from mypack.mymodule import MyPair
И код работает точно так же:
mojo main.mojo
2 4
Если вы хотите переименовать свой пакет, вы не можете просто отредактировать имя файла
.mojopkgили.📦, поскольку имя пакета закодировано в файле. Вместо этого вы должны снова запустить mojo package, чтобы указать новое имя.
__init__ файл¶
Как упоминалось выше, файл __init__.mojo необходим для указания того, что каталог следует рассматривать как пакет Mojo, и он может быть пустым.
В настоящее время в файлах .mojo не поддерживается код верхнего уровня, поэтому, в отличие от Python, вы не можете написать код в __init__.mojo, который выполняется при импорте. Однако вы можете добавить структуры и функции, которые затем можно импортировать из имени пакета.
Однако, вместо добавления API-интерфейсов в файл __init__.mojo, вы можете импортировать элементы модуля, что дает тот же эффект, делая ваши API-интерфейсы доступными из имени пакета, вместо того, чтобы требовать обозначения <package_name>.<module_name>.
Например, опять же, предположим, что у вас есть эти файлы:
main.mojo:
mypackage/
__init__.mojo
mymodule.mojo
Давайте теперь добавим следующую строку в __init__.mojo:
__init__.mojo
from .mymodule import MyPair
Это все, что там есть. Теперь мы можем упростить инструкцию import в main.mojo следующим образом:
main.mojo:
from mypackage import MyPair
Эта функция объясняет, почему некоторые элементы стандартной библиотеки Mojo могут быть импортированы из их имени пакета, в то время как для других требуется обозначение <package_name>.<module_name>. Например, функциональный модуль находится в пакете algorithm, поэтому вы можете импортировать элементы этого модуля (например, функцию map()) следующим образом:
from algorithm.functional import map
Однако файл algorithm/__init__.mojo также содержит эти строки:
algorithm/__init__.mojo
from .functional import *
from .reduction import *
Таким образом, вы действительно можете импортировать что угодно из functional или reduction, просто присвоив пакету имя. То есть вы можете удалить название функции из инструкции import, и это также работает:
from algorithm import map
Какие модули из стандартной библиотеки импортируются в область действия пакета, зависит от области применения и может быть изменено. Обратитесь к документации по каждому модулю, чтобы узнать, как можно импортировать его элементы.