[ノンプロ研Python中級講座1期]Day3 モジュール

PythonモジュールPython

どうも。ケニー(tsujikenzo)です。このシリーズでは、2023年3月から始まりました「ノンプロ研Python中級講座1期」について、全6回でお届けします。今日は4回目です。

前回のおさらい

前回は、「Day2 オブジェクトとクラス」をお届けしました。

今回は、「Day3 モジュール」をお届けします。

今日のアジェンダ

  • 今週の成果物
  • モジュール
  • モジュールの勘どころ
  • モジュールシステム
  • パッケージ

今週の成果物

今週は、引き続きPandasによる、CSVデータの取り込みを行っていました。

会社の過去の業績などを、データフレームで加工することを復習していました。少しだけモジュール化にも触れています。

公開した記事はこちらです。

#18 出納帳を分析しよう|Kenny Tsuji | 『旬北海道』北海道から世界の食卓へ
札幌でちいさな貿易商社を経営している、ケニー(tsujikenzo)です。noteでは、Tweet以上、技術ブログ未満の、アウトプットを行っています。 プログラミングや技術に関することはこちら。 技術ブログ『学習と成長のブログ』 会社や働き方についてなどの音声配信も行っております。 Podcast『北海道から世界の...

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つあります。

  1. 識別子(変数や関数名)の名前のバッティングを防ぐ・・・名前空間の提供
  2. どこになにが書いてあるかわかりやすくする・・・可視化
  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」 をお届けします。

参考資料

このシリーズの目次

  1. [ノンプロ研Python中級講座1期]受講理由と事前課題
  2. [ノンプロ研Python中級講座1期]Day1 関数と式
  3. [ノンプロ研Python中級講座1期]Day2 オブジェクトとクラス
  4. [ノンプロ研Python中級講座1期]Day3 モジュール
  5. [ノンプロ研Python中級講座1期]Day4 ファイル操作とAPI
  6. [ノンプロ研Python中級講座1期]卒業LT前編~はじめてのC++~
  7. [ノンプロ研Python中級講座1期]卒業LT中編~環境変数とPath~
  8. [ノンプロ研Python中級講座1期]卒業LT後編~Pythonの実行と正体~
タイトルとURLをコピーしました