Java/Python 導入ガイド《3》リテラル表現としての意義

記事一覧入門編基礎編応用編中級編

Java プログラマーのための Python 導入ガイド〈初級/入門編〉《Jython2.5.0》
《3》リテラル表現としての意義

《著》森こねこ・本間りす・小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第1版♪2003/05/23 ● 第2版♪2009/04/03

》作業中です《 2006年6月28日 (水)

■ 概要

Java™ Programming Language〔JPL〕の事例を使って、JavaJython との違いを学びます。

リテラル表現としての意義

 Python では、コレクションを生成するのに便利な「リテラル表現」が可能です。すると、数/文字列などの「リテラル表記」と同様に、多彩な表現が可能となります。

>>> 3,type(3)
(3, )
>>> "ABC",type("ABC")
('ABC', )
>>> 3+4j,type(3+4j)
((3+4j), )

数/文字列に限らず、任意のオブジェクトの源泉となるのが「リテラル表記」です。リテラル表記による「文字どおりの literal」式を評価するだけで、コンストラクター/メソッドを使わずに、任意のオブジェクトが得られます。このように、リテラル表記が充実していると、コードをより簡潔に表現できます。

リテラルはただの定数ではない

 Python では、括弧 [] そのものが、オブジェクトを生成する「リテラル表現」と見なせます。つまり「文字どおりの literal」式を評価するだけで得られる「オブジェクトの源泉となる表現」をプログラマーに提供します。

>>> 

空文字列をリテラル表記 "" で表現できるように、空リストを表現する括弧 [] が、オブジェクトの源泉となる「リテラル表現」となります。

>>> len(""),len([])
(0, 0)

空文字列の長さ/空リストの要素数は、ともに 0 となります。

>>> bool(""),bool([])
(False, False)

空文字列/空リストは、ともに False と等価です。そのため、if/while などに続く条件式にも指定できます。
 数/文字列の場合には、リテラル表記を使って直に情報(データ)を記述できます。リストの場合には、リテラル表現として間接的に情報が得られる式(それを評価すると任意のオブジェクトが得られるもの)を記述します。すると、次のように、

>>> 3,"ABC",[3+4,len("ABC"),"ABC".lower(),True,None]
(3, 'ABC', [7, 3, 'abc', True, None])

リテラル表現としての、リストの括弧 [] の中には、

  • 演算子 3+4
  • 関数 len("ABC")
  • メソッド "ABC".lower()

などを含む、任意の式を自由に混在できます。また、他の first-class object と同様に、リストを関数の引数/リターン値にも指定できます。

>>> map(str,[3+4,len("ABC"),"ABC".lower(),True,None])
['7', '3', 'abc', 'True', 'None']
>>> map(id,[3+4,len("ABC"),"ABC".lower(),True,None])
[25180480, 25180528, 18775104, 3118816, 3156640]

ここでは、組み込み関数 map の実引数に、リテラル表現としてのリストを指定しています。リスト内の各要素に対して、最初の例ではその文字列表現 str が、次の例ではその識別情報 id が得られます。また、他の first-class object と同様に、任意の制御構造 if/for/while との組み合わせも自由です。

>>> if [3+4,len("ABC"),"ABC".lower(),True,None]:
...     print "not empty"
... else:
...     print "empty"    
not empty
>>> for e in [3+4,len("ABC"),"ABC".lower(),True,None]:
...     print hex(id(e)),":",repr(e)
... else:
...     print "good luck"
0x1803940 : 7
0x1803970 : 3
0x11c6fa0 : 'abc'
0x2f96e0 : True
0x302aa0 : None
good luck
>>> while []:
...     print "forever"
... else:
...     print "the end"    
the end

ここまでの論議は、辞書のリテラル表現 {} についても、同様のことが成立します。

■ 純粋な OOP の世界では

 ここで注目して欲しいのは、整数/文字列などにも、オブジェクトの識別情報が与えられていることです。純粋な OOP の世界では、すべてが first-class object であり、平等の権利を持つ存在(一人前のオブジェクト)として扱われます。Java の世界では、組み込み型/true/false/null などは、オブジェクトと平等の権利を持たないので、それを補うための支援(ラッパー/ボクシングなど)が必要になります。
 純粋な OOP の世界では「リテラル」はただの定数ではありません。オブジェクトの源泉を提供する「定式化された表現」となります。

《付記》Smalltalk では、より多彩なリテラル表現が可能です。たとえば、アルゴリズム定数などの記述も容易です。Python における、今後の課題のひとつです。《ひよ子》

《リストの内包表記》

 Python では、内包を使ったリストの表現が可能です。それを説明する前に、数学の授業を思い出してください。集合を表現するには、2つの方法(外延/内包)がありました。たとえば、正の偶数を含む集合 S を表現するのに、外延では、次のように

  S = { 2, 4, ... }

括弧内に要素を列挙します。内包では、次のように

  S = { 2n | n ∈ N }  N は自然数の集合

要素を列挙するのではなく、{ 要素を表現する数式 | 定義 } という形式で表現します。リストの内包は、これとよく似ています。

>>> # {e | e in "ABC"}
>>> [e for e in "ABC"]
['A', 'B', 'C']

括弧に続く式 e は、先の「要素を表現する数式」に対応して、リストの各要素を表現する式です。その後には、for に続く変数 e の源泉が文字列 "ABC" にあることを明記します。すると、文字(長さが1の文字列)を要素とするリストが得られます。

>>> # {e.lower() | e in "ABC"}
>>> [e.lower() for e in "ABC"]
['a', 'b', 'c']

括弧に続く式 e.lower() は、リストの各要素を表現する式です。メソッド lower を適用すると、小文字を要素とするリストが得られます。

《付記》VDM++ では、内包に限らず、多彩な表現が可能です。その点ではむしろ、OOP 言語のほうが後塵を拝しているとも言えます。Ruby/Python における、今後の課題のひとつです。《ひよ子》

==================================
森こねこ 著 ◆ 監修:小泉ひよ子とタマゴ倶楽部

Last updated♪2009/08/03