Cansado de JavaScript: use Python basado en navegador

Mi experiencia de desarrollar el juego "Snake" en Brython



imagen



"Espera, ¿qué?" - Creo que la mayoría de los lectores reaccionarán de esa manera al título.



¿Quiere decir "solo use Python en el navegador"?



Todo el mundo sabe que solo JavaScript funciona en los navegadores.



Bueno, arriba hay una captura de pantalla del código fuente de mi sitio personal. Eche un vistazo, puede ver algo nuevo para usted.



¡Sí, es Python!



Ahora, hablemos sobre cómo y qué tan bien funciona, y también analicemos otras alternativas de JavaScript.



Presentando Brython



Brython es una implementación de JavaScript de Python3 que le permite escribir código Python para la web.



Básicamente, es una biblioteca de JavaScript que convierte su código Python al JS equivalente y lo ejecuta en tiempo de ejecución.



Dado que escribir código de navegador en Python suena bien, decidí intentarlo.



Desarrollo de "Snake" en Brython



imagen



Aquí hay un enlace a mi sitio donde puede probar las versiones JavaScript y Brython de Snake. Y aquí hay un enlace a GitHub con el código fuente .



Para probar Brython, decidí escribir el clásico Snake.



Como no soy un experto en HTML Canvas ni un desarrollador de juegos, decidí usar esta implementación de JavaScript como punto de partida. Una vez ya creé mi "Snake" sobre la base de Canvas, pero esta implementación es más ordenada y compacta.



El autor también lo escribió en menos de 5 minutos . Tengo que darle crédito a Chris DeLeon, es muy impresionante.



Entonces, agregué la puntuación y guarde la mejor puntuación a la implementación de Chris, y también mejoré ligeramente la interfaz (agregué un botón de pausa y un botón con instrucciones). Luego porté el juego a Brython.



También modifiqué su código para que funcione en un modo strict, ya que la implementación de Chris usa cosas como variables globales implícitas, que, en mi opinión, no reflejan cómo se ve la mayor parte del código JS (no estoy criticando al autor, él programó para el momento ). Quería una buena comparación entre el código Brython y JS.



JavaScript resultó ser así , y no publicaré este código aquí, por lo que nuestro objetivo es centrarnos en Brython.



Aunque la mayor parte del código Brython se tradujo literalmente de JS, algunas partes (como la funcionalidad de puntuación) se escribieron directamente en Brython y luego se implementaron en JS para ver las diferencias.



El resultado final se ve así:



<!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>


Entonces, según este fragmento, comprendamos algunos conceptos básicos de Brython



Conexión Brython.js



No se requiere instalación para usar Brython. Simplemente importe el script dentro head :



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


Ejecutando Brython



Para que Brython traduzca y ejecute código Python como si fuera código JS, necesitamos llamar Brythonjusto cuando se carga el cuerpo del documento. Por ejemplo, así:



<body onload=”brython()”>


Esta etiqueta buscará etiquetas de scripttipo "text/python"y ejecutará su código.



API para trabajar con la web



JavaScript por defecto da acceso a objetos como documenty windownecesarios en cualquier proyecto JS. En consecuencia, Brython también debería poder trabajar con ellos.



Para resolver este problema, los creadores de Brython simplemente podrían dar a los desarrolladores la capacidad de acceder a estos objetos desde el código Python, pero esto provocaría problemas de depuración undefined variabley un rendimiento degradado.



Por lo tanto, para usar estas API, debemos importarlas de la misma manera que importamos cualquier otro módulo de Python:



from browser import document, html, window


Y no es necesario que ejecute el comando pip install. Después de todo, ¡lo incrusta todo en HTML! Simplemente agregue las importaciones requeridas y Brython se encargará del resto.



Para ver lo bien que funciona, he intentado utilizar varios métodos diferentes de la API de la web: alert, setInterval, addEventListeneretc. Todos trabajaron como debían.



Métodos y objetos de JavaScript integrados



En Snake, tan pronto como la serpiente se come la manzana, necesitamos generar una nueva manzana en una ubicación aleatoria.



Sin embargo, no puedo usar el módulo aleatorio de la biblioteca Python *. Entonces, ¿cómo puedo generar un número aleatorio (sin escribir mi propia biblioteca)?



Resulta que Brython tiene un soporte de JavaScript más amplio de lo que pensaba. Ver:



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


Gracias al módulo javascript, si hay un objeto al que puedo acceder usando JS, entonces puedo acceder a él usando Brython.



Si importo una biblioteca de JavaScript (jQuery, Bootstrap) y quiero usar sus métodos, puedo hacerlo con from javascript import <>. Y, naturalmente, también puedo usar objetos JS integrados como Dateo String.

* Brython parece venir con una serie de bibliotecas estándar de Python implementadas directamente en JavaScript, y si un módulo no tiene una versión JS, aún puede importarlo. Brython obtendrá una versión pura de Python y el código del módulo importado funcionará junto con el código de Brython. Sin embargo, el módulo aleatorio no funcionó para mí, pero puedo entender por qué.

Construcciones específicas



En Python, si quiero descomprimir una lista, puedo escribir list2 = [*list1]. Además, si quiero asignar valores a una variable en función de alguna condición, puedo escribir foo = 10 if condition else 20.



Estas construcciones tienen equivalentes de JavaScript: el [...arr]operador spread ( ) y el operador ternary ( let foo = condition ? 10 : 20).



Pero, ¿Brython los apoya?



Los probé y funcionaron muy bien. Puede ver que la lista de unboxing de Python y la asignación condicional se utilizan en mi código.



Depuración



Para ser honesto, pensé que depurar en Brython sería horrible.



De hecho, no es tan malo.



Por supuesto, escribí un proyecto muy pequeño y no muy complejo, pero los errores arrojados por Brython fueron en su mayoría precisos y bastante comprensibles.



Esto es cierto al menos para los errores de sintaxis. Importar módulos de la biblioteca de Python es una historia completamente diferente.



Actuación



imagen



JavaScript Snake



imagen



Brython Snake



Como era de esperar, el código Brython es más lento que JavaScript. En mi caso, fue aproximadamente 1,7 veces más lento.



Sospecho que en proyectos más complejos, Brython será varias veces más lento que JS puro.



Sin embargo, puede transpilar su código Brython con anticipación y solo usar JavaScript en la página, lo que debería funcionar mejor. Intenté



usar Brython Editor para convertir mi código Brython a JS y ejecutar el código resultante en una página web, pero debido a una gran cantidad de errores, me he rendido con esto por ahora. Sin embargo, no me he esforzado demasiado en esto.



Reflexiones finales sobre Brython



Para ser honesto, estaba bastante impresionado con Brython. Aquí hay algunos pros y contras de mi propia experiencia con el idioma:



Pros



  • Me las arreglé para escribir "The Snake" sin problemas innecesarios, y la experiencia de depuración fue sorprendentemente positiva.
  • En mi proyecto simple, Brython interactuó sin problemas con los objetos JavaScript nativos disponibles en la página.
  • Aprecio el hecho de que mi código se ve más limpio en Python, y también me encanta que puedo usar construcciones útiles de Python para escribir código de navegador.
  • En el caso de mi juego, aunque Brython carga más lento que JavaScript, el usuario no nota esta diferencia.
  • Me complace ver a Python en el código fuente de mi sitio.


Desventajas



  • Brighton es significativamente más lento que JS puro.
  • Brython JavaScript.
  • Brython
  • Brython .


En general, habiendo terminado mi primer proyecto en Brython, puedo decir con seguridad que lo intentaré de nuevo algún día.



Sin embargo, creo que Brython ahora es más adecuado para desarrolladores de JavaScript familiarizados con Python y cansados ​​de JS, en lugar de desarrolladores de Python que quieren hacer desarrollo web sin aprender JavaScript.



Creo que comprender JavaScript es esencial para trabajar bien con Brython. Y si decide tomarse el tiempo para aprender JavaScript para que le sea más fácil escribir en Brython, entonces puede usar JavaScript.



Otras alternativas de navegador JS



imagen



La razón por la que elegí Brython fue porque la mayoría de las opciones de transición de Python a JS que conocí por primera vez, era la única que se estaba desarrollando activamente en GitHub. La mayoría de los transpilers de Python a JavaScript que he visto no han tenido confirmaciones durante varios años.



Sin embargo, existen otras alternativas.



Pyodide , por ejemplo, parece una opción interesante. Compila Python (junto con sus bibliotecas científicas) en WebAssembly, lo que le permite ejecutarse en un navegador.



WebAssembly, como su nombre indica, es un ensamblador para la web. Así como el ensamblador en nuestras computadoras puede actuar como intermediario entre lenguajes de alto nivel y código de máquina, WebAssembly hace lo mismo en la web.



Por lo tanto, es posible escribir un compilador que traduzca Python (o cualquier otro lenguaje) a WebAssembly, lo que le permitirá ejecutarse en un navegador.



Este es un proyecto ambicioso y prometedor que probablemente conducirá al hecho de que veremos más y más desarrollo web sin JavaScript.



Sin embargo, todavía está en su infancia (~ 3 años), por lo que probablemente pasará algún tiempo antes de que veamos que JavaScript es reemplazado regularmente por otros lenguajes.



Y mientras esperamos, tendrá que usar herramientas como Brython si realmente no puede manejar JavaScript.



Pero, sinceramente, ¡este es un buen comienzo!



imagen


Descubra los detalles de cómo obtener una profesión de alto perfil desde cero o subir de nivel en habilidades y salario tomando los cursos en línea pagados de SkillFactory:











All Articles