はじめに
本連載の初回は、プログラミング歴6か月の本間が担当します。初心者の皆さんと同じ立場から記述しますので、よろしくお願いします。
Java meet Python。そして、Jythonが産まれました。Jythonでは、JavaBeansに準拠するJavaのリソースを再利用するときに、便利な機能を提供します。今回は、一粒で二度美味しい、Jythonの魅力(旨味)を紹介します。
対象読者
こんな症状を抱えているなら……。
- JavaBeansに準拠した既存の資産(負債?)は今後も運用したい。
- しかし、そのメンテナンスには多大な費用が掛かる。
- Javaの開発効率の悪さにストレスが溜まる。
JavaBeans:値の獲得と設定
JavaBeansでは、ある特性を獲得/設定するためのプロトコルとして、それぞれ、getter/setterメソッドと呼ばれるものを規定しています。
public class NameBeans { private String name; public Beans() { this.name = "John"; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } }
Javaで記述したクラスNameBeans
には、String
型の特性name
を定義しています。これに伴い、その値を獲得するメソッドgetName
と、その値を設定するメソッドsetName
が定義されます。このとき、get/setに続く名前は大文字で始めます。また、getメソッドのリターン値と、setメソッドの引数とは、同じ型になります。
Javaモジュールを取り込むには
>>> import NameBeans
Javaで記述したモジュールを取り込むには、import
を利用します。すると、クラスファイルNameBeans.classの情報に、Jythonからアクセスできます。
>>> dir(NameBeans) ['getName', 'name', 'setName']
組み込み関数dir
を使って、クラスNameBeans
に固有の情報を調べると、メソッドgetName
/setName
が定義されているのが分かります。
>>> dir(NameBeans()) ['__init__', 'class', 'equals', 'getClass', 'getName', 'hashCode', 'name', 'notify', 'notifyAll', 'setName', 'toString', 'wait']
クラスNameBeans
のインスタンスに固有の情報を調べると、先に加えて、親クラスObject
から継承したメソッドgetClass
なども含まれるのが分かります。
NameBeans
はクラスオブジェクトを、式NameBeans()
はインスタンスオブジェクトを、それぞれ参照します。クラス/インスタンスに共通の概念モデルを持つ、その世界の住人だけに許された特権と言えます。洗練されたOOPの世界では、もうJavaの常識は通用しません。Introspectorを使って
from java.beans import Introspector def properties(bean): info = Introspector.getBeanInfo(bean) return [e.name for e in info.propertyDescriptors] >>> properties(NameBeans) ['class', 'name']
パッケージjava.beansを利用すると、JavaBeansに準拠する情報が得られます。ここでは、クラスNameBeans
に固有の特性name
のほかに、親クラスObject
で定義されたメソッドgetClass
から類推される、特性class
が得られます。
JavaBeansの属性にアクセスする
>>> bean = NameBeans() >>> bean.name John
Jythonでは、Pythonのスタイルを併用できます。メソッドgetName
を使わなくても、属性名name
を使って、Javaで記述した特性値を獲得できます。
>>> bean.name += " Doe" >>> bean.name John Doe
同様に、メソッドsetName
を使わなくても、代入演算子+=
を使って、新しい値を設定できます。これは、bean.name=bean.name+"Doe"
と等価です。Javaのスタイルを踏襲して、getter/setterを使った式bean.setName(bean.getName()+"Doe")
と比べて、簡潔で見通しのよいコードを記述できます。
>>> bean = NameBeans(name="Jane Doe") >>> bean.name Jane Doe
さらに、キーワード引数name=
を使うと、メソッド呼び出しsetName()
と同じ効果が得られます。ただし、この方法は、コンストラクタ呼び出しには適用できますが、通常のメソッド呼び出しには適用できません。