トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS   ログイン


python-logo.gif

Python Programing Langage

インデントブロック is not アンフリーフォーマット

 インデントブロックは、ABC言語から受けついだPython最大の特徴としてよく紹介されます。そしてこの特徴を以って、古参のベテランプログラマの方々はCobolなどのフォーマット固定言語を彷彿させ、難色を示すという話を時々聞きます。

 実際から言えば、Pythonはほぼフリーフォーマットです。ブロックのインデントは強制されますが、式はいくらでも長くできますし、パーレン(丸括弧)でくくれば、行もかなりファジーに設定できます。

 何より、強制されなくともブロック構造はインデントされて書かれるのが普通なので、むしろ「ブロックに括弧を書かなくて良い、手軽な言語」として考えていただいたほうが正確かと思います。

 ただ、TABによるインデントはトラブルの元なので、ホワイトスペースによるインデントをお勧めいたします。

どこにでもあるelse?

 if文にelse節があるのはあたりまえ。elifも、case文と同様と考えればそんなに珍しくもない。でも、for文やwhile文にelse節が付けられるのはPythonぐらいでしょう。しかもこのelse節は「breakせずに正常にループが終了したら起こる」のです。

 理屈としてはこうです。if文の条件式が偽になった時にelse節が実行されます。forやwhileは、条件を満たさなくなった時にループを抜けます。ゆえに、「条件節を満たさなかった時にelse」は理屈には合っています。しかし、「正常にループが終わるとelse(~でなければ)」というのは、語感的に微妙な気がしないでもないですね。

Lambdaはお一人様のみ

 Pythonのラムダ文と呼ばれる文法は、lambdaキーワードによって、式を関数に変換して返すことが出来ます。ただし、defキーワードによる関数定義と異なり、ラムダ文の中には式しか書けません。Pythonでは代入は式でなく文ですから、ラムダ文によって記述できる関数は、かなり限定的なものになります。

 ラムダ文が式にしか適用できないのは、ラムダ文の中であまり複雑化しないように、という配慮らしいのですが、その結果、数学で言うところのλ式に近い雰囲気になっている(当然、本来のλ式には代入などない)ともいえます。

 ラムダ文は、名前にバインドされない無名関数を作ることによく使われますが、別に代入文を使って名前をつけることも可能です(お好きな方は再帰でもどうぞ)。むしろ「関数オブジェクト」を記すリテラルと考えたほうがいいかもしれません。

文は式ならず

 文と式の区別の無い言語の信奉者には、Pythonの「文と式の区別」は、前に挙げた「ブロックインデント」とともに、異端審問のように糾弾されるネタの一つです。Pythonでの式文(lambda文を含む)以外の文は、代入文、print文、exec文、for文、if文、while文、クラスや関数などの定義文、その他の例外文関連でしょうか。

 このうち、print文とexec文はPython3000では関数に変更されますし、if文は条件付評価式(Conditional Expressions)でかなりのことが書けます。for文も、単純な繰り返しによるリスト、タプル、イテレータなどは(Python3000では集合も)内包表現で書けますし、そして、どんな文もdef定義で囲ってしまえば関数⇒式になってしまいます。各文を無理やり式にする必要は無いと思いますし、そのメリットもあるんだか無いのだか、結構理解しにくいです。

 では、文と式を分けることにメリットはあるのか……これは、代入(=)と比較演算(==)での単純ミスを起こさないため、ということがよく例に挙げられます。その他にも、式でなんでも表現できるということは、逆に複雑な式が書けてしまうという「悪しき欲求(ダークフォース?)」を呼びます。その抑制のためにも、文法で禁止してしまうのも一つの方法ではないのかな、と思います。

 なお、昨今流行の関数プログラミングには、Python文法は一見不利に見えますが、基本的に代入を行わなければ文にする必要は無いので、かえって良いのかもしれませんね。

なんでもimport?

 Pythonでは、プログラムを終了するにも、コマンドパラメータを取得するにもインポートが必要です。他のスクリプト言語では、面倒なパッケージインポートなどをせずとも使える組み込みツール(関数/手続き)がてんこ盛りなのに、Pythonはそれに比較して意外と少ないです。

 これは、逆に考えれば自由に使える名前が多い、ということです。名前空間は混雑しやすいですから、必要なものだけを導入し、すっきりと記述できる、という方針でもあります。また、インポートするパッケージ/モジュールを見ることで、スクリプトの性質が理解しやすくなるという点もあります。

 どうしても面倒だという方は、よく使うツールを自分用に登録したモジュールを用意されることをお勧めします。

 ただし、未だにimport sysでsys.exit()を呼び出してる方については、(多分2.5以降は)quit()で一発で終了できますので、「Pythonはインポートしないと終了すらできない」という濡れ衣を着せるのは止めてください(まぁ、以前は実際そうだったのだけど……)

わが道を行く「オブジェクト指向」の考え

 C++に似ているようで、そうでなし、さりとてSmalltalk風かというとそうでもなし。そもそも、オブジェクト指向と銘打ってる割には、カプセル化なんて全然気にしないし……Pythonのオブジェクト指向プログラミングのスタイルは、かなり独特です。

 全体としての書き方は、C++やJavaに似てますが、演算子のオーバーロードはメソッドフックを使って実現します。

 クラスやクラスインスタンスは、改造改変が自由自在であり、それで暴走したって自己責任です。

 また、意味の無い多重継承に至っては……パーツを組み合わせる合体クラスでも作るのでないかぎり、何に使うのか意味不明です(has-a関係をサブクラスで表現していいのかしらん?)

 selfポインタを使って外側から内側をイジるような気持ちの悪いスタイルに至っては、非難ごうごうです(modula-3の特徴だそうな)

 オブジェクト認識の基本は「ダック・タイピング(アヒルに見えて、アヒルのように啼いたらアヒルと考える)」ですが、必要があれば継承もありますし、イヌのように血統書にこだわるのならisinstance関数というタイプチェック方法もあります。

 Python3000になって、関数やオブジェクトが受け取るオブジェクトの指定ができるようになったようですが、これ、単なるアナウンス用だけであり、強制力は全く無いそうな……

正規表現のリテラルは?

 AWKはもちろん、PerlでもRubyでも手軽に使える正規表現。Pythonはreモジュールを呼び出してraw文字列を食わせてやらないと動いてくれません。正規表現を文法に入れるかどうかについては、私はコードが汚くなるような気がするのであまり好きではないのですが、「正規表現が気軽に使えないスクリプト言語なんぞウェブアプリで使えるか!」という意見は根強いようです。

 setはモジュールから組み込み、リテラルへとトントン拍子に出世しましたが、正規表現がreモジュールから昇格するという話は聞いた事がありません(PEPにあるのかな?)。Pythonistaは、あまり正規表現リテラルに興味が無いようです。

あっちこっちでイテレータオブジェクト

 私の記憶に間違いがなければ(間違っていたら誰か教えてください)3.0で廃止されたxrange関数で始めて実装されたイテレータオブジェクト。現在ではrange関数自身がイテレータオブジェクトを返す関数になった他、3.0ではより多くの関数や書式がイテレータオブジェクトを返す形(つまりジェネレータ)に変化しつつあります。

 イテレータオブジェクトはfor構文と一緒に使ってなんぼ。見えない部分でのスピードアップ/メモリ節約に役立っている筈ですが、これが本当に理解しやすいかは謎。理解しやすさをモットーとするPython文法に逆行してるんじゃないかな、とか考えるのは私だけでしょうか(再帰よりマシかな? いや、そーでもないよなぁ)

TSWikiのPython関連ページ