«Подождите, что?» — вот как, по моему мнению, большинство людей отреагирует на название этой статьи.
Что вы имеете в виду, говоря «Просто используйте браузерный Python»?
Все знают, что браузеры могут выполнять только JavaScript.
Ниже приведен скриншот исходного кода моего личного сайта, посмотрите, заметите ли вы что-то другое:
Да, это Python!
А теперь давайте поговорим о том, как это работает, насколько хорошо это работает, и какие еще альтернативы браузерному JS существуют.
Представляем Brython
Brython — это реализация Python3, написанная на JavaScript, которая позволяет писать Python-код для веб.
По сути, это библиотека JavaScript, которая преобразует ваш Python-код в эквивалентный JS и обрабатывает его во время выполнения.
И поскольку написание Python для браузера звучит довольно круто, я решил попробовать.
Создаем игру Змейка с помощью Brython
Вот ссылка на мой сайт, где вы можете попробовать как JavaScript, так и Brython Snake. А вот ссылка на весь код на GitHub.
Для того чтобы попробовать Brython в действии, я решил создать классическую игру «Змейка».
Поскольку я не специалист по HTML Canvas и не разработчик игр, я решил использовать эту реализацию JavaScript в качестве отправной точки. Я уже создавал свою собственную игру-змейку на холсте, но эта намного аккуратнее и компактнее.
О да, и этот парень создал ее менее чем за 5 минут. Спасибо Крису Делеону, это очень впечатляет.
Итак, в дополнение к реализации Криса я добавил функцию подсчета очков и результатов, немного улучшил интерфейс, добавил кнопку паузы и кнопку инструкций. Затем я портировал его на Brython.
На самом деле, я также изменил его код так, чтобы он работал в строгом режиме JS, поскольку он использовал такие вещи, как неявные глобалы, которые, как мне кажется, не являются репрезентативными для большинства JavaScript (не критикую его — он занимался скоростным кодированием), и я хотел получить хорошее сравнение кода Brython и JS.
В итоге JavaScript получился таким, и я не буду публиковать здесь этот фрагмент, потому что моя цель — сосредоточиться на Brython.
Хотя большая часть кода Brython была «прямым переводом» JS, некоторые части, например, функциональность подсчета очков, я создал непосредственно в Brython, а затем реализовал в JS, чтобы посмотреть, как это будет выглядеть.
Конечный результат таков:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Brython Snake</title> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/brython.min.js"> </script> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <style> /* Removed to keep the snippet short. Find the full file here: */ </style> </head> <body onload="brython()"> <h1 class="text-center">Snake built with <a href="https://brython.info">Python!</a></h1> <canvas id="game-board" width="400" height="400"></canvas> <br> <h3 id="score" class="text-center">Score: 0</h3> <br> <h6 id="high-score" class="text-center">High Score: 0</h6> <br> <div class="text-center"> <button id="instructions-btn" class="btn btn-info">Instructions</button> </div> <script type="text/python"> from browser import document, html, window from javascript import Math score = 0 high_score = 0 px = py = 10 gs = tc = 20 ax = ay = 15 xv = yv = 0 trail = [] tail = 5 pre_pause = [0,0] paused = False def game(): global px, py, tc, gs, ax, ay, trail, tail, score px += xv py += yv if px < 0: px = tc-1 if px > tc-1: px = 0 if py < 0: py = tc-1 if py > tc-1: py = 0 ctx.fillStyle = "black" ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = "lime" for i in range(len(trail)): ctx.fillRect(trail[i][0]*gs, trail[i][1]*gs, gs-2, gs-2) if trail[i][0] == px and trail[i][1] == py: score = score if paused else 0 tail = 5 trail.insert(0, [px, py]) while len(trail) > tail: trail.pop() if ax == px and ay == py: tail += 1 ax = Math.floor(Math.random()*tc) ay = Math.floor(Math.random()*tc) score += 1 update_score(score) ctx.fillStyle = "red" ctx.fillRect(ax*gs, ay*gs, gs-2, gs-2) def update_score(new_score): global high_score document["score"].innerHTML = "Score: " + str(new_score) if new_score > high_score: document["high-score"].innerHTML = "High Score: " + str(new_score) high_score = new_score def key_push(evt): global xv, yv, pre_pause, paused key = evt.keyCode if key == 37 and not paused: xv = -1 yv = 0 elif key == 38 and not paused: xv = 0 yv = -1 elif key == 39 and not paused: xv = 1 yv = 0 elif key == 40 and not paused: xv = 0 yv = 1 elif key == 32: temp = [xv, yv] xv = pre_pause[0] yv = pre_pause[1] pre_pause = [*temp] paused = not paused def show_instructions(evt): window.alert("Use the arrow keys to move and press spacebar to pause the game.") canvas = document["game-board"] ctx = canvas.getContext("2d") document.addEventListener("keydown", key_push) game_loop = window.setInterval(game, 1000/15) instructions_btn = document["instructions-btn"] instructions_btn.addEventListener("click", show_instructions) </script> </body> </html>
Итак, основываясь на этом фрагменте, давайте разберем некоторые ключевые понятия о Brython:
Включая brython.js
Для Brython не требуется установка. Просто импортируйте скрипт внутри <head> :
<script type=”text/javascript” src=”https://cdn.jsdelivr.net/npm/[email protected]/brython.min.js">
Запуск Brython
Для того, чтобы Brython мог транслировать и исполнять код на Python как обычный JS, нам нужно вызвать brython сразу после загрузки тела документа, как показано ниже:
<body onload=”brython()”>
Он будет искать теги сценариев типа text/python и оценивать код внутри них.
API для работы с Веб
По умолчанию JavaScript предоставляет вам доступ к таким объектам, как документ и окно, которые необходимы в любом проекте JS. Таким образом, Brython должен иметь способ включить и их.
Чтобы решить эту проблему, создатели Brython могли бы просто позволить разработчикам по умолчанию сразу обращаться к document и window в коде Python, но это заставило бы отладчики Python постоянно кричать о undefined variable и ухудшило бы производительность.
Таким образом, чтобы использовать эти Web API, мы должны импортировать их так же, как мы это делаем с любым модулем Python:
from browser import document, html, window
На самом деле, вам не нужно выполнять pip install
. В конце концов, мы вставляем это в наш HTML! Просто включите операторы импорта, и все в порядке — Brython будет знать, что делать.
Чтобы проверить, насколько хорошо это работает, я попробовал несколько различных методов из Web API, таких как alert
, setInterval
, addEventListener
и т.д. Все сработало, как и ожидалось.
Объекты и методы нативного JavaScript
В игре Snake, после того как змея съест яблоко, нам нужно сгенерировать новое яблоко в случайном месте.
Однако, когда я начинал работать с Brython, я не знал, что могу использовать модуль случайных чисел random
Python (вы можете!). Как же мне сгенерировать случайное число (без создания собственной библиотеки)?
Оказывается, на самом деле мы можем получить доступ к большему количеству JavaScript, чем я думал. Посмотрите на это:
from javascript import Math random_num = Math.floor(Math.random()*10)
С модулем javascript
, если есть объект, к которому я могу обратиться с помощью JS, я могу обратиться к нему с помощью Brython.
Например, если я импортирую библиотеку JavaScript (jQuery, Bootstrap) и хочу использовать ее методы — я могу сделать это с помощью from javascript import <library>
. И, естественно, таким же образом я могу использовать встроенные объекты JS, такие как Date
или String
.
Концепции, специфичные для конкретного языка
В Python, если я хочу распаковать список, я могу сделать list2 = [*list1]
. Также, если я хочу установить значение переменной на основе условия, я использую foo = 10 if condition else 20
.
These do have JavaScript equivalents: the spread operator( [...arr]
) and the ternary operator ( let foo = condition ? 10 : 20
).
У них есть эквиваленты в JavaScript: оператор spread( [...arr]
) и троичный оператор ( let foo = condition ? 10 : 20
).
Но поддерживает ли их Brython?
Я попробовал их использовать, и все работает отлично. Вы увидите, что распаковка списка Python и условное присвоение включены в мой окончательный исходный код.
Отладка
Честно говоря, я думал, что отладка Brython будет ужасной.
Однако на самом деле все не так уж плохо.
Конечно, то, что я создал, это небольшой проект, не очень сложный, но ошибки, выдаваемые Brython, были в основном точными и достаточно описательными.
Это верно, по крайней мере, в отношении проблем с синтаксисом. Импорт модулей Python — это совсем другое дело.
Производительность
Как и ожидалось, оценка кода Brython во время выполнения выполняется медленнее, чем JavaScript. В моем случае это было примерно в 1,7 раза медленнее.
Для более сложных проектов, я подозреваю, Brython будет в несколько раз медленнее, чем чистый JS.
Однако вы можете заранее транспонировать код Brython и включать JavaScript только на веб-странице, что должно улучшить работу.
Я пытался использовать редактор Brython Editor для преобразования кода Brython в JS и запуска реального JS на веб-странице, но он выдавал так много ошибок, что я решил пока отложить его в сторону. Впрочем, я не приложил к этому много усилий.
Заключительные размышления о Brython
Честно говоря, Brython произвел на меня большое впечатление. Вот некоторые плюсы и минусы из моего собственного опыта работы с этим языком:
Плюсы
- Мне удалось написать «Змейку» без лишних хлопот, причем опыт отладки оказался на удивление положительным.
- В моем простом проекте Brython беспрепятственно взаимодействовал с нативными JavaScript-объектами, доступными на странице
- Я ценю тот факт, что мой код выглядит чище на Python, а также мне нравится, что я могу использовать полезные конструкции из Python для написания браузерного кода.
- В случае с моей игрой, хоть Brython загружается медленнее, чем JavaScript, пользователь этой разницы не замечает.
- Мне приятно видеть Python в исходном коде моего сайта.
Минусы
- Брайтон работает значительно медленнее, чем чистый JS.
- Для использования Brython разработчику необходимо иметь опыт работы с JavaScript.
- Вы неизбежно столкнетесь с большим количеством ошибок
- Документации Brython и его сайту есть куда расти в плане удобства навигации и возможностей обучения
- У Brython отсутствует сильная экосистема и инструменты развития.
В целом, закончив свой первый проект с Brython, я могу с уверенностью сказать, что когда-нибудь попробую его снова.
Однако я считаю, что в нынешнем виде Brython больше подходит для разработчиков JavaScript, которые знают Python и устали от JavaScript, чем для разработчиков Python, которые хотят заниматься веб-разработкой без необходимости изучать JavaScript.
Чтобы хорошо работать с Brython, я думаю, вам нужно немного понимать JavaScript. И если вы решите потратить время на изучение достаточного количества JavaScript, чтобы с легкостью писать на Brython, то с тем же успехом вы можете просто использовать JavaScript.
Другие альтернативы Browser JS
Причина, по которой я выбрал Brython, заключается в том, что из всех альтернатив Python to JS, о которых я впервые узнал, это был единственный, который все еще активно разрабатывался на GitHub. Большинство транспилеров Python → JavaScript, с которыми я сталкивался, вообще не видели коммитов за последние несколько лет.
Однако существуют и другие альтернативы.
Например, интересным представляется Pyodide. Он компилирует Python (вместе с его научными библиотеками) в WebAssembly, что позволяет запускать его в браузере.
WebAssembly, как следует из названия, — это язык ассемблера для веба (Интернета). Подобно тому, как ассемблер в наших компьютерах может работать как посредник между языками высокого уровня и машинным кодом, WebAssembly может позволить то же самое сделать в Интернете.
Таким образом, можно написать компилятор для Python или любого другого языка к WebAssembly, что позволит запускать его в браузере.
Это амбициозный и многообещающий проект, который, вероятно, приведет к тому, что мы будем видеть все больше и больше веб-разработок без JavaScript.
Однако он все еще находится в зачаточном состоянии (~3 года), поэтому, вероятно, пройдет некоторое время, прежде чем мы увидим, как JavaScript будет заменен другими языками на регулярной основе.
А пока этого не происходит, вам придется прибегнуть к таким инструментам, как Brython, если вы действительно не можете работать с JavaScript.
Но, честно говоря, это неплохое начало!