🐍

HTMLファイル内にPythonのコードを記述するツール「PyScript」を使ってみた

2024/02/18に公開

PyScript とは

PyScriptは、Pythonのコードをhtmlファイル内に記述することで、Pythonのコードを実行できるようにするツールである。

PyScript を使ってみた

下記のようにhtmlファイル内にPythonのコードを記載することで、Pythonのコードを実行できる。
作成したhtmlファイルをブラウザを開くことで、実行結果を確認できる。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link
      rel="stylesheet"
      href="https://pyscript.net/releases/2023.11.2/core.css"
    />
    <script
      type="module"
      src="https://pyscript.net/releases/2023.11.2/core.js"
    ></script>
  </head>
  <body>
    <script type="py" terminal>
      # ここにPythonのコードを記述
      print("Hello, World!")
      print("\n")
      for i in range(10):
        print(str(i) + "こんにちは")
    </script>
  </body>
</html>

ToDo アプリを作成してみる

公式サイトのexampleを参考に、ToDo アプリを作成してみる。

1. ファイルの作成

コードを記述するためのhtmlファイルと、Pythonのコードを記述するためのmain.pyを作成した。

コード

2. Web サーバーの起動

ローカルのhtmlファイルをブラウザで開くと、main.pyを読み込むことができないため、Web サーバーを起動する必要がある。

ローカルの web サーバーを起動し、htmlファイルをブラウザで開いた。
ちなみに私は、Simple Web Serverを使用した。

3. ToDo アプリの動作確認

問題なく動作した。

メリットとデメリット

メリット

  • 簡単にPythonのコードを実行できる
  • htmlファイル内に簡単にpythonの処理を組み込むことができる。

デメリット

  • 自動コード整形との相性が悪い

    htmlファイル内にPythonのコードを記載することになるが、自動コード整形によって改行やインデントが削除されることがある。

    例えば、下記のコードは日時を取得して画面上に表示させるコードである。

    <py-script>
      from datetime import datetime now = datetime.now()
      display(now.strftime("%m/%d/%Y, %H:%M:%S"))
    </py-script>
    

    このコードを自動整形すると、下記のよう改行が削除され、正しく動作しなくなる。

    <py-script>
      from datetime import datetime now = datetime.now()
      display(now.strftime("%m/%d/%Y, %H:%M:%S"))
    </py-script>
    

    Pythonのコードは、インデントや改行も重要な意味を持つため、自動整形によって改行が削除されると、コードが正常に動作しなくなる。

    pythonのコードは別ファイルに記述し、htmlファイルから読み込むようにした方が良い。

  • 手の込んだ機能を実装しようとするとPythonのコードが複雑になり可読性が悪くなる

PyScript を使ってみての感想

  • プログラミング初学者が使用する観点

    あまりおすすめできない。

    PyScriptはプログラミング初学者にpythonの実行環境を簡単に提供することができるが、Google Colaboratoryでも同様にpythonの実行環境を提供することができる。

    Google Colaboratoryの方が、PyScriptよりも UI が良く、直感的に操作できると思う。

  • 実利用の観点

    htmlファイルにちょっとしたPythonの処理を組み込むという観点では、PyScriptは良いツールだと思う。(例: 簡単な計算など)
    しかし、簡単な計算などはJavaScriptでも実装できるため、PyScriptを使用する必要性はあまり感じない。

    また、PyScriptを使用して、本格的な web アプリを作成するという観点では、PyScriptは向いていないと思う。逆に難易度が高くなると感じた。
    Web アプリを作成する場合は、DjangoFlaskなどのフレームワークを使用した方が良いと思う。

まとめ

PyScriptは、htmlファイル内にPythonのコードを記述することで、Pythonのコードを実行できるようにするツールである。
簡単にPythonのコードを実行できるため、簡単な計算などを行う際には便利だと思うが、本格的な web アプリを作成する際には、PyScriptを使用する必要性はあまり感じない。

現時点では、使用する機会はないと思う。

ToDo アプリのコード

index.html
<!DOCTYPE html>

<html>
  <head>
    <!-- Recommended meta tags -->
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />

    <!-- PyScript CSS -->
    <link
      rel="stylesheet"
      href="https://pyscript.net/releases/2024.1.1/core.css"
    />
    <!-- CSS for examples -->
    <link rel="stylesheet" href="./assets/css/examples.css" />

    <!-- This script tag bootstraps PyScript -->
    <script
      type="module"
      src="https://pyscript.net/releases/2024.1.1/core.js"
    ></script>

    <!-- for splashscreen -->
    <style>
      #loading {
        outline: none;
        border: none;
        background: transparent;
      }
    </style>
    <script type="module">
      const loading = document.getElementById("loading");
      addEventListener("py:ready", () => loading.close());
      loading.showModal();
    </script>

    <title>Todo App</title>
    <link rel="icon" type="image/png" href="./assets/favicon.png" />

    <style>
      .line-through {
        text-decoration: line-through;
      }
    </style>
  </head>

  <body>
    <dialog id="loading">
      <h1>Loading...</h1>
    </dialog>

    <section class="pyscript">
      <main>
        <section>
          <div>
            <h1>To Do List</h1>
          </div>
          <div>
            <input id="new-task-content" type="text" />
            <button id="new-task-btn" type="submit" py-click="add_task">
              Add task
            </button>
          </div>

          <div id="list-tasks-container"></div>

          <template id="task-template">
            <section class="task py-li-element">
              <label class="flex items-center p-2">
                <input style="vertical-align: middle;" type="checkbox" />
                <p style="display: inline;"></p>
              </label>
            </section>
          </template>
        </section>
      </main>

      <script type="py" src="./main.py"></script>
    </section>
  </body>
</html>
main.py
from datetime import datetime as dt

from pyscript import document
from pyweb import pydom

tasks = []

def q(selector, root=document):
    return root.querySelector(selector)

# define the task template that will be use to render new templates to the page
# Note: We use JS element here because pydom doesn't fully support template
#       elements now
task_template = pydom.Element(q("#task-template").content.querySelector(".task"))

task_list = pydom["#list-tasks-container"][0]
new_task_content = pydom["#new-task-content"][0]


def add_task(e):
    # ignore empty task
    if not new_task_content.value:
        return None

    # create task
    task_id = f"task-{len(tasks)}"
    task = {
        "id": task_id,
        "content": new_task_content.value,
        "done": False,
        "created_at": dt.now(),
    }

    tasks.append(task)

    # add the task element to the page as new node in the list by cloning from a
    # template
    task_html = task_template.clone()
    task_html.id = task_id

    task_html_check = task_html.find("input")[0]
    task_html_content = task_html.find("p")[0]
    task_html_content._js.textContent = task["content"]
    task_list.append(task_html)

    def check_task(evt=None):
        task["done"] = not task["done"]
        task_html_content._js.classList.toggle("line-through", task["done"])

    new_task_content.value = ""
    task_html_check._js.onclick = check_task


def add_task_event(e):
    if e.key == "Enter":
        add_task(e)


new_task_content.onkeypress = add_task_event

Discussion