厌倦了JavaScript-使用基于浏览器的Python

我在Brython开发游戏“ Snake”的经验



图片



“等等,什么?” -我认为大多数读者都会对标题做出反应。



您是说“只在浏览器中使用Python”吗?



所有人都知道,只有JavaScript才能在浏览器中使用。



好吧,以上是我的个人网站的源代码的屏幕截图。看看,您可能会发现一些自己的新事物。



是的,它是Python!



现在,让我们讨论它的工作方式和运行状况,并讨论许多其他JavaScript替代方法。



Brython简介



BrythonPython3的JavaScript实现,可让您为网络编写Python代码。



基本上,这是一个JavaScript库,可将您的Python代码转换为等效的JS并在运行时运行它。



由于用Python编写浏览器代码听起来很棒,因此我决定尝试一下。



在布莱顿开发“蛇”



图片



这是我网站链接,您可以在其中试用JavaScript和Brython版本的Snake。这是带有源代码的GitHub链接



为了尝试Brython,我决定写经典的Snake。



由于我不是HTML Canvas专家或游戏开发人员,因此我决定以JavaScript实现为起点。一旦我已经在Canvas的基础上创建了我的“ Snake”,但是此实现更加整洁和紧凑。



作者还写了它在不到5分钟。我必须感谢克里斯·德莱昂(Chris DeLeon),这令人印象深刻。



因此,我为Chris的实现添加了得分并保存了最佳分数,并且还对界面进行了一些改进(添加了暂停按钮和带有说明的按钮)。然后,我将游戏移植到了Brython。



我还修改了他的代码,使其可以在某种模式下工作strict,因为Chris的实现使用了隐式全局变量之类的东西,在我看来,这并不能反映JS中大多数代码的样子(我不是在批评作者-他当时编程)。我想对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/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>


因此,基于此摘要,让我们了解一些基本的Brython概念



Brython.js连接



使用Brython无需安装。只需将脚本导入 head



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


运行布赖顿



为了让Brython像JS代码一样转换和执行Python代码,我们需要在Brython加载文档正文时进行调用例如,像这样:



<body onload=”brython()”>


该标签将搜索script类型的标签"text/python"并运行其代码。



用于网络的API



JavaScript的默认情况下可以访问相同的对象document,并window在任何JS项目所需。因此,Brython也应该能够与他们合作。



为了解决这个问题,Brython的创建者可以简单地使开发人员能够从Python代码访问这些对象,但这会导致调试器发出哭声undefined variable并降低性能。



因此,要使用这些API,我们必须以与导入任何其他Python模块相同的方式导入它们:



from browser import document, html, window


而且您不需要执行命令pip install毕竟,您都将其嵌入HTML!只需添加所需的导入,Brython将处理其余的导入。



要了解它有多好作品,我试图用API网络的几种不同的方法:alertsetIntervaladdEventListener等。他们都按照应有的方式工作。



内置的JavaScript对象和方法



在Snake中,蛇一吃完苹果,就需要在随机位置生成一个新苹果。



但是,我不能使用Python *库中的random模块。那么,如何生成一个随机数(不编写自己的库)呢?



事实证明,Brython具有比我想象的更广泛的JavaScript支持。看到:



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


多亏了模块javascript,如果有一个我可以使用JS访问的对象,那么我可以使用Brython访问它。



如果导入JavaScript库(jQuery,Bootstrap)并想使用其方法,则可以使用from javascript import <>当然,我也可以使用内置的JS对象(例如Date或)String

* Brython似乎附带了许多直接用JavaScript实现的标准Python库,如果模块没有JS版本,您仍然可以导入它。Brython将获得纯Python版本,并且导入的模块代码将与Brython代码一起使用。但是,随机模块对我不起作用-但我可以理解原因。

具体结构



在Python中,如果要解压缩列表,可以编写 list2 = [*list1]另外,如果我想根据某种条件为变量赋值,我可以写foo = 10 if condition else 20



这些构造具有JavaScript等效项:spread( [...arr])运算符和ternary(let foo = condition ? 10 : 20运算符



但是Brython支持他们吗?



我尝试了它们,它们效果很好。您可以看到在我的代码中使用了从Python拆箱和条件赋值的列表。



调试



老实说,我认为在Brython中进行调试会很糟糕。



其实还不错。



当然,我写了一个很小但不是很复杂的项目,但是Brython抛出的错误大部分是准确的并且可以理解。



至少对于语法错误而言,这是正确的。从Python库导入模块是一个完全不同的故事。



性能



图片



JavaScript Snake



图片



Brython Snake



正如预期的那样,Brython代码比JavaScript慢。就我而言,它慢了大约1.7倍。



我怀疑在更复杂的项目中,Brython将比纯JS慢几倍。



但是,您可以提前转换Brython代码,而仅在页面上使用JavaScript,这应该会更好。



实际上,我尝试使用Brython编辑器将我的Brython代码转换为JS并在网页上运行结果代码,但是由于存在大量错误,我现在已经放弃了。但是,我并没有为此付出太多努力。



关于布莱顿的最后想法



老实说,我对Brython印象深刻。根据对这种语言的经验这里有一些优点和缺点



优点



  • 我设法编写了“ Snake”而没有不必要的麻烦,并且调试经验令人惊讶地令人振奋。
  • 在我的简单项目中,Brython与页面上的本机JavaScript对象进行了无缝交互。
  • 我欣赏我的代码在Python中看起来更干净的事实,并且我也喜欢可以使用有用的Python构造来编写浏览器代码。
  • 就我的游戏而言,尽管Brython的加载速度比JavaScript慢,但用户并没有注意到这种差异。
  • 我很高兴在网站的源代码中看到Python。


缺点



  • Brighton比纯JS慢得多。
  • Brython JavaScript.
  • Brython
  • Brython .


总的来说,在完成我在Brython的第一个项目后,我可以充满信心地说我有一天会再次尝试。



但是,我认为Brython现在更适合于熟悉Python和厌倦JS的JavaScript开发人员,而不是想要在不学习JavaScript的情况下进行网络开发的Python开发人员。



我认为,对JavaScript的理解对于与Brython良好协作至关重要。而且,如果您决定花时间学习JavaScript以使您更轻松地用Brython编写代码,那么您就可以使用JavaScript。



其他浏览器JS替代品



图片



之所以选择Brython,是因为我最初了解到了大多数从Python到JS的转换选项,它是GitHub上唯一积极开发的选项。我看过的大多数Python到JavaScript的编译器都已经几年没有提交了。



但是,还有其他选择。例如,



Pyodide似乎是一个有趣的选择。它将Python(及其科学库)编译为WebAssembly,从而使其可以在浏览器中运行。



顾名思义,WebAssembly是Web的汇编程序。正如我们计算机上的汇编器可以充当高级语言和机器代码之间的中介一样,WebAssembly在网络上也可以做到这一点。



因此,可以编写将Python(或任何其他语言)翻译成WebAssembly的编译器,使其能够在浏览器中运行。



这是一个雄心勃勃且充满希望的项目,很可能会导致一个事实,那就是,我们将看到越来越多的没有JavaScript的Web开发。



但是,它仍处于起步阶段(约3年),因此可能需要一段时间才能看到JavaScript被其他语言定期替换。



在等待期间,如果您真的无法使用JavaScript,则必须使用Brython之类的工具。



但老实说,这是一个好的开始!



图片


通过参加SkillFactory的付费在线课程,了解如何从头开始或在技能和薪资水平上获得高水平职业的详细信息:











All Articles