P-1 目的のためにはスタイルを選ばず
〜「ちょー」高級言語は伊達じゃない〜
Pythonは「超高級言語」を自認するプログラミング(スクリプト)
言語です。
低級言語、高級言語はよく聞いたことがあるでしょうが、「超高
級言語(VHLL Very High Level Language)」って一体なんでしょうか?
順当に考えれば、低級言語から高級言語に引いた直線の延長上に
あるもの、となるのでしょう。
低級か高級かの差は、価格の違いにあり・・・・・ません(もし
そうなら、フリーウェアのPythonは、どう考えても最低級言語にな
るはずですから)
低級/高級の差は、ご存知の通り、いかに「マシンに近い(低
級)」か、「人間に近い(高級)」かを示します。
つまり、マシンや吐き出すコードのことに細かく配慮できる(い
や、しなくてはならない、かな?)言語が低級言語で、そんなもの
にお構いなしで、自分の考えをダイレクトに記述できるのが高級言
語、ということになるかと思います。
<閑話休題>
正統Pascalと、Delphiの記述言語ObjectPascalでは、ObjectPascal
のほうがより低級、という一見不思議な現象が起こっています。C++
に比肩しうる言語としてPascalをチューニングするには、より低級
な側面も必要だったのでしょうか・・・ちなみに、Delphi信奉者は
ObjectPascalをVisualBasic並に簡単だ、とか言ってますが、ある面、
C++より難しいです、コレ・・・
</閑話休題>
たとえば、宣言文というものがありますが、これは「マシンがそ
の変数/関数/型などをどう扱うか」を決めるためと、「人間が間
違えないように、名前をつける」ためとの両面の性質があります
(というか、Pascal(Algol60?)以降「そうなった、とでも言うべき
でしょうか)
低級言語の宣言文は前者の目的で行い、高級言語は前者又は後者
の目的で行います。
となると「マシンが同扱うか(実装)はどうでもいい。区別のた
めにのみ宣言は必要」という態度こそが「超高級言語流」となるで
しょう。
で・・・Pythonは、実際そうだったりします。
変数宣言が代入で済まされることは言うに及ばず、ローカル/グ
ローバルの違いも、「クラスや関数宣言の外で代入されればグロー
バル」「クラスや関数宣言の中で代入されればローカル」という、
非常にシンプルなルールがあるだけです(globalキーワードを使え
ば、クラスや関数の中からでもグローバル変数を宣言、代入できま
す)
Pythonは、徹底的に「超高級」ブランドを維持するため、ありと
あらゆる手段を尽くしています(実行速度とメモリスペースは、そ
の代償(維持費?)となりますけど)
今流行りのオブジェクト指向(つーても、Smalltalkは80年代以前
からだよなぁ・・・)的ツールも、Pythonは一通りそろえています
が、「オブジェクト指向プログラミング(OOP)が可能にできるように」
というだけであって「OOPの思想にはとらわれない」という基本姿勢
をきっちりと出しています。
事実、OOPは大規模なプログラミングには非常に有効ですが、小規
模な使い捨てプログラムには「制約が多すぎる」という印象が持た
れています。
自尊心の高いポリシーを持った言語(JavaとかRubyとか)では、
「きっちりとしたオブジェクト指向」を目指してがんばっているよ
うですが、そういう面では「柔軟な(政治用語で「いいかげんな」
とも言う)」Pythonは、プログラムの単位からして古風な文(ステー
トメント)式です(そういう面では、関数式のCより原始的ですね)。
さらに、そういった「先進的なオブジェクト指向言語」が目の敵
にしている「多重継承」だの「演算子のオーバーロード」だのも、
なんのためらいもなく採用しています(よって、似非OOP言語と陰口
を叩かれますが、否定はしてないようです)
大体、ベースクラス設計が問題になるほど大規模なプロジェクト
に「たかがスクリプト言語」のPythonを投入するなんて、誰も考え
ていないでしょう(できないわけではないし、どうやらあまり知ら
れていないところでは実際、動いているらしいのですが)
Pythonの基本パッケージや汎用ライブラリの作者ともなれば、か
なり慎重にクラス設計をする必要があるでしょうが、そうでなけれ
ば、Pythonスクリプトの再利用は、コーディングした自分自身か、
あるいは「書いた奴が隣にいる」環境で使えば十分です。
※少なくとも、気軽にオブジェクト指向を体験できる言語として、
元祖Smalltalkを除けばPythonに勝るものはそうないでしょう。
保守よりも、とりあえず使いやすいことが優先、というわけで、
演算子を手軽に拡張できる(すなわち、オブジェクトをより便利に
扱える)演算子のオーバーロードや、てっとりばやくオブジェクト
の機能を合成できる多重継承も、重宝して使わせてもらっているわ
けです。
※とはいえ、もしあなたが不特定多数の人向けにクラスライブラリ
やフレームワークを提供するつもりなら、この2者はやはり慎重
にあつかうべきでしょう。Pythonでは、privateに相当するキーワー
ドは存在しませんが、__setattr__メソッド(フィールド代入に対
するフック)を適度に利用することによって、不正変更をロック
することは可能です。ただし、「間違いを減らす」ことはできて
も、悪意を防ぐことは「どんな言語でも不可能」です。C++で、ベー
スクラスを設計する練習代としては、もってこいだと私は思うの
ですが・・・。
無論、OPPツールだけではありません。
Snowball,AWKといったプログラムが採用した連想関数をより発展
させた「辞書(dictionary)」やICONから拝借したスライスは、Python
の強力な武器の一つです。
なにせ、クラスインスタンス(俗に言うオブジェクト)がデータ
としてのみならず、キーとして使えるのは、言語多しといえ、Python
以外にそうは無いでしょう(ただし、キーとして使用できるのは、
変更不可能オブジェクトに限りますが・・・)
Pythonは完全なOOP言語ではありませんが、完全なPythonオブジェ
クト指向プログラミング(POOP)言語です。
Pythonオブジェクトってナニ? といわれると非常に難しいので
すが、とかくそういう名称でひっくくれて、ある程度同じように扱
えるモノと思ってください。
Pythonオブジェクトは全て、リストやタプルの要素になったり、
辞書の値になったりすることができます。
また、変数に収納できますし、クラスのフィールドにもなります。
Pythonスクリプトに於いては、全てのものがPythonオブジェクト
です・・・とPythonの教科書には書いてありますが、正確に言うな
らば、キーワードと演算子とコロンとセミコロン、シャープ以外は、
すべてPythonオブジェクトです。
列挙するなら、即値(リテラル値)、整数型変数、浮動小数点型
変数、ロング整数型変数、文字列、タプル、リスト、辞書、ファイ
ル、クラスインスタンス、クラス、関数・・・
・・・ちょ、ちょいまち・・・
クラスインスタンスはともかく、クラスってのは・・・(汗)
はいはい、これ、間違いじゃないんです。
クラスや関数のような「定義」すら、Pythonオブジェクトなんで
す。
※とあるWeb上のPythonの入門記事で、Smalltalk式のメタクラスは
存在しない、と書いてありましたが、私は、Pythonのクラスはメ
タクラスプロトコル的な使い方の一部は使えるんじゃないかな、
と思います。
ですから、クラス定義をリストにして、「はい、1番のクラス、
次、2番のクラス」なんてこともできちゃうんですよね、これが。
Pythonには、C言語のCASE文に相当する文法はありません。
だって、辞書と関数でできちゃいますから(しかも、文字列だろ
うがオブジェクトだろうがおかまいなし)
関数定義を変数にしまいこむことも、Pythonでは「フツー」です。
でも、ちょっと考えてみてください。
「性質があって、機能があって・・・」とか教えられるオブジェ
クトより、Pythonオブジェクトのほうがよほど「モノ」っぽくあり
ませんか?(感覚的に適当に扱えるとこあたり)。
ま、今回のテーマは、Pythonがいかに「超高級」なのか、ですか
ら、Pythonオブジェクトの詳細な説明についてはいづれということ
にしましょう。
さて、Pythonはファジーな部分だけではありません。
一部の方々には「超不評な」字下げ方式(インデントブロック)
も、Pythonのポリシーの現れです。
これについても後に(熱く)語るとして、今は「読みやすさを重
視したため」とだけ言っておきましょう。
あと・・・あまり語られることが少ないのですが、'()'(パーレ
ン)が省略できない、というのも、Pythonの妙なこだわりの一つで
す。
Rubyなどでは、メソッドのパラメータが「明らか」な場合は、
function() を function と書けたり、
function(a,b,c) を function a,b,c と書けたりできる、という
ルールがあります。
たしかに、一々シフトキーを押して()を書くのは面倒ですので、
ちょっとしたことではありますが、コーディング上の負担軽減とし
ては結構効果的(というか、効果絶大)です。
でも、Pythonではこれはできません。
なぜなら、カッコが無くなってしまうと「値」なのか「アクショ
ン」なのか、見づらくなってしまうからだと思われます。
前述の通り、PythonはPythonオブジェクトでできていますので、()
が無ければ関数でさえPythonオブジェクトとして扱えます。
これは逆に、()のついていない場所では「単なる値のやりとりを
しているだけだよ」という確認ができることにほかなりません。
つまり、デバッグなどでソースをたどる時に、他に副作用がある
かどうかを、目で見ながら確認できるわけです。
値として呼び出されているように見えて、実は副作用がある、と
いう「見えにくいコード」をつくってしまうくらいなら、()の手間
くらい惜しんではいけない、と考えるのがPythonの哲学です。
Perlのような正規表現による条件文をダイレクトに文法に盛り込
まなかったのも、ソースの見づらさを犠牲にできない、という配慮
からだと思われます。
※Awkもよく愛用している私としては、この点だけは時々うらやまし
く思いますが、まぁ、仕方ないのかな、と思います。
Pythonは肩肘張らずに気楽につきあえる言語ですが、それは、目
に見えないこまやかな気配りに裏付けされた、安心感、信頼感によ
るものでもあるのです。
「超高級言語」は「最も人間の思考に近い言語」ではないのかも
しれませんが、「最も人間に近しい道具でありたい」という思いが
こめられている、と、私は考えています。
<巻末おまけ・・・Pythonにあまり向かないもの(1)>
私自身、簡単なテキストフィルタを書く時は、Awkを使います。
Pythonにはreモジュールという正規表現用のモジュールがあるの
で、これを使えばできないことはありませんが、出来る限りAwkを呼
び出して処理させます。
ただし、簡単ではあっても、対話式のデータベースを作るときは、
Pythonの方が便利です。
その点、文法に正規表現のあるPerlやRubyは便利かな、と思いま
すが、「全部自分で済まそうとしない」というUnix哲学的に言えば
Pythonは嫌味な優等生タイプ(笑)なのでしょう(Perlはもともと、
Unixでは異端児ですしね・・・)