Управляющие конструкции
This content is not available in your language yet.
Самая «питоновская» глава раздела: почти всё переносится дословно. Поэтому сосредоточимся на трёх вещах, которые всё-таки отличаются, — и на одной, которой в Mojo пока нет вовсе.
Ветвление
Заголовок раздела «Ветвление»def main(): var temperature = 25
if temperature > 30: print("жарко") elif temperature > 20: print("тепло") else: print("прохладно")
print("одеваться:", "легко" if temperature > 20 else "тепло")тепло одеваться: легко
if / elif / else и тернарный оператор — без единого отличия от Python.
Чего нет: match
Заголовок раздела «Чего нет: match»Если вы привыкли к сопоставлению с образцом из Python 3.10, придётся обойтись без него:
error: unexpected token in expression
Конструкция match / case в Mojo 1.0 не поддерживается — компилятор
не знает такого ключевого слова и спотыкается на нём как на обычном
выражении.
Пишите цепочку if / elif / else. Для разбора по типам в Mojo есть
более мощный инструмент — перегрузка функций,
которая решает задачу на этапе компиляции.
while и for ... in работают привычно, range принимает те же три
формы, включая отрицательный шаг:
def main(): for i in range(10, 0, -3): print(i, end=" ") print()10 7 4 1
Есть и редкая питоновская конструкция for ... else — блок else
выполняется, если цикл завершился без break. Работает она и с while.
Перебор коллекций
Заголовок раздела «Перебор коллекций»enumerate и zip на месте:
def main(): var cities: List[String] = ["Москва", "Казань"] var population: List[Int] = [13, 1]
for index, city in enumerate(cities): print(index, city)
for pair in zip(cities, population): print(pair[0], "—", pair[1], "млн")0 Москва 1 Казань Москва — 13 млн Казань — 1 млн
Обратите внимание на разницу: enumerate даёт распаковку в две переменные,
а элементы zip приходят кортежем, к которому обращаются по индексу.
Есть и reversed для обхода в обратном порядке.
Изменение элементов прямо в цикле
Заголовок раздела «Изменение элементов прямо в цикле»А вот это отличается от Python по существу. В Python переменная цикла —
копия ссылки на элемент, и присваивание ей ничего не меняет в списке.
В Mojo можно получить ссылку на элемент через ref:
for i in range(len(numbers)): numbers[i] *= 10for ref value in numbers: value *= 10Вариант с индексами тоже работает, но ref читается лучше и не даёт
ошибиться с границами. Без ref переменная цикла — копия, и умножение
ничего не изменит в списке.
Перебор словаря
Заголовок раздела «Перебор словаря»Здесь Mojo честнее Python. Обращение по ключу может не найти значение, поэтому оно способно бросить исключение:
error: cannot call function that may raise in a context that cannot raise
Вы написали codes[city] внутри обычной функции. Обращение к словарю
по ключу — операция, которая может завершиться ошибкой, если ключа нет.
Либо пометьте функцию как raises, либо перебирайте пары через
.items() — тогда ключ и значение приходят сразу, и обращаться
по ключу не нужно.
def main(): var codes = Dict[String, Int]() codes["Москва"] = 495 codes["Казань"] = 843
for item in codes.items(): print(item.key, item.value)Москва 495 Казань 843
Отдельно доступны .keys() и .values(), а for city in codes перебирает
ключи — как в Python.
Всё вместе
Заголовок раздела «Всё вместе»def main(): # Ветвление и тернарный оператор var temperature = 25 if temperature > 30: print("жарко") elif temperature > 20: print("тепло") else: print("прохладно")
print("одеваться:", "легко" if temperature > 20 else "тепло")
# range: с началом, концом и шагом, в том числе отрицательным for i in range(10, 0, -3): print(i, end=" ") print()
# Перебор списка вместе с индексом var cities: List[String] = ["Москва", "Казань", "Томск"] for index, city in enumerate(cities): print(index, city)
# Два списка параллельно var population: List[Int] = [13, 1, 0] for pair in zip(cities, population): print(pair[0], "—", pair[1], "млн")
# Изменение элементов прямо в цикле: ref даёт ссылку на элемент var numbers: List[Int] = [1, 2, 3] for ref value in numbers: value *= 10 print("после умножения:", numbers[0], numbers[1], numbers[2])
# break и continue var sum = 0 for value in range(1, 10): if value % 2 == 0: continue if value > 7: break sum += value print("сумма нечётных до 7:", sum)
# У циклов есть else — он срабатывает, если не было break for value in range(2): print("шаг", value) else: print("цикл дошёл до конца")
# Перебор словаря: items() даёт сразу ключ и значение var codes = Dict[String, Int]() codes["Москва"] = 495 codes["Казань"] = 843 for item in codes.items(): print(item.key, item.value)тепло одеваться: легко 10 7 4 1 0 Москва 1 Казань 2 Томск Москва — 13 млн Казань — 1 млн Томск — 0 млн после умножения: 10 20 30 сумма нечётных до 7: 16 шаг 0 шаг 1 цикл дошёл до конца Москва 495 Казань 843
Полезные встроенные функции
Заголовок раздела «Полезные встроенные функции»Проверено на Mojo 1.0: len, abs, min, max, round, pow, sort,
enumerate, zip, reversed, range — на месте. Есть и any с all,
но принимают они коллекцию, а не отдельное значение:
def main(): var flags: List[Bool] = [True, False] print(any(flags), all(flags))True False
А вот привычного sum в языке нет. Сумму списка считают циклом:
def main(): var values: List[Int] = [3, 1, 2] var total = 0 for value in values: total += value print(total)6
🎯 Проверь себя
Как изменить элементы списка прямо в цикле?
Через for ref value in numbers: — тогда переменная цикла становится
ссылкой на элемент, и value *= 10 меняет сам список. Без ref
это копия, и изменения пропадут.
Почему `for city in codes: print(codes[city])` не компилируется?
Обращение к словарю по ключу может бросить исключение, если ключа нет.
Значит, вызывающая функция должна быть помечена raises — либо нужно
перебирать .items(), где ключ и значение приходят вместе.
Чем заменить `match` из Python 3.10?
Цепочкой if / elif / else: конструкции match в Mojo 1.0 нет.
Если разбор идёт по типам, а не по значениям, лучше подойдёт перегрузка
функций — она разрешается на этапе компиляции.
Что дальше
Заголовок раздела «Что дальше»Обработка ошибок: raises, try / except
и контекстные менеджеры.
Тексты курса — CC BY-NC-SA 4.0, код примеров — Apache 2.0