Cansado de JavaScript - use Python baseado em navegador

Minha experiência no desenvolvimento do jogo "Snake" em Brython



imagem



"Espera, o quê?" - Acho que a maioria dos leitores vai reagir ao título dessa forma.



Você quer dizer "apenas use Python no navegador"?



Todo mundo sabe que apenas JavaScript funciona em navegadores.



Bem, acima está uma imagem do código-fonte do meu site pessoal. Dê uma olhada, você pode ver algo novo por si mesmo.



Sim, é Python!



Agora, vamos falar sobre como e como funciona bem e também discutir uma série de outras alternativas de JavaScript.



Apresentando Brython



Brython é uma implementação JavaScript do Python3 que permite escrever código Python para a web.



Basicamente, é uma biblioteca JavaScript que converte seu código Python para o JS equivalente e o executa em tempo de execução.



Como escrever código de navegador em Python parece legal, decidi fazer uma tentativa.



Desenvolvimento de "Snake" em Brython



imagem



Aqui está um link para o meu site onde você pode experimentar as versões JavaScript e Brython do Snake. E aqui está um link para o GitHub com o código-fonte .



Para experimentar Brython, decidi escrever o clássico Snake.



Como não sou um especialista em HTML Canvas ou desenvolvedor de jogos, decidi usar essa implementação de JavaScript como ponto de partida. Uma vez eu já criei meu "Snake" com base no Canvas, mas essa implementação é mais organizada e compacta.



O autor também escreveu em menos de 5 minutos . Tenho que dar crédito a Chris DeLeon, isso é muito impressionante.



Então, adicionei pontuação e salvando a melhor pontuação para a implementação de Chris e também melhorei um pouco a interface (adicionei um botão de pausa e um botão com instruções). Então eu transferi o jogo para Brython.



Eu também modifiquei seu código para que funcione em um modo strict, uma vez que a implementação de Chris usa coisas como variáveis ​​globais implícitas, que, em minha opinião, não refletem a aparência da maior parte do código em JS (não estou criticando o autor - ele programou para a época ) Eu queria fazer uma boa comparação entre o código Brython e JS.



O JavaScript acabou sendo assim e não vou postar esse código aqui, então nosso objetivo é focar em Brython.



Embora a maior parte do código Brython tenha sido traduzido literalmente de JS, algumas partes (como a funcionalidade de pontuação) foram escritas diretamente em Brython e, em seguida, implementadas em JS para ver as diferenças.



O resultado final é assim:



<!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/brython@3.8.9/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>


Então, com base neste snippet, vamos entender alguns conceitos básicos de Brython



Conexão Brython.js



Nenhuma instalação é necessária para usar o Brython. Basta importar o script dentro de head :



<script type=”text/javascript” src=”https://cdn.jsdelivr.net/npm/brython@3.8.9/brython.min.js">


Running Brython



Para que Brython traduza e execute o código Python como se fosse um código JS, precisamos chamar Brythonapenas quando o corpo do documento for carregado. Por exemplo, assim:



<body onload=”brython()”>


Esta tag irá procurar tags do scripttipo "text/python"e executar seu código.



API para trabalhar com a web



JavaScript, por padrão, dá acesso a objetos semelhantes documente windownecessários em qualquer projeto JS. Conseqüentemente, Brython deve poder trabalhar com eles também.



Para resolver esse problema, os criadores do Brython poderiam simplesmente dar aos desenvolvedores a capacidade de acessar esses objetos a partir do código Python, mas isso levaria a gritos do depurador undefined variablee degradação do desempenho.



Portanto, para usar essas APIs, devemos importá-las da mesma forma que importamos qualquer outro módulo Python:



from browser import document, html, window


E você não precisa executar o comando pip install. Afinal, você incorpora tudo em HTML! Basta adicionar as importações necessárias e Brython cuidará do resto.



Para ver como ele funciona bem, eu tentei usar vários métodos diferentes da API da Web: alert, setInterval, addEventListeneretc. Todos trabalharam como deveriam.



Objetos e métodos JavaScript integrados



No Snake, assim que a cobra comer a maçã, precisamos gerar uma nova maçã em um local aleatório.



No entanto, não posso usar o módulo aleatório da biblioteca Python *. Então, como posso gerar um número aleatório (sem escrever minha própria biblioteca)?



Acontece que Brython tem suporte a JavaScript mais amplo do que eu pensava. Vejo:



from javascript import Math
random_num = Math.floor(Math.random()*10)


Graças ao módulo javascript, se houver um objeto que posso acessar usando JS, então posso acessá-lo usando Brython.



Se eu importar uma biblioteca JavaScript (jQuery, Bootstrap) e quiser usar seus métodos, posso fazer com from javascript import <>. E, claro, também posso usar objetos JS integrados como Dateou String.

* Brython parece ser fornecido com várias bibliotecas Python padrão implementadas diretamente em JavaScript e, se um módulo não tiver uma versão JS, você ainda poderá importá-lo. Brython obterá uma versão Python pura e o código do módulo importado funcionará junto com o código Brython. No entanto, o módulo aleatório não funcionou para mim - mas posso entender por quê.

Construções específicas



Em Python, se eu quiser descompactar uma lista, posso escrever list2 = [*list1]. Além disso, se eu quiser atribuir valores a uma variável com base em alguma condição, posso escrever foo = 10 if condition else 20.



Essas construções têm equivalentes em JavaScript: o [...arr]operador spread ( ) e o operador ternário ( let foo = condition ? 10 : 20).



Mas Brython os apóia?



Eu tentei e eles funcionaram muito bem. Você pode ver que o unboxing da lista do Python e a atribuição condicional são usados ​​no meu código.



Depurando



Para ser honesto, achei que depurar no Brython seria horrível.



Na verdade, não é tão ruim assim.



Claro, eu escrevi um projeto muito pequeno e não muito complexo, mas os erros lançados por Brython foram em sua maioria precisos e bastante compreensíveis.



Isso é verdade, pelo menos para erros de sintaxe. Importar módulos da biblioteca Python é uma história completamente diferente.



atuação



imagem



JavaScript Snake



imagem



Brython Snake



Como esperado, o código Brython é mais lento que o JavaScript. No meu caso, foi cerca de 1,7 vezes mais lento.



Suspeito que em projetos mais complexos, Brython será várias vezes mais lento do que JS puro.



No entanto, você pode transpilar seu código Brython com antecedência e usar apenas JavaScript na página, que deve ter um desempenho melhor.



Na verdade, tentei usar o Editor Brython para converter meu código Brython em JS e executar o código resultante em uma página da web, mas devido a um grande número de erros, desisti disso por enquanto. No entanto, não coloquei muito esforço nisso.



Considerações finais sobre Brython



Para ser honesto, fiquei bastante impressionado com Brython. Aqui estão alguns prós e contras de minha própria experiência com o idioma:



Prós



  • Consegui escrever "Snake" sem problemas desnecessários e a experiência de depuração foi surpreendentemente positiva.
  • Em meu projeto simples, Brython interagiu perfeitamente com os objetos JavaScript nativos disponíveis na página
  • Agradeço o fato de que meu código parece mais limpo em Python e também adoro poder usar construções úteis de Python para escrever código de navegador.
  • No caso do meu jogo, embora Brython carregue mais devagar que o JavaScript, o usuário não nota essa diferença.
  • Tenho o prazer de ver Python no código-fonte do meu site.


Minuses



  • Brighton é significativamente mais lento do que JS puro.
  • Brython JavaScript.
  • Brython
  • Brython .


Em geral, tendo concluído meu primeiro projeto em Brython, posso dizer com segurança que tentarei novamente algum dia.



No entanto, acredito que Brython agora é mais adequado para desenvolvedores JavaScript que estão familiarizados com Python e cansados ​​de JS, em vez de desenvolvedores Python que desejam desenvolver web sem aprender JavaScript.



Acho que um entendimento de JavaScript é essencial para trabalhar bem com Brython. E se você decidir reservar um tempo para aprender JavaScript para tornar mais fácil para você escrever no Brython, então você pode simplesmente usar o JavaScript.



Outras alternativas de JS de navegador



imagem



A razão pela qual escolhi o Brython foi por causa da maioria das opções de transição de Python para JS que aprendi pela primeira vez, era a única em desenvolvimento ativo no GitHub. A maioria dos transpiladores de Python para JavaScript que examinei não teve commits por vários anos.



No entanto, existem outras alternativas.



Pyodide , por exemplo, parece uma opção interessante. Ele compila o Python (junto com suas bibliotecas científicas) para WebAssembly, o que permite sua execução em um navegador.



WebAssembly, como o nome sugere, é um assembler para a web. Assim como o assembler em nossos computadores pode atuar como intermediário entre as linguagens de alto nível e o código de máquina, o WebAssembly faz o mesmo na web.



Assim, é possível escrever um compilador que irá traduzir Python (ou qualquer outra linguagem) em WebAssembly, permitindo que seja executado em um navegador.



Este é um projeto ambicioso e promissor que provavelmente levará ao fato de que veremos cada vez mais desenvolvimento web sem JavaScript.



No entanto, ele ainda está em sua infância (~ 3 anos), então provavelmente levará algum tempo antes de vermos o JavaScript sendo regularmente substituído por outras linguagens.



E enquanto esperamos, você terá que usar ferramentas como Brython se você realmente não consegue lidar com JavaScript.



Mas, honestamente, este é um bom começo!



imagem


Saiba mais sobre como obter uma profissão de alto perfil do zero ou Subir de nível em habilidades e salários, fazendo os cursos online pagos da SkillFactory:











All Articles