トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS   ログイン

ここがヘンだよPythonista の変更点

#ref(http://www.python.org/images/python-logo.gif)
[[Python Programing Langage>http://python.org/]]

-&color(green){Pythonista}; = %%Python教の狂信者%% Pythonを好んで使う人々のこと

-※こんなページタイトルですが、'''&color(green){Pythonista};とは直接関係ありません'''。単にプログラミング言語Pythonの、一風変わった特徴/哲学の特集です。

-このページの参照数 &counter; 回

#contents

*インデントブロック is not アンフリーフォーマット [#d289a45b]

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

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

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

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

*どこにでもあるelse? [#k99ae934]

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

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

*λはお一人様のみ [#bdaeda41]

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

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

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

*関数プログラミングとPythonの関係は○○○○? [#de1fb445]

 昨今の流行の関数プログラミング。

 Pythonは関数をファーストクラスオブジェクトとして扱い、高階関数などお手の物、と思いきや、Python 3で標準関数の座を引きずり下ろされたreduce、代替構文(内包表記)と機能変更で微妙に応用範囲が狭まったfilterとmap、代替構文(引数のシーケンス、マッピング展開)に取って変わられたapplyと、標準の高階関数の地位は低いと言えます。

※『**』演算子が導入されてからも全然削除されないpow関数とかを考えると、その扱いの差は歴然?

 一時はlambdaの廃止もささやかれ、Pythonでは関数プログラミングは書きにくくなるとすら言われました。

 ところが一方で、条件付評価式(if-else式)や、上記で出た内包表記、そしてPython 3でのprint, execの関数化、functoolsの充実など、関数プログラミング向けのツールは実は微妙に増えつつあります。

 なんか関数プログラミングに対してツンデレなPython。

*文は式ならず [#u9ceee09]

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

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

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

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

*なんでもimport? [#b2979c21]

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

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

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

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

*わが道を行く「オブジェクト指向」の考え [#v69ee9a2]

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

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

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

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

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

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

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

*クラス最速? [#w161469f]

 クラスからインスタンスを生成する際に、SmalltalkやRubyならnewメソッドを呼び出しますし、Javaはnewキーワードで定義します。

 しかし、Pythonは、ある意味「無茶」です。

> instance = Class()

 括弧の中に引数を入れて、クラス(オブジェクト)を直接呼出しすれば、インスタンスがぽこっ、と生成されます。

 こんなファジー(or乱暴)なやり方は、Python以外では(私は)知りません。

 関数をオブジェクトの一種とし、オブジェクトに「直接呼出し」ルールをくっつけることが出来るPythonならではのやり方ですが、とりあえず多分コード的にはとんでもなく少ない部類に入ります。

 ではなぜnewキーワードやnewメソッドを使わないのか……実は現在主流になっているobjectを母体とした新式クラス(旧式クラスはPython3では廃止)では、__new__メソッドというソレに相当するものもあるのですが、暗黙に呼び出されます。

 しかしそもそもnewキーワードは(C++やPascalをご存知の方なら話は早いのですが)ポインタの示す領域を定義するためのキーワードなので、もしPythonでソレを実行するなら、代入や再代入する度にnewキーワードを呼び出す必要が出てくることになります(Pythonオブジェクトは、内部的にはすべてポインタです)

 なのでPythonでは、全てをばっさり省略します(いいのか?)

*結果は明白、過程は謎、の代入ルール [#h5f65e59]

 Pythonではよく、「括弧が省略できない」と言われますが、それには理由があります。

 実は

> var = obj

と

> var = obj()

は、必ず「違うモノ」になるからです((勿論、__call__メソッドで「なにもせずに」自分を返すようなトリッキーなメソッドを実装していれば別ですけど))

 var = obj では「varにobjが代入」になりますが、var = obj()では、「obj()の戻り値をvarに代入」となります。

 普通の言語では、objのところに関数やメソッドなどがあれば、そのまま代入することはできませんので、呼び出した結果を書きます。

 しかしPythonでは「呼び出せないオブジェクト」はあっても「代入できない関数やメソッドは存在しない!」というルールがあります。

 そう、Schemeのように&color(red){「関数だろうがメソッドだろうが全てファーストクラスオブジェクト」};というアレです。

 ですからコードを見れば、単純代入なのか呼び出しなのか、一目瞭然です((これも、propertyを使って小細工が施されている場合は別です))

 しかし、結果はわかりやすいのですが、たとえば「obj()」として呼び出されているモノが&color(red){実際何なのか};は一切不明です(笑)

 関数やλ式ならともかく、Pythonではクラスインスタンス生成も、その他のオブジェクトの__call__メソッド呼び出しも&color(blue){「全部同じ書式」};です。

 気になる方は、インタープリタを立ち上げて、reprでインスペクトしてみて下さい((マニュアルにも「関数」と紹介されていても、実はクラスだったりするものが結構あります))

*正規表現のリテラルは? [#ieb38ffc]

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

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

*あっちこっちでイテレータオブジェクト [#kfe450fa]

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

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

*TSWikiのPython関連ページ [#q0f994cc]
-[[Pythonのメインページ>Python]]
-[[Python 3(Py3k, Python 3000)のページ>Python3000]]
-[[Python 3の変更点「What's New In Python 3.0」>What'sNewInPython3.0]]

#comment
#comment_nospam