どうも。ケニー(tsujikenzo)です。このシリーズでは、2023年3月から始まりました「ノンプロ研Python中級講座1期」について、全6回でお届けします。今日は4回目です。
前回のおさらい
前回は、「Day2 オブジェクトとクラス」をお届けしました。
今回は、「Day3 モジュール」をお届けします。
今日のアジェンダ
- 今週の成果物
- モジュール
- モジュールの勘どころ
- モジュールシステム
- パッケージ
今週の成果物
今週は、引き続きPandasによる、CSVデータの取り込みを行っていました。
会社の過去の業績などを、データフレームで加工することを復習していました。少しだけモジュール化にも触れています。
公開した記事はこちらです。
noteと合わせて、Day3の振り返りをしながら、プログラミング言語の考察を行っていきましょう(もう、堂々と宣言してるし。。。)
モジュール
一度プログラムを書いたら、同じ処理は再利用したいとか、部品ごとにまとめたい、という要望は、プログラミング言語設計の歴史の初期からあったようです。
すでに似たような仕組みは提供されていましたが、関連性の強い関数や変数のまとまりを明示するために「モジュール」という概念をはじめて導入したのは、1978年のModula-2言語です。
モジュールは、定義するまとまりと、それを呼び出す側で考えると分かりやすいでしょう。
//odula-2によるモジュール名の定義
MODULE SampleModule;
(* モジュールのインタフェース部 *)
//add関数は2つの数値を加算する
PROCEDURE add(x, y: INTEGER): INTEGER;
//subtract関数は2つの数値の差を求める
PROCEDURE subtract(x, y: INTEGER): INTEGER;
(* モジュールの実装部 *)
//addメソッドの実装
PROCEDUR Eadd(x, y: INTEGER): INTEGER;
BEGIN
RETURN x + y
END add;
//subtractメソッドの実装
PROCEDURE subtract(x, y: INTEGER): INTEGER;
BEGIN
RETURN x - y
END subtract;
//モジュールの終わり
END SampleModule.
呼び出し側です。
//モジュール名の定義
MODULE SampleProgram;
//他のモジュールからメソッドをインポートして使える状態にする
FROM SampleModule IMPORT add, subtract;
//変数宣言
VAR
a, b, sum, diff: INTEGER;
//ロジック部
BEGIN
a := 10;
b := 5;
sum := add(a, b);
diff := subtract(a, b);
WriteLn("Sum = ", sum);
WriteLn("Difference = ", diff);
//モジュールの終わり
END SampleProgram.
IMPORTに続く文字列は識別子ですので、メソッド名だけでなく、変数名やクラス名が設定可能です。
これは、Pythonに引き継がれている言語仕様です。
モジュールの単位はなんなのか
プログラミング言語における「モジュール」の単位は、ソースコードの組織化単位であり、1つまたは複数の関連する機能や変数、クラス、関数などを含む単位です。
では、「○○.py」や「標準モジュールやシートモジュール」のような、ファイル単位のこと?と思いたくなりますが、複数のファイルから構成するモジュールもありますので、モジュール=ファイルではありません。
各言語の技術書では、モジュールは、このように定義されています。
- 関連性の強い関数や変数のまとまり(Modula-2)
- プログラムを部品ごとにまとめる仕組み(VBA)
- アプリを機能単位に分割するためのしくみ(JavaScript)
- 複数のパッケージをまとめる単位(Java)
決して、「モジュールはソースコードが書かれたファイル単位」とは書いていません。
うまく言えませんが、プログラミング言語仕様と、ファイル仕様は別の話だからです。
モジュールが複数のファイルから構成されているばあいは、それらをパッケージとして扱うプログラミング言語が多いです。
Pythonにおけるパッケージの操作方法は、Day3で習います。(割愛します)
モジュールの勘どころ
モジュールを使って、関数、クラス、変数などをパーツ化する理由は3つあります。
- 識別子(変数や関数名)の名前のバッティングを防ぐ・・・名前空間の提供
- どこになにが書いてあるかわかりやすくする・・・可視化
- 閉じ込めて再利用する・・・定義と呼び出しを分離する
名前空間の提供や定義と呼び出しなら、関数やクラスでいいはずです。可視化なら空行とコメントでいいでしょう。
しかし、だんだん規模が大きくなり、関数や変数の数も増えてくると、それらをまとめたものが欲しくなります。
アプリケーションの規模がおおきくなり、プログラミング言語がモジュール(および、モジュールシステム)をサポートしているなら、モジュールやパッケージを利用して設計するといいでしょう。
スクリプト言語は、一般的にはスクリプト(手続き)を記述するための言語です。
しかしながら、近年(と言っても10年以上前)は、アプリ開発など多様なプログラミングが行われており、スクリプト言語でも大規模開発をしたいというニーズが増えました。
そのようなニーズに応えるため、型を指定するTypeScriptや、モジュールシステムがサポートされました。
引用元:改定3版JavaScript本格入門 山田祥寛 技術評論社
モジュールシステム
Google Apps Scriptでは、モジュールをサポートしていません。スクリプトファイルはグローバル空間を共有しており、ファイルによる名前空間を提供しておりません。
//test1.gs
function greeting() {
return "Hello,I'm Kenny";
}
//test2.gs
function myFunction() {
const message = greeting();
console.log(message); //Hello,I'm Kenny
}
JavaScriptも同様に、グローバル空間を共有していますので、複数のJSファイルが同じページに読み込まれると、デフォルトでグローバル空間(ブラウザではwindowオブジェクト、Node.jsではglobalオブジェクト)を共有します。
この問題を解決するために、ES6でモジュールシステムがサポートされました。
//sample-1.js
//関数定義
function greeting(arg="") {
return "Hello,I'm Kenny"+ arg;
}
//関数のエクスポート
module.exports = greeting;
//sample-2.js
//別ファイルでエクスポートされた関数の読み込み
const myFunction = require('./sample-1.js');
//関数の実行
console.log(myFunction()); // Hello,I'm Kenny
//関数の定義
functionmy Function2() {
console.log(myFunction("だよ"));
}
//関数の実行
myFunction2(); // Hello,I'm Kennyだよ
Google Apps Scriptは、V8化により一部のES6の機能が使えますが、まだモジュールシステムをサポートしていません。
恐らく、今後もサポートすることはないと思います。
そもそもGASは、Googleのサービスとのシームレスな統合を可能にしています。
もし、外部のモジュールをインポートしたいなら、「そういうのはライブラリでやってね」ということでしょう。
パッケージ
長くなってきました。もう終わりましょう。
Pythonでは、複数のモジュールから構成されるばあいは、パッケージとして扱うことができます。
モジュールを含むディレクトリに、init.pyファイルを含めることができるのが、特徴的です。
そして、パッケージと言えばJavaです。
Javaは、クラスやインターフェースを定義したJavaファイルを複数用意し、それらをパッケージにまとめて扱うことができます。
//SampleClass1.java
package Package1;
public class SampleClass1 {
public static void method1() {
System.out.println("Hello I'm Kenny!");
}
}
//SampleClass2.java
package Package2;
import Package1.SampleClass1;
public class SampleClass2 {
public static void main(String[] args) {
SampleClass1 sc=new SampleClass1();
sc.method1(); //Hello I'm Kenny!
}
}
パッケージを隠蔽したり公開したり、まさにザ・オブジェクト指向プログラミングです。
まとめ
以上で、 「Day3 モジュール」 をお届けしました。
モジュールとパッケージについて深堀りするということは、クロージャや関数型プログラミングにも触れたかったけど、いい加減にしました。
ノンプログラマーに必要な設計能力とは、つまりノンプログラマーアーキテクトになるには、正しい設計を選択できるスキルが必要ですね。
まだまだ道のりは長そうです。
次回は、 「ファイル操作とAPI」 をお届けします。
参考資料
- パーフェクトExcel VBA
- コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)
- 徹底攻略Java SE 11 Silver問題集[1Z0-815]対応
- 改訂3版JavaScript本格入門