新技術 PyScriptを解説! jQueryとの違い、使ってみた感想など
2022.06.16
現代のWebアプリのフロントエンド開発において、JavaScriptやそのライブラリであるjQueryの存在は無視できません。フロントエンドのスクリプト言語として、絶大な地位を確立しています。しかし、私の願望が多分に入っていますが、もしかしたらその状況が変わるかもしれません。
2022年5月にAnaconda社よりブラウザでPythonが実行できるPyScript がリリースされました。この記事では、リリースされたばかりのPyScriptについてまとめました。
はじめに
2022年5月にPythonの主要なディストリビューションである「Anaconda」などを提供しているAnaconda社から「PyScript」がオープンソースで公開されました。PyScriptはHTMLにPythonを記述し、実行できます。つまり、ブラウザ上でPythonが実行できるようになるのです。今回は、このPyScriptについて解説します!
記事前半ではPyScriptの実装例を、後半ではjQueryとの比較をお伝えするので、是非じっくりとご覧ください。
PyScript(パイスクリプト)とは?
まず、PyScriptの概要についてお伝えします。
PyScriptとはオープンソースのHTMLの中でPythonを記述し、実行できるライブラリです。Anaconda社により開発されています。PyScriptには以下のような特徴があります。
このような特徴から、現在のフロントエンド開発でJavaScript、jQueryが主流な状況に変化が現れる可能性があり、フロントエンドからバックエンドまですべてPythonでWebアプリ開発という選択肢が出てきそうです。
なお、現在PyScriptはアルファ版であることから、本番環境での利用は非推奨となっていますのでご注意ください。
PyScriptの実例
今回、PyScriptを実際に利用してみるために、以下の環境でPythonのWebアプリフレームワークであるFlaskを用いて、簡単なWebアプリを作成します。
環境構築
Flaskを以下のコマンドでインストールします。
$ pip install Flask
インストールが完了したら、以下のコマンドでバージョンが表示されたら正常にインストールできています。
$ flask --version Python 3.10.0 Flask 2.1.2 Werkzeug 2.1.2
公式のチュートリアルに沿ってページの表示させてみます。
hello.pyを作成し、以下のコードを実装します。
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>"
次に、以下のコマンドによりFlaskを起動させます。(-h オプションはホストの指定、-p オプションはポート番号を指定できます。今回は、Virtual Box上の仮想マシンに環境を構築し、ホストマシンからアクセスするためかつ私の開発環境の都合により設定しています。)
$ export FLASK_APP=hello $ flask run -h 0.0.0.0 -p 8000
ブラウザでhttp://localhost:8000/にアクセスして、以下のページが表示されたら成功です。
これで、PyScriptを試してみる環境が構築できたので、さっそく新機能のPyScriptを実際に触っていきましょう。
同じ機能をPyScriptとjQueryそれぞれで実装、比較
まずは、簡単なコードから試していきます。sample_pyscript.py以下のような実装をしました。
from flask import Flask, render_template app = Flask(__name__) @app.route('/sample/') @app.route('/sample/<name>') def sample(name=None): return render_template('sample.html', name=name)
また、templates/sample.htmlのコードは以下の通りです。
<!doctype html> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <py-script> if '{{ name }}': name: str = '{{ name }}' print(f'Hello {name}!') else: print('Hello World!') </py-script>
JavaScriptやjQueryでは<>内にコードを記述しましたが、PyScriptでは<py-script>内にPythonコードを記述します。
http://localhost:8000/sample/にアクセスすると、以下のように表示されました。
また、http://localhost:8000/sample/jigsaw/にアクセスすると、以下のように表示されました。
ブラウザ上でPythonコードが動いています。感動です。
次に、同一の機能を持つページをPyScriptとjQueryの両方で実装してみます。
まずは、サーバ側を実装します。さきほどの、sample_pyscript.pyに以下を追加します。
@app.route('/sample_pyscript/') def sample_pyscript(): return render_template('sample_pyscript.html') @app.route('/sample_jquery/') def sample_jquery(): return render_template('sample_jquery.html')
入力フォームに入力したMarkdownのプレビューのモーダルを表示させる機能を持ったページを実装します。
sample_jquery.html、sample_pyscript.htmlのHTMLは共通で以下の通りです。
<!doctype html> <html> <body> <div class="card"> <div class="card-header"> <b>Test App</b> </div> <div class="card-body"> <div class="row"> <div class="col-auto"></div> <div class="col-6"> <input type="text" id="text" class="form-control"> </div> <div class="col-auto"></div> </div> </div> <div class="card-footer"> <div class="pull-right"> <button type="button" id="preview-btn" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#previewModalLabel">Preview</button> </div> </div> </div> <div class="modal fade" id="previewModalLabel" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="previewModalLabel">Preview</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div id="text-in-modal" class="modal-body"></div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </div> </div> </div> </div> </body> </html>
jQueryでの処理部分は、以下のような実装です。(今回、見栄えの面からBootstrap5を使用しています。)
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> $('#preview-btn').on('click', function () { var text = $('#text').val(); $('#text-in-modal').text(text); }); </script>
「Preview」ボタンをクリックすると、入力フォームから値を取得してプレビューモーダルへ挿入するという処理をおこなっています。
同様の処理をPyscriptで実装すると、以下の通りです。
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <py-script> from typing import Any def show_text(*args: Any, **kws: Any) -> None: text: str = Element('text').element.value pyscript.write('text-in-modal', text) </py-script>
2つのページへブラウザからアクセスして操作すると、以下の画像のように、実装できています。
[jQueryで実装したページ(http://localhost:8000/sample_jquery)]
[PyScriptで実装したページ(http://localhost:8000/sample_pyscript)]
さらに拡張して、入力フォームにMarkdownを入力するとモーダルでプレビューが見れるようにします。
sample_jquery.htmlのコードを以下のように修正します。
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <!-- Markdownのパースにmarked.jsを使用します。 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.16/marked.min.js" integrity="sha512-8d9aScHpB0kf4+i5O3JlEP6VfvvjYYyZXa71ZKq0CzytOfDcH8d4Iej33s/0nNDcqWHhdDuAZKjA2y2qXzvJZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> $('#preview-btn').on('click', function () { var text = $('#text').val(); var html = marked.parse(text); // <= 取得した値をパースします $('#text-in-modal').html(html); }); </script>
sample_pyscript.htmlのコードも以下のように修正します。(ライブラリmarkdownをpipインストールする必要があります。)
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" /> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script defer src="https://pyscript.net/alpha/pyscript.js"></script> <!-- 標準ライブラリ以外は、py-envタグに記述する必要があります。 --> <py-env> - markdown </py-env> <py-script> from markdown import markdown from typing import Any def show_text(*args: Any, **kws: Any) -> None: text: str = Element('text').element.value html: str = markdown(text) # <= 取得した値をパースします pyscript.write('text-in-modal', html) </py-script>
それぞれの結果は以下の通りです。
PyScript |
---|
jQuery |
---|
PyScriptのほうは、うまくいっていないようです。開発者モードでは、両者に差はないように見えますが、残念ながら原因はわかっていません。
PyScript |
---|
jQuery |
---|
PyScriptとjQueryの比較
前章では、同じ機能をjQueryとPyScriptそれぞれで実装しました。この章では、具体的な比較や実装段階での気づいた点などについてまとめていきます。
HTML要素からの値の取得
前章で作成したコードでは、HTMLの要素からの値の取得を以下のように実装しています。
PyScript | jQuery |
---|---|
text: str = Element(‘text’).element.value | var text = $(‘#text’).val(); |
要素のIDを指定して値を取得していますが、両者で大きな違いはありません。ただし、現在のところ、PyScriptではIDを指定することしかできません。
HTML要素の値の更新
こちらについても、両者で大きな違いはありません。またこちらについても、現在のところ、PyScriptではIDを指定することしかできません。
PyScript | jQuery |
---|---|
pyscript.write(‘text-in-modal’, text) | $(‘#text-in-modal’).text(text); |
PyScriptのpyscript.write()では、いかのように引数append=Trueを指定することで、値の更新ではなく、追加を行うことが可能です。
pyscript.write('text-in-modal', text, append=True)
その他、気づいた点などは以下の通りです。
まとめ
今回は、2022年5月に公開された新機能PyScriptを実際に使ってみて、現在私が開発業務で使用しているjQueryと比較してみました。まだ、PyScriptはアルファ版であるため、いろいろな点がデメリットとしてあります。また、公式としても本番環境での使用を推奨していません。
しかし、筆者はシンプルで可読性の高く、データ処理や分析のライブラリが充実しているPythonがフロントエンドで使用できるPyScriptに非常に大きな期待をもっています。今後、パフォーマンス改善や機能の追加がおこなわれ、ライブラリも充実していき、PythonのみでWebアプリケーション開発という選択肢ができることを期待しています。