MicroPythonとPython、その違いとは?

(画像提供:Quality Stock Arts - stock.adobe.com)
MicroPythonによるプログラミングの最大の魅力の1つは、20年近くにわたりデスクトップ環境で広く使われているCPythonと似ていることです。構文と設計パラダイムがほぼ同じであるため、組み込み開発環境とデスクトップ開発環境との間をほぼシームレスに移行できます。これは、モバイル、デスクトップ、クラウドなど、さまざまなプラットフォームから組み込み電子機器のデータにアクセスすることが求められるIoT時代には、非常に望ましいことです。ツールやプログラミング言語の種類が少なければ、開発要員数を抑え、製品開発サイクルを短縮することができます。とはいえ、組み込みハードウェア環境の性質上、デスクトップと比較して、MicroPythonとCPythonの間には少なからず違いがあることに注意しておく必要があります。
組み込み電子機器のエコシステムには、デスクトップやサーバーにはない多くの制約があります。まず第一に、消費電力による制約です。組み込み機器はその多くがバッテリ駆動ですが、バッテリ寿命の延長にはパフォーマンス面で限界があります。デスクトップコンピュータは数ギガヘルツで動作するのに対し、マイコンの動作速度はせいぜい数十メガヘルツです。また、メモリとストレージの制約もCPythonとMicroPythonとの差を大きく広げる制限要因となることがあります。メモリはわずかキロバイトかメガバイト単位なので、メモリ負荷のかかる機能はMicroPython実装では削減されたり、完全に削除されることも珍しくありません。このような違いを知っておくことは、組み込みコードのデバッグに長時間を取られないためにも重要です。以下、開発者が知っておくべき重要な違いについて説明したいと思います。
- CPython開発者は、何百ものビルド済みモジュールを利用することができ、モジュールはコード1行で簡単にプロジェクトに追加できます。これらのモジュールにより、機能をプロジェクトに追加したいときも始めからやり直す必要はありません。ただし、モジュールの多くはメモリの使用量が非常に大きくなる可能性があります。MicroPythonはモジュールをなくすか、組み込みプラットフォーム向けにカスタマイズされたモジュールの実装を提供します。また、汎用I/O (GPIO) ピンとのインターフェイスなど、組み込みプラットフォームに特化したモジュールもあります。
- CPythonは自動参照カウント (ARC) というメモリ管理方式を採用していますが、MicroPythonはガベージコレクション方式を採用しています。具体的には、MicroPythonはメモリが割り当てられるとき、ヒープ上に十分な大きさのメモリのチャンクを見つけようとします。これに失敗すると、MicroPythonは未使用または冗長なオブジェクトの割り当てを解除しようとします。これは通常ミリ秒単位の処理です。または、開発者はgc.collect()を時々実行して、一定の間隔でメモリをクリーンアップすることで、コードの重要なセクションでガベージコレクションが発生しないようにすることができます。
- 構文の違いには、おそらくほとんどの開発者が悩まされています。特にCPythonの経験が豊富で、プラグラミングを体で覚えている開発者ほどそうでしょう。
- MicroPythonでは数値とキーワードの間にスペースが必要ですが、CPythonでは不要です。
- MicroPythonでは内包表記の変数に := を使って代入できますが、CPython では構文エラーになります。
- 初心者のプログラマーにとってPythonの親しみやすい特徴の1つは、データ型 (整数、ブール値、浮動小数点数など) の取り扱い方です。Pythonでは、すべてのデータ型はクラスであり、変数はクラスのインスタンスです。しかし、MicroPythonはCPythonのオブジェクトデータモデルを全て実装しているわけではありません。注意すべき相違点には、多重継承ができない、__new__と__del__の特殊メソッドが機能しない場合がある、メソッド解決順序 (MRO) が異なる、メタクラスがサポートされていない、などがあります。
- MicroPythonには例外の連鎖は実装されていません。ですからMicroPythonはプログラムの異なる抽象化レイヤー間で例外を再スローすることはできません。
- 組み込み型の処理が異なります。例えば、MicroPythonでは配列の削除をサポートしていません。
- Pythonでは、関数はオブジェクトであり、関数呼び出しでアクセスできる定義された属性セットを持っています。例えば、すべての関数は組み込み属性 __doc__ を持っており、関数のソース コードで定義された docstring を返します。関数のユーザー定義属性は、CPython では可能ですが、MicroPython ではサポートされていません。これは、組み込みシステムによくあるメモリの制限のためです。
- sys.stdin、sys.stdout、sys.stderrをオーバーライドすることはできません。これらは標準入力、標準出力、標準エラーにインタプリタが使用するファイルオブジェクトです。ユーザーにテキストを表示したり、ユーザーから入力を受け取る方法です。
- ロードに失敗したモジュールも、ロード済みとして登録されます。これはモジュール処理をより効率的にするためです。したがって、ロードは例外処理でラップされません。本番環境にデプロイする前に、必ず開発環境でコードをテストするようにしてください。
- 環境属性は実装されていません。したがって、開発者は getenv()、utenv()、nsetenv() メソッドを使用して環境変数を設定し、取得する必要があります。なお、getenv()メソッドに渡す引数は1つだけです。
- print()関数は、CPythonと同じ方法で再帰的なデータ構造 (再帰的なリストなど) を確認しません。MicroPythonはスタックの使用状況を確認するので、再帰的なデータ構造をプリントしてもスタックオーバーフローでクラッシュすることはありません。
- MicroPythonは、"self"を引数としてカウントするので、メソッドのエラーメッセージに予期せぬ引数の数が表示されることがあります。エラーメッセージを処理する際は、このことに注意してください。
- JSON (JavaScript Object Notation) は、クラウドと効率的に通信するために多くの IoT エンド デバイスで使用されている一般的なデータ交換フォーマットです。MicroPythonのJSON モジュールは、JSON オブジェクトがシリアライズ可能でない場合、例外をスローしません。
- structモジュールは、Pythonの値とPythonバイトオブジェクトとして表されるC構造体との間の変換を実行します。これにより、ファイルに格納されたバイナリデータや、センサで一般的に使用されるネットワーク接続およびシリアルプロトコルからのバイナリデータを効率的に処理することができます。残念ながら、 struct.pack(format, v1, v2) 関数は、正しい数の引数が与えられていることを確認しません。これに対し、CPython実装では引数の数を確認します。
- 配列内の整数を検索する機能は実装されていません。そのため、以下のコードはエラーになります。 CPythonはfalseを表示しますが、MicroPythonはnot implementedエラーメッセージを返します。
import array as array
a = array.array('i', [1, 2, 3, 4])
print(1 in a) - MicroPythonは、組み込みアプリケーション開発のための強力で使いやすいプログラミング言語です。ただし、デスクトップやクラウドアプリケーションに使用される機能豊富なPython実装に比べ、制約があります。MicroPythonの将来のバージョンでその違いは、改善されるかもしれませんが、 Python のリファレンス実装に新しい機能が追加されれば、また新しい違いが生じる可能性があります。CPythonとMicroPythonの最新の相違点を確認するには、MicroPythonのウェブサイトで公式ドキュメントを確認するようにしてください。