Bosan dengan JavaScript - gunakan Python berbasis browser

Pengalaman saya mengembangkan game "Snake" di Brython



gambar



"Tunggu, apa?" - Saya pikir sebagian besar pembaca akan bereaksi seperti itu terhadap judul.



Apakah maksud Anda "gunakan saja Python di browser"?



Semua orang tahu bahwa hanya JavaScript yang berfungsi di browser.



Nah, diatas adalah screenshot dari source code situs pribadi saya. Coba lihat, mungkin Anda akan melihat sesuatu yang baru untuk diri Anda sendiri.



Ya, itu Python!



Sekarang, mari kita bicara tentang bagaimana dan seberapa baik kerjanya, dan juga membahas sejumlah alternatif JavaScript lainnya.



Memperkenalkan Brython



Brython adalah implementasi JavaScript dari Python3 yang memungkinkan Anda menulis kode Python untuk web.



Pada dasarnya, ini adalah pustaka JavaScript yang mengubah kode Python Anda menjadi JS yang setara dan menjalankannya saat runtime.



Karena menulis kode browser dengan Python terdengar keren, saya memutuskan untuk mencobanya.



Perkembangan "Snake" di Brython



gambar



Ini adalah tautan ke situs saya di mana Anda dapat mencoba versi JavaScript dan Brython dari Snake. Dan ini adalah tautan ke GitHub dengan kode sumbernya .



Untuk mencoba Brython, saya memutuskan untuk menulis Snake klasik.



Karena saya bukan ahli HTML Canvas atau pengembang game, saya memutuskan untuk menggunakan implementasi JavaScript ini sebagai titik awal. Dulu saya sudah membuat "Snake" saya berdasarkan Canvas, tetapi implementasi ini lebih rapi dan lebih kompak.



The Penulis juga menulis dalam waktu kurang dari 5 menit . Saya harus memberikan penghargaan kepada Chris DeLeon, ini sangat mengesankan.



Jadi, saya menambahkan skor dan menyimpan skor terbaik untuk implementasi Chris, dan juga sedikit meningkatkan antarmuka (menambahkan tombol jeda dan tombol dengan instruksi). Lalu saya memindahkan game ke Brython.



Saya juga memodifikasi kodenya sehingga berfungsi dalam mode strict, karena implementasi Chris menggunakan hal-hal seperti variabel global implisit, yang, menurut saya, tidak mencerminkan seperti apa sebagian besar kode di JS (saya tidak mengkritik penulis - dia memprogram untuk saat itu ). Saya ingin mendapatkan perbandingan yang baik antara kode Brython dan JS.



JavaScript ternyata seperti ini , dan saya tidak akan memposting kode ini di sini, jadi tujuan kita adalah fokus pada Brython.



Meskipun sebagian besar kode Brython diterjemahkan secara harfiah dari JS, beberapa bagian (seperti fungsi penilaian) ditulis langsung di Brython dan kemudian diimplementasikan di JS untuk melihat perbedaannya.



Hasil akhirnya terlihat seperti ini:



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


Jadi, berdasarkan potongan ini, mari kita pahami beberapa konsep dasar Brython



Koneksi Brython.js



Tidak diperlukan instalasi untuk menggunakan Brython. Cukup impor skrip di dalamnya head :



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


Menjalankan Brython



Agar Brython menerjemahkan dan mengeksekusi kode Python seolah-olah itu adalah kode JS, kita perlu memanggil Brythontepat ketika badan dokumen dimuat. Misalnya seperti ini:



<body onload=”brython()”>


Tag ini akan mencari tag scriptjenis "text/python"dan menjalankan kodenya.



API untuk bekerja dengan web



JavaScript secara default memberikan akses ke objek yang disukai documentdan windowdibutuhkan dalam proyek JS apa pun. Oleh karena itu, Brython juga dapat bekerja dengan mereka.



Untuk mengatasi masalah ini, pencipta Brython dapat dengan mudah memberi pengembang kemampuan untuk mengakses objek-objek ini dari kode Python, tetapi ini akan menyebabkan tangisan debugger undefined variabledan kinerja yang menurun.



Jadi, untuk menggunakan API ini, kita harus mengimpornya dengan cara yang sama seperti kita mengimpor modul Python lainnya:



from browser import document, html, window


Dan Anda tidak perlu menjalankan perintah pip install. Bagaimanapun, Anda menanamkan semuanya dalam HTML! Cukup tambahkan impor yang diperlukan dan Brython akan menangani sisanya.



Untuk melihat seberapa baik kerjanya, saya mencoba menggunakan beberapa metode yang berbeda dari API Web: alert, setInterval, addEventListenerdll Mereka semua bekerja sebagaimana mestinya.



Objek dan Metode JavaScript bawaan



Di Snake, segera setelah ular memakan apel, kita perlu membuat apel baru di lokasi acak.



Namun, saya tidak dapat menggunakan modul acak dari pustaka Python *. Jadi bagaimana saya bisa menghasilkan nomor acak (tanpa menulis perpustakaan saya sendiri)?



Ternyata Brython memiliki dukungan JavaScript yang lebih luas dari yang saya kira. Lihat:



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


Berkat modulnya javascript, jika ada objek yang bisa saya akses menggunakan JS, maka saya bisa mengaksesnya menggunakan Brython.



Jika saya mengimpor pustaka JavaScript (jQuery, Bootstrap) dan ingin menggunakan metodenya, saya dapat melakukannya dengan from javascript import <>. Dan tentu saja, saya juga bisa menggunakan objek JS bawaan seperti Dateatau String.

* Brython tampaknya datang dengan sejumlah pustaka Python standar yang diimplementasikan langsung dalam JavaScript, dan jika sebuah modul tidak memiliki versi JS, Anda masih dapat mengimpornya. Brython akan mendapatkan versi Python murni dan kode modul yang diimpor akan bekerja bersama kode Brython. Namun, modul acak tidak berfungsi untuk saya - tetapi saya bisa mengerti mengapa.

Konstruksi khusus



Dengan Python, jika saya ingin membongkar daftar, saya bisa menulis list2 = [*list1]. Juga, jika saya ingin memberikan nilai ke variabel berdasarkan beberapa kondisi, saya bisa menulis foo = 10 if condition else 20.



Konstruksi ini memiliki persamaan JavaScript: [...arr]operator spread ( ) dan operator ternary ( let foo = condition ? 10 : 20).



Tapi apakah Brython mendukung mereka?



Saya mencobanya dan hasilnya bagus. Anda dapat melihat daftar unboxing dari Python dan tugas bersyarat digunakan dalam kode saya.



Debugging



Sejujurnya, saya pikir debugging di Brython akan sangat buruk.



Sebenarnya, tidak seburuk itu.



Tentu saja, saya menulis proyek yang sangat kecil dan tidak terlalu rumit, tetapi kesalahan yang dibuat oleh Brython sebagian besar akurat dan cukup bisa dimengerti.



Ini benar, setidaknya untuk kesalahan sintaks. Mengimpor modul dari pustaka Python adalah cerita yang sama sekali berbeda.



Performa



gambar



JavaScript Snake



gambar



Brython Snake



Seperti yang diharapkan, kode Brython lebih lambat dari JavaScript. Dalam kasus saya, itu sekitar 1,7 kali lebih lambat.



Saya menduga bahwa dalam proyek yang lebih kompleks, Brython akan beberapa kali lebih lambat dari JS murni.



Namun, Anda dapat mentranspilasi kode Brython Anda sebelumnya dan hanya menggunakan JavaScript di halaman, yang seharusnya berkinerja lebih baik.



Saya memang mencoba menggunakan Editor Brython untuk mengonversi kode Brython saya ke JS dan menjalankan kode yang dihasilkan di halaman web, tetapi karena sejumlah besar kesalahan, saya menyerah untuk saat ini. Namun, saya belum berusaha terlalu keras untuk ini.



Pikiran terakhir tentang Brython



Sejujurnya, saya cukup terkesan dengan Brython. Berikut adalah beberapa pro dan kontra dari pengalaman saya sendiri dengan bahasa tersebut:



Pro



  • Saya berhasil menulis "The Snake" tanpa kerumitan yang tidak perlu, dan pengalaman debugging ternyata sangat positif.
  • Dalam proyek sederhana saya, Brython berinteraksi secara mulus dengan objek JavaScript asli yang tersedia di halaman
  • Saya menghargai fakta bahwa kode saya terlihat lebih bersih dengan Python, dan saya juga suka bahwa saya dapat menggunakan konstruksi Python yang berguna untuk menulis kode browser.
  • Dalam kasus game saya, meskipun Brython memuat lebih lambat dari JavaScript, pengguna tidak melihat perbedaan ini.
  • Saya senang melihat Python dalam kode sumber situs saya.


Minus



  • Brighton secara signifikan lebih lambat daripada JS murni.
  • Brython JavaScript.
  • Brython
  • Brython .


Secara umum, setelah menyelesaikan proyek pertama saya di Brython, saya dapat mengatakan dengan yakin bahwa saya akan mencoba lagi suatu hari nanti.



Namun, saya yakin Brython sekarang lebih cocok untuk pengembang JavaScript yang akrab dengan Python dan bosan dengan JS, daripada pengembang Python yang ingin melakukan pengembangan web tanpa mempelajari JavaScript.



Saya pikir pemahaman tentang JavaScript sangat penting agar dapat bekerja dengan baik dengan Brython. Dan jika Anda memutuskan untuk meluangkan waktu mempelajari JavaScript agar Anda lebih mudah menulis di Brython, maka Anda bisa menggunakan JavaScript.



Alternatif JS browser lainnya



gambar



Alasan saya memilih Brython adalah karena sebagian besar opsi transisi Python ke JS yang pertama kali saya pelajari, itu adalah satu-satunya yang aktif berkembang di GitHub. Sebagian besar transpiler Python ke JavaScript yang saya lihat belum memiliki komit selama beberapa tahun.



Namun, ada alternatif lain.



Pyodide , misalnya, sepertinya merupakan opsi yang menarik. Ia mengkompilasi Python (bersama dengan pustaka ilmiahnya) ke WebAssembly, yang memungkinkannya berjalan di browser.



WebAssembly, seperti namanya, adalah assembler untuk web. Sebagaimana assembler di komputer kita dapat bertindak sebagai perantara antara bahasa tingkat tinggi dan kode mesin, WebAssembly melakukan hal yang sama di web.



Jadi, dimungkinkan untuk menulis kompiler yang akan menerjemahkan Python (atau bahasa lain) ke dalam WebAssembly, memungkinkannya untuk berjalan di browser.



Ini adalah proyek ambisius dan menjanjikan yang kemungkinan besar akan mengarah pada fakta bahwa kita akan melihat lebih banyak pengembangan web tanpa JavaScript.



Namun, ini masih dalam tahap awal (~ 3 tahun), jadi mungkin perlu beberapa saat sebelum kita melihat JavaScript secara teratur diganti oleh bahasa lain.



Dan sementara kami menunggu, Anda harus menggunakan alat seperti Brython jika Anda benar-benar tidak dapat menangani JavaScript.



Tapi sejujurnya, ini adalah awal yang baik!



gambar


Pelajari lebih lanjut tentang cara mendapatkan profesi profil tinggi dari awal atau Naik Level dalam keterampilan dan gaji dengan mengikuti kursus online berbayar SkillFactory:











All Articles