新しいシリーズalt.lang.jreへようこそ。このシリーズの読者であれば既にJava言語をよく知っており、クロスプラットフォームの仮想マシン(JREの一部)でJava言語がどのように実行されるかを知っていると思います。ところが、JREがJava言語の他の言語も対応できることを知っている人は少ないのではないでしょうか。JREでは(Javaプラットフォーム以前からのものを含めて)複数言語サポートの面で、Javaの経験が無い開発者が取りつきやすいような入門点を用意しているのです。また、めったにJava言語の外に迷い出たことのない開発者に対しても、「我が家」への慣れを犠牲にすることなく、他の言語の可能性を試せるような機会を用意しています。
様々な開発シナリオに対して適切な言語を選択できるということは、どんな開発者にとっても大きな強みとなりますが、特に複雑なエンタープライズ・システムに関して作業する人たちにとっては有利です。同時にJREには複数の言語に対応できるという適応性があるため、エンタープライズ開発環境としてのJavaプラットフォームの地位が、より一層確固としたものになります。
このシリーズの記事では、JREに関する代替言語として数多くの言語を調査して行きます。このシリーズで皆さんが学ぶ言語の大部分はオープンソースであり、無料で使うこともできますが、購入する必要のある商用製品も中にはあります。マシン効率よりもプログラマーの生産性を向上させるという「スクリプト」言語としての特徴を持つものが多いのですが、一般的な主流言語を移植したものである場合もあります。その全ての言語はどれもJREがサポートするものであり、また著者が見る限り、動的で柔軟というJavaプラットフォームの地位を高めるものです。
第1回目の今回はJythonに焦点を当てます。JythonはPython言語の使いやすさと、JREの持つ強力さ、柔軟性を融合させるものです。このシリーズの最初にJythonを選択した理由は、私の意見ではJREの代替言語の中で最も成熟しており、生産性も高いものの一つと考えられるためです。従ってここでのJythonの紹介では、Javaプログラミング作業においてどのような生産性向上が図れるかに焦点を当てることにします。今後の記事ではGroovyや、JRuby、Rhino、Nice、NetRexx、その他数多くのJRE用代替言語を紹介して行きます。
Python はJVM上で実行中にはPython 2.1構文とその意味体系の大部分を完全にサポートしますが、JythonはこのPythonの実装です。Jythonはインタープリター型で対話型、オブジェクト指向のプログラミング言語で100%純粋にJavaで書かれており、Javaプラットフォームと継ぎ目無く統合できます。ですからJythonを学び、使いこなすのは驚くほど簡単であり、JVMをサポートする環境であれば、(Microsoft WindowsやMac OS、大部分のUnixやLinuxを含めて)どんな環境であっても動作します。またJythonはJREが提供する全クラスとAPIを完全に利用しています。
Jythonが抜きん出て生産性が高いのは、Pythonというスクリプト言語の使いやすさと柔軟性が、Javaプラットフォームの堅牢さと合体しているという点によるものです。Jythonの構文は単純で英語風であり、また意味体系も直感的です。従ってJythonは既存のPythonプログラマーや入門レベルのプログラマー、それに非常に迅速なアプリケーション開発プラットフォームを模索しているプログラマーなどにとって理想的な言語と言うことができます。ストリングやテキストをサポートする機能があるため、テキスト処理プログラムを書くためのプラットフォームとしても素晴らしいものです。また(正規表現を含めて)ストリング操作機能や、プロシージャー機能、コンビニエンス機能などが組み込まれていることから、単純な「スクリプト」プログラムを作るための理想的な言語でもあります。
Jythonは、簡単に使い始められる点や適用性などからはVisual Basicに例えられ、また機能性を重視している点からはスクリプト言語に、強力さと信頼性ではJava言語に例えることができます。Jythonは強力で機能性を持ったプログラミング言語であると同時に、(オブジェクト指向やモジュラー化構造のおかげで)大きなアプリケーション開発にも最適な言語です。
これから先のセクションでは、強力かつ多用途なこの言語を下で支える機構を詳しく見て行きます。
Jythonの構文はライン向き(line-oriented)であり英語に似ている一方、JavaやC++などの言語の持つ構造化、オブジェクト指向プログラミング・スタイルをサポートしています。Jythonのコードは直接解釈または変換によってJavaソースとなり、自動的にクラスファイルにコンパイルされます(参考文献)。コンパイルされたJythonクラスはJythonインタープリターから独立して実行されるか、または、(例えばアプレットやサーブレットを開発するために)あたかもJavaクラスであるかのようにJavaコードから利用されます。
先ほど説明した通り、生産性の高さはJythonの最大の強みです。(Java言語と比較した)Jython独特の特徴は下記のようなものです。
- 対話モードで一行ずつコードを入力して実行できるため、学習が容易であり、実験的に使用することも簡単です。
- 変数は割り当てられた時に動的にタイプ化されるため、変数を事前宣言したり、
new演算子を使ったりする必要がありません。こうした機能強化によってプログラミングの柔軟性が大幅に向上し、またプログラムのテキストサイズも小さくなるため、生産性が向上します。 - ストリング操作が広範であり、また容易に利用できます(例えばJythonでの
x == yは、Javaでのx.equals(y)と同じ意味になります。) - アダプター・オブジェクトが自動生成され、デフォルトのJavaインターフェース実装を自動的に提供するため、イベント・ハンドラー・コールバックの実装がずっと容易になります。
- Jythonでは自然な無限精度整数値(つまりの
java.math.BigIntegerような型への単純アクセス)や自然な複素数値が使えるため、Java言語がサポートするよりもはるかに多くの数学的アプリケーションをサポートできます。 - 動的属性(各クラス・インスタンスがJava Mapのように動作する)によって、クラスの機能性がはるかに動的なものになります。
- (Java 1.5の
import staticような)インポートの機能強化によって柔軟性とモジュラー性が高まります。 - Classless で mainless(つまりオープンな)コードによって、(スクリプトのような)プロシージャー的プログラムの生産性が高まります。
- パブリックな変数やファンクション、ソースファイル毎のクラスが複数持てるため、維持管理が必要なソースファイルの数が減り、大規模な開発が単純になります。
- ファンクションやメソッドのデフォルト引き数によって、作成する必要のある多重定義のメソッド(overloaded methods)の数を減らすことができます。
- ファンクションやメソッドのキーワード引き数によって、コード自体がドキュメンテーションとなり、柔軟性が増します。
- (ファンクションがファーストクラス・オブジェクトである)機能プログラミングによって、Java言語に欠けている、強力で柔軟なプログラミング・スタイルが可能になります。
- 継承の階層構造を必要とする問題に対して、複数継承がより豊かな継承階層構造をサポートします。
- 演算子のオーバーロード(Operator overloading)によって、言語の中に継ぎ目無く統合できる、新しいデータ型を作ることができます。
このリストでJythonの持つ構造的な強みの概要が分かると思います。これから先のセクションでは、Jythonの生産性の面での強み、つまりデータ型やステートメント・タイプの元となる要素を幾つか説明して行きます。
Jythonでは多くのデータ型をサポートしています。全てがファーストクラスであり、全てがオブジェクトです。大部分はリテラル表現をサポートしているため、使い方が大幅に簡単になります。多くはJavaの型よりも使いやすく、特に集合型は使いやすくなっています。Jythonのデータ型の中で最も頻繁に使われるものを表1に示しています。
表1. Jythonのデータ型の要約
| 型 | コメント | 例 | ||
| Null | (Javaでのnullのような)未定義値。 | 無し。 | ||
| Integer(整数) | 通常の整数(Javaでのint)または長整数(JavaでのBigInteger)。 |
| ||
| Float(浮動小数点) | (Javaでのdoubleのような)分数または指数。 |
| ||
| Complex(複素数) | 複素数演算をサポートする浮動小数点の対。 |
| ||
| String | 文字の不変シーケンス。文字型はありません(代わりに一つの文字ストリングを使います)。 |
| ||
| Range(範囲) | 整数の不変シーケンス。 |
| ||
| Tuple(タプル) | (java.util.Collections.unmodifiableCollection (someList)のような)任意の型の不変シーケンス。 |
| ||
| List(リスト) | (java.util.ArrayListのような)任意の型の可変シーケンス。 |
| ||
| Map(マップ) | (java.util.Mapのような)アイテム(名前/値の対)の可変集合。名前は不変かつ唯一である必要があります。値はNoneの場合もあります。 |
| ||
| Boolean | 他の型に基づく真/偽の値。 |
偽 - 0または空。
真 - 0以外、空ではない。
| ||
| Function | 任意のクラス。クラスはクラス属性とファンクション(メソッドと呼ばれます)の名前空間です。 |
| ||
| Class | 任意のクラス。クラスはクラス属性とファンクション(メソッドと呼ばれます)の名前空間です。 |
| ||
| Module | 変数やファンクション、クラス定義などを含むソース・ファイル(と名前空間)。 | インポート可能な変数やファンクション、クラスなどを定義する任意の.pyファイル。もしこれらのどれも定義しない場合には、単にスクリプトと呼ばれます。 |
Jythonには表2に示すようなステートメントのタイプがあります。
表2. Jaythonのステートメント・タイプの要約
| ステートメント | コメント | 例 | |
| Expression | 任意の表現。表現の結果は廃棄されます。 ある結果を引き起こすためによく使用されます。 |
| |
| Assignment | ターゲットに表現を割り当てます。 |
| |
| Augmented Assignment | 表現でターゲットを更新します。 |
| |
| Unpacking Assignment | シーケンスの要素を複数ターゲット割り当てます。 タプルやリストのメンバーへのアクセスに非常に便利です。 1,2,3という表現は(1,2,3)の短縮形であることに注意して下さい。 |
| |
| Multiple Assignment | 複数ターゲットに同じ表現を割り当てます。 |
| |
| Pass | 何も操作しません。 |
| |
| If If/Else If/Elif/Else | 条件付き処理。 |
| |
| While | 条件に基づくループ。 |
| |
| For | シーケンスを繰り返す。数値シーケンスで繰り返す場合にはrangeを使用します。 |
| |
| Continue | 次のループ(while/for)の繰り返しまで進む。 |
| |
| Break | ループ(while/for)を抜ける。 |
| |
| Delete | 変数、シーケンス要素、またはクラス属性を削除する。 |
| |
| Global | グローバル値への参照を宣言します。ファンクションの中で使用します。 |
| |
| 表現をストリームに出力します。 |
| ||
| Assert | 条件が真であるとアサートする。 |
| |
| Import | モジュールの全てまたは一部をインポートする。 |
| |
| Execute | ストリング/ファイルをサブプログラムとして実行する。関連したファンクションとして、コンストラクトされたストリングを実行し、その結果を戻すexecもあります。これがサポートされているおかげで、動的にプログラムを作成することができます。 |
| |
| Try/Except | 例外ハンドラー内部でコードを実行する。 |
| |
| Try/Finally | クリーンアップ・ルーチンでコードを実行する。 |
| |
| Raise | 例外を作成し、投げます。 |
| |
| Define | ファンクションを定義します。引き数は、オプションかつ/またはキーワードです。ファンクションは汎用であり、そのため非常に柔軟なプログラミングが可能となります。 |
| |
| Return | オプション値と共にファンクションから戻ります。 |
| |
| Class | クラス(属性やメソッドのコンテナ)を定義します。 |
|
ここまでで、皆さんにはJythonの構造と構文がだんだん分かってきたはずです。それ以外の様々なことを学ぶために最適なのは、簡単かつ完全な、動作するプログラムを調べてみることです。典型的なプログラム、Hello World! から始めてみましょう。これはJythonでは次のようになります。
リスト1. JythonでのHello World!
print "Hello World!"
|
Jythonでは(Pythonの場合と同様)、ソースファイルに拡張子「py」を使います。「Hello World」ステートメントは、hello.pyのようなソースファイルに置けば、完全なプログラムになります。
比較のために、これと等価なJavaプログラムを見てみましょう。hello.javaのようなファイルとして次のようになります。
リスト2. JavaでのHello World!
public class hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
|
Jythonでの形式の方が明らかに単純ですが、これは多くの場合に言えることです。もちろん、Jythonの良いところは、コードが直接解釈または変換によってJavaソースとなり、自動的にクラスファイルにコンパイルされることです。Hello Worldプログラムは次のようなJavaコマンドを使って実行させることができます。
C:\>java -Dpython.home=C:\jython-2.1 -cp C:\jython-2.1\jython.jar
org.python.util.jython hello.py
|
あるいはもっと便利な、下記のようなJythonスクリプトを使って実行させることができます。
C:\>jython hello.py |
次に、コマンドライン引き数をエコー出力できる小さなプログラムを使って、もう少し機能的な例を試してみましょう。プログラムのエコー出力のためには、次のようなコード(echo.py)を使います。
リスト3. コマンドライン引き数をエコー出力するプログラム
import sys
count = 1
for arg in sys.argv[1:]:
print 'Argument %i=%s' % (count, arg)
count += 1
|
この完全なJythonプログラムでもJythonの重要な特徴が分かります。最初に気がつくのは、各行がステートメントであることでしょう。行の終わりにセミコロン(;)は必要ありません。また変数が宣言されないことにも気がつくでしょう。
コマンドライン引き数が、ストリングのシーケンスである組み込みのシンボルsys.argvを介してアクセスされることにも気がつくはずです。sysは有用な値やファンクションを含む標準モジュールですが、この他にも多くの標準モジュールがあります。最初のargv要素(0)はプログラム名(つまりecho.py)です。これをスキップするには、argvリストの一切れを取り去って実質的に1の位置から開始し、それからリストの最後までを繰り返します。
ループはforステートメント・グループで行われます。forの後の段付けされた行がforの本体です。printステートメントは、ストリングをフォーマットするJythonの機能(C/C++のprintfやJava 1.5のprint機能と似たものです)の使い方を示しています。
上のコードは次のように、さらに簡潔に書くこともできます。
from sys import argv for i in range(1, len(argv)): print 'Argument %i=%s' % (i, argv[i]) |
この場合ではsys.argvリストのインデックスにrangeを使っています。argv変数は直接インポートされているので、修飾は必要ありません。argvリストの長さはlenファンクションから得られ、メソッドとして得られるのではないことに注意して下さい。これはJythonの語法ですが、他の多くの言語でも共通です。他にも多くのファンクションがあります。
クラス定義の練習として、リスト4に示すキャッシュ付き階乗計算プログラムのfactorial.pyを使います。
リスト4. キャッシュ付き階乗計算プログラム
class Factorial:
''' A factorial calculator '''
seen = {} # cache of prior calculated values
def __init__ (self, value):
self.__value = value
def compute (self, value=None):
''' calculate the result '''
if value is None: value = self.__value # default
if value < 0: # bad arg!
raise ValueError, 'arg < 0'
elif value < 2: # base case
return 1L # insure long integers are used
else: # need to calculate
if not value in Factorial.seen.keys(): # not done before?
# calculate this value and cache it
Factorial.seen[value] = value * \
Factorial(value - 1).compute()
return Factorial.seen[value] # get value from the cache
|
ここではJythonの新しい機能を数多く見ることができます。まず最初に、コメントはシャープ(#)記号で始めます。クラスやメソッドは最初の行にドキュメンテーションのコメント文字列(JavaDocが使われるのと同様な方法で、ツールが処理します)を持つことができます。ステートメントはその役割での出番以外に、キーワードによっても使われます。クラスとメソッドの本体は区切り記号では囲まず、段下げすることによって示します。
さらに、クラスはclassステートメントで宣言します。defステートメントはメソッドを導入します。クラス属性はクラス内での役割によって作られますが、インスタンス属性はコンストラクター・メソッド__init__内での役割によって作られます。seen変数はディクショナリ(dictionary)です。インスタンスはファンクションとしてクラス・オブジェクトを呼ぶことによって作られます。メソッドは(Javaの場合と同じように)ドット( . )演算子で呼び出されます。
self変数は(Javaでのthisのように)メソッドの受け取り側であることにも注意して下さい。メソッド内では、インスタンス属性やクラスのメソッドへの参照は全て、selfで修飾されている必要があります。クラス変数は(Javaでの場合のように)クラス名で修飾されます。
ファンクションには、computeファンクションのvalue引き数で示すようにデフォルトの引き数がある場合があります。パラメーターの値が省略されると、__valueインスタンス属性が使われます。
ここまでの説明で、構文は少し違っていてもJythonがJava言語の機能を全てサポートしていることが明確に分かるでしょう。例えばJythonのraiseステートメントはJava言語のthrowステートメントと同じです。
次のコードを使ってFactorialクラスをテストすることができます。これはfactorial.pyファイル(参考文献)の中にも入っています。
if __name__ == "__main__":
from sys import argv
if len(argv) == 1: vals = range(10)
elif len(argv) == 2: vals = range(int(argv[1]))
elif len(argv) == 3: vals = range(int(argv[1]), int(argv[2]))
else: print " Incorrect range"; vals = ()
for i in vals:
print "Factorial(%i)=%i" % (i, Factorial(i).compute())
print "Cache:", Factorial.seen
|
Jythonではクラス定義とテストケースを組み合わせることができます。上のif __name__...テストでは、このファイルがコマンドとして実行される時にのみテストケースのコードが実行されます。テストケースを実行せずにFactorialクラスを再利用するために、このファイルを別のファイルでインポートすることもできます。テストケースは幾つかのコマンド引き数処理から成り、その後に、指定された値がある時にはその階乗を計算するループが続いています。最後に値のキャッシュが出力されます。jython factorial.py 5 10コマンドで次のような出力が得られます。
Factorial(5)=120
Factorial(6)=720
Factorial(7)=5040
Factorial(8)=40320
Factorial(9)=362880
Cache: {9: 362880L, 8: 40320L, 7: 5040L, 6: 720L, 5: 120L, 4: 24L, 3: 6L, 2: 2L}
|
上の例では、Jythonの長整数型(###L)を使って不定長の整数が計算できることにも気が付くでしょう。
最後に、GUIを作る、もっと複雑なプログラムでJythonの紹介を終わりたいと思います。単純なAWTベースのアプリケーションを検討してみれば、JavaコードからJythonを呼ぶことができること、またJythonがJavaプラットフォームの全機能にアクセスできることがすぐに分かるでしょう。
初めに、Scribbleと呼ぶJavaのPanelサブクラスであるGUIを作ります(リスト5)。後で、このPanelを表示するFrameを作ります。
リスト5. クラスScribbleはJavaのPanelのサブクラス
from java.awt import BorderLayout as BL, Color, Button, Panel
class Scribble(Panel):
""" A simple GUI example """
def __init__ (self): # constructor
Panel.__init__(self, BL())
self.add(Button('Clear', actionPerformed=self.doClear),
BL.SOUTH)
self.mouseDragged = self.doDrag
self.mousePressed = self.doPress
self.__last = 0, 0
def doClear (self, event):
""" clear background """
g = self.graphics
g.color = self.background
g.fillRect(0, 0, self.size.width, self.size.height)
def doDrag (self, event):
""" draw line from last to here """
g = self.graphics
g.color = Color.black
lx, ly = self.__last
x = event.x; y = event.y
g.drawLine(lx, ly, x, y) # draw new line segment
self.__last = x, y # save coordinates
def doPress (self, event):
""" save click point """
self.__last = event.x, event.y
if __name__ == "__main__":
def doClose (event):
import sys
sys.exit()
from java.awt import Frame
frame = Frame("Scribble", windowClosing=doClose)
frame.add( Scribble() )
frame.size = 400, 300
frame.visible = 1
|
多分リスト5のコードを見て皆さんが最初に気がつくのは、セミコロンを区切りとして幾つものステートメントが1行の中に置かれていることでしょう。行はカンマの後に続けることができます。importステートメントは複数のクラスをインポートでき、またオプションでそれらをリネームすることもできます。importは実行可能ステートメントなので必要なところに置くことができ、不必要なシンボルのインポートを避けることができます。ネストされたdoCloseファンクションに注意して下さい。また宣言が無いこと、クラス・インスタンスを作る時に新しい演算子が無いことにも注意して下さい。
self.__lastインスタンス属性(これは2つの下線(double underscore)で始まるので、プライベート属性です)は、前回のマウス・クリック位置を保持しています。マウス・ドラッグのイベントが起きる度に、保持されている点とイベントの起きた点との間に、黒い線(非常に短い場合もあります)が引かれます。
イベント・ハンドラーがどのように定義されているかにも注意して下さい。Listenerインターフェースは何も使われておらず、代わりにクラス(例えばactionPerformed)が定義する、面白いイベント・ハンドラー・エントリー・ポイントに一致する属性がJythonのファンクションに設定されています。もう一方の、使っていないエントリー・ポイントがある場合には、そのエントリー・ポイントは自動的に空のファンクションにマップされるので、Adapterクラスを使う必要がありません。また、Javaオブジェクト(例えばGraphicsオブジェクトg)のJavaBeansオブジェクト・プロパティはどれもJythonプロパティとしてアクセスされ、get/setメソッドからアクセスされるのではないことにも注意して下さい。これによってコーディングが大幅に単純化されます。ただし、もし使いたければ相変わらずget/setメソッドを使うこともできます。
図1はScribble GUIを実際に使っているところの例です。
図1. Scribble GUIの例
PropylonのCTO(最高技術責任者)であり、数多くの著作のあるSean McGrathはJythonを、大会社の後ろ盾が無いにもかかわらず「恐ろしいほどの素晴らしいJava生産性向上ツール」だと言っています。また「21世紀に生き延びるためにJavaプラットフォームが持ち得た最強の武器」とも表現しています。alt.lang.jreの最初である今回の記事では、JythonがJavaプラットフォームでの開発にもたらす使いやすさや、効率の良さを見てきました。また、簡単にですが、Javaプラットフォームの将来のために複数言語のサポートが重要であることに関しても説明を始めました。
Jythonについては他にも沢山言うことがあるのですが、それを全部言っていると本が一冊書けてしまうでしょう。下記の参考文献を見て、強力で使いやすいこの言語について、より深く学んで下さい。
- 2回構成の「Introduction to Jython」チュートリアル(developerWorks, 2003年5月)は、さらに詳しくJythonを学ぶための足がかりとして最適です。
-
Jython homepageからJythonをダウンロードして、ファイルのコンパイルに関して学んで下さい。
- Javaランタイム環境を含めて最新版のJDKをSun Java technology home pageからダウンロードして下さい。
- Uche Ogbujiによる「魅力的なJython」(developerWorks, 2003年5月)では、Jythonを手短に、また実際的に紹介しています。
- Michael Nadelによる最近の記事「Use Jython to build JUnit test suites」(developerWorks, 2004年5月)では、Javaプラットフォームで複雑なタスクを実行する上でJythonを使うことによって生産性がいかに改善されるかを、実際に動作する例を挙げて説明しています。
- Victor Yangによる「Learn how to write DB2 JDBC tools in Jython」(developerWorks, 2004年4月)もタスク実行の面からJythonの力を探っています。DB2のJDBCプログラミングがJythonでいかに簡単になるかを自分自身の目で確かめてみて下さい。
- Samuele PedroniとNoel RappinによるJython Essentials(2002年3月O'Reilly刊)は一冊の本の形で、しっかりとJythonを紹介しています。
-
Jython for Java Programmers(2001年12月New Riders刊)はJythonでのアプリケーション開発や開発、そして最適化に焦点を当てています。
- Jythonの先輩Pythonを学ぶことによってJythonの多くを知ることができます。まず手始めにPython home pageを見てみて下さい。
- JythonやJavaプラットフォーム、その他の開発技術に関するSean McGrathの考え方は、頻繁に更新されているblogspotで見ることができます。
-
Developer Bookstoreには豊富なJava関連の書籍を含めて広範囲な話題の技術書が取り揃えられています。
- developerWorksのJava technologyゾーンには、Javaプログラミングのあらゆる面に関する記事が豊富に用意されています。

Barry Feigenbaum博士はIBM Worldwide Accessibility Centerのメンバーです。ここでは障害を持った人たちにIBM製品を使いやすいものにするための努力が続けられています。Feigenbaum博士はJavaOne 2004で展示されたBlueSpaceウォールディスプレイ・プロジェクトの開発チームのリーダーです。技術書や記事を執筆しており、いくつかの特許も持っています。またJavaOneのような業界での会議でも発言しています。テキサス州オースチンにあるテキサス大学にて、コンピューター・サイエンスの非常勤助教授を務めています。連絡先はfeigenba@us.ibm.comです。