2010年1月 9日

Perlにおけるモジュールとパッケージの関係

Perlで分かりづらい概念の一つに「モジュール」と「パッケージ」の関係が挙げられます。ようやく最近理解できてきた様な気がするので、以下にそのメモを。

例として、以下の様なスクリプト本体とモジュールが有ったとします。

/usr/local/bin/script.pl

#!/usr/local/bin/perl

use strict;
use warnings;

require Some::Module;

my $value = Some::Module::func();

print "$value\n";
/usr/local/lib/perl5/site_perl/5.10.1/Some/Module.pm
package Some::Module;

use strict;
use warnings;

sub func {
  return localtime;
}

1;

script.plの中で「require Some::Module;」と記述する事で、「/usr/local/lib/perl5/site_perl/5.10.1/Some/Module.pm」というモジュールが"実行"されます。このモジュールの中には、"func"というサブルーチンの定義だけが書かれているので、この段階では特にサブルーチンの中のコードが"実行"される事は有りません。定義されるだけです。

「/usr/local/lib/perl5/site_perl/5.10.1/Some/Module.pm」の中には「package Some::Module;」という記述が有る事で、「Some::Module」というパッケージ名が定義されます(名前空間と考えると分かりやすいですね)。このパッケージ名が定義された事で、「script.pl」の中からSome::Moduleの中に有るfuncという関数が呼び出す事が出来る様になるのです。

そう、重要なのはrequireにより呼び出された時に、モジュールは"実行される"という事です。モジュールの中のコードが実行される事でパッケージ名が"初めて"定義されるのです。つまり、requireするまではSome::Moduleというパッケージ名は存在しないのです。

パッケージ名が定義されていないのに、なぜ「require Some::Module;」と書けるのか?ここが最も理解しづらいポイントでした。

実は、ここで記述している"Some::Module"はパッケージ名を記述しているのではなく、単にモジュールファイルのパス名を記述しているだけなのです。だから、「require Some::Module;」と書けるのです。

Perlではrequireで指定されている「Some::Module」をライブラリの検索対象のパス配下に有る(この例では「/usr/local/lib/perl5/site_perl/5.10.1/」)、「Some/Module.pm」というファイルを探して実行しろ、と解釈しているのです。

module_path

Perlでは、モジュールを配置するパス名+ファイル名と、パッケージ名を一致させる習慣になっています。そうしないと、そのパッケージ名がどのモジュールで定義された物なのか分かりづらいですからね。

逆に言うと、requireとpakageのそれぞれにまったく同じ文字列(この例ではSome::Module)が書かれているのに、それらは全然違う事を意図しているので、凄く混乱し易いのです(requireの後ろはパス名、packageの後ろはパッケージ名)。図に整理するとこんな感じになります。

module_package.png

パッケージの階層と呼び出す時のPATHがきちんと整合している事を確認しましょう。

修正2010/2/26

誤り例が誤りという情けない指摘をいただきました。ひとまずさっくり書き直したのですが、Perl To The Peopleへ移す時にもう少しちゃんと考え直します。

トラックバックURL

このエントリーのトラックバックURL:
http://ash.roova.jp/mt/mt-tb.cgi/36

コメント[2]

最後の箇所で、パッケージの指定方法
package Module;
には問題はないはずです。

>一番よくやる間違いは、パッケージ名にモジュールのファイル名を記述してしまう事です。

これは、名前空間をパッケージ名にしているので
その場合、呼出側のPATH指定に問題がある。。の間違いじゃないでしょうか。逆に混乱をまねいてしまいます^^;


ご指摘ありがとうございます。確かにPATH名が間違っている、パターンですね。修正します。

コメントする