what-is-pythonic_jp

Japanese translation of "What Is Pythonic"

View the Project on GitHub morinatsu/what-is-pythonic_jp

Pythonicって何?

この記事はMartijn Faassen氏によって書かれた”What is Pythonic?”を訳者自身の学習を目的に翻訳したものです。

訳者の英語能力やPythonの知識不足による誤訳が含まれている可能性があります。

http://faassen.n–tree.net/blog/view/weblog/2005/08/06/0 (原文)

“Pythonic”って何よ?

2,3か月前にこんな質問をされた。主にEuroPython会議の計画に使われている、EuroPythonメーリングリストのあらゆる場所で。興味深い質問だったが、頻繁に目にする言葉であるのに、それを説明しようという試みはほとんど見たことがないことに気がついた。スレッドはその後も続き、私自身を含むさまざまな人々がそれぞれに答えた。他の人の役に立つかもしれないから、私の答えをブログ向けに書き直してみた。

“Pythonic”は曖昧な概念だ。しかし必ずしも”知能”とか”命”といった、実際に定義してみようとするとつかみどころが無くなりそうな概念よりも曖昧なものではない。定義するのが難しいということは無益であるということを意味しておらず、人類はそのような面倒な定義付けを行ってきた。”Pythonic”というのは”Python言語らしい書き方である”みたいな意味で、今、我々はその実際の意味を表現することを必要としている。

Python言語が発達し、コミュニティが成長していく、その間に渡って、Pythonを正しく使うためのたくさんのアイデアが生まれた。Python言語は数々の仕事をなすための多くの数の慣用表現(”それを行う1つの方法”)を活発に促す。他方、Pythonコミュニティでの新しい慣用表現の発達はそれをサポートする言語の進化にも影響してきた。辞書型の .get()メソッドの採用は、それまで行われていた has_key() とアイテムへのアクセスの組み合わせを一体化したものであり、このような進化の1つの例と考えることができる。

慣用表現が他のプログラミング言語の直訳とはならないことが頻繁にある。たとえば、リストのすべてのアイテムに1つの操作を行う場合の、C言語のこんな感じの書き方。

for (i=0; i  mylist_length; i++) {
    do_something(mylist[i]);
}

これをPythonでそのまま書くとこう。

i = 0
while i  mylist_length:
    do_something(mylist[i])
    i += 1

これは例えちゃんと動いたとしても、Pythonicであるとは考えることはできない。これはPython言語が勧めている書き方ではない。もっといい書き方ができるはずだ。Pythonでリストに含まれるすべての数を生成する典型的な慣用表現は組み込みの Range() 関数のようなものを使うことだ。

for i in range(mylist_length):
    do_something(mylist[i])

これでもまだ十分に”Pythonic”であるとは言えない。Python言語自身が勧める、Pythonicなやり方はこうだ。

for element in mylist:
    do_something(element)

comp.lang.pythonでよくされる質問にはPythonでは不可能な何か、参照を直接受け渡したり変更したりする方法といったものが含まれる。それらはまさにそのようにしているものなのだ(それは importclassdef 文に密接に関連している)。それらが複数の戻り値を持つ関数を書きたいという欲望に基づいたものであることは疑いない。C言語や他の言語で関数にポインタや参照を受け渡すときの書き方がこれだ。

void foo( int * a, float * b) {
    *a = 3;
    *b = 5.5;
}

...

int alpha;
int beta;
foo(&alpha, &beta);

引数を通して関数の結果を受け渡す、このような書き方はPythonでも可能だ。

def foo(a, b):
    a[0] = 3
    b[0] = 5.5

alpha = [0]
beta = [0]
foo(alpha, beta)
alpha = alpha[0]
beta = beta[0]

これはしかし悲鳴をあげたくなるほどに”Pythonic”でなく、関数から複数の値を返す、まったく異なり、もっと良いPython言語らしい書き方がある。タプルとタプルのアンパッキングを利用するのだ。

def foo():
    return 3, 5.5

alpha, beta = foo()

Pythonicでないコードは、経験を積んだPythonプログラマーにとっておかしなものに見え、あるいは扱いにくいものになりがちである。冗長で理解しにくいものであるかもしれず、その代わりに、よく知られており、分りやすくて短い書き方の方が長く連続して望んだ効果を得ることができる。言語はその正しい書き方をサポートしがちなため、その言語らしくない書き方は実行もより遅くなるということがよく起こる。

PythonicであるということはPythonを成果物やデータ構造をきれいな、読みやすい書き方で使うことである。インスタンスの動的な型付けを利用することがPythonicであり、静的な型付けのスタイルを採用することは、必要のない冗長さをもたらすから明らかにPython的でない。Pythonicであるということは、よく知られていない方法で仕事をすることで、経験を積んだPythonプログラマーを驚かせることを避けることだ。

“Pythonic”という言葉は低レベルの書き方を越えたレベルにおいても適用される。ライブラリやフレームワークにとってPythonicであるとは経験を積んだPythonプログラマーがなすべき仕事を可能な限り簡単に自然にピックアップできるということである。Pythonによって書かれたライブラリまたはフレームワークは、それを必要とするプログラマが扱いにくくPythonらしさのないコードを書くのであれば、Python的でない。たぶん、それはPythonが提供するクラス群のような成果を使用していないのだ。もっと便利で理解しやすいライブラリにできるにもかかわらず。

関数やメソッドを引数として関数に渡すことを許すことで得られる便利さは見落とされているかもしれない。ライブラリに定義されたクラスはJavaのような言語ではその隠蔽性を強制しようとしてもいいが、Pythonではもっとゆるい’助言的なロッキング’という戦略を採っており、属性は利用可能でありながら、プログラマーに対してはアンダーラインから始まるものはプライバシー要素であるというヒントを与えている。

もちろん、ライブラリやフレームワークのような大規模なものにおいては、何がPythonicであるか否かは議論の的となる。それでもいくらかのガイドラインは存在する。その1つは冗長さ少なくしようということだ:PythonライブラリのAPIはJavaライブラリで同じことをする場合より小さく軽くなる傾向がある。重くて懲りすぎたAPIはとても”Pythonic”であるとは考えられない。W3C XML DOM APIの場合は、何度かされたPythonでの実装はPythonicであるとは思えないものであった。何人かはそれを”Javaっぽい”と考えた。実際にはJavaのプログラマー達はそれらはJava的でないと考えている、と私は聞いたのだけど…。

Pythonベースで書かれたフレームワークが、車輪を再発明しようとしておらず、既存の言語表記で実現されていることをしていなければ、それはPythonicであると考えることができる。それはまた一般的なPythonの表現にもしたがっているべきだ。

もちろんフレームワークの問題、フレームワークであるからには、もしそれをアプリケーションを小さくするためにするために使うのなら、なじみのないパターンを取り入れようとするのはほとんど避けられない。それがフレームワークの力を利用する手段なのだから。私にはなじみのフレームワーク、Zope2がそのようなフレームワークの例で、それは確かに他の場所ではなかなか見られないような特有のやりかたをたくさん導入する。「獲得」はその一例だ。結果として、多くの経験のあるPythonプログラマーはそれをPythonicであるとは考えなかった。

Pythonicなフレームワークを作るのはとても難しい。何がクールであるか、その言語らしいかといった概念はその助けにならず、良いPythonコードは長年にわたる時を経てすばらしいものに発展してきたのだ。ジェネレータ、セット、unicode文字列、 datetime のような機能が今Pythonicであると考えられている。Zope2は確かにその年代を示すフレームワークの例で、その最初の開発が1997年だとかそんな部分的なことで非難することはできない。それを考えれば、彼は結構長く持ちこたえているではないか。ありがとう。

私が最近のことを顧みてPythonらしさの新しい傾向の例と考えるのは、Pythonのパッケージやモジュール構造の書き方の標準化の動きだ。Twistedのような新しいコードベースやZope3、PyPy、多かれ少なかれこのパターンに従うことだろう。

パッケージやモジュールの名前は短く、lowercaseで、唯一であること パッケージはnamespaceパッケージであるべきこと、即ち __init__.py ファイルは空にすること

私はlxmlのような自分がかつて書いたライブラリもこのしきたりに従うよう試みるかもしれない。

ときどき思うのは、ソフトウェアが”非Pythonic”であるという非難は少々フェアでないものかもしれず、ソフトウェアの他の側面を見えにくくするかもしれないということだ。習得に時間が掛かる、よりパワフルなフレームワークより、Pythonプログラマーにとってとっつきやすいあまりパワフルでないフレームワークの方がよりPythonicであると考えることがあるかもしれない。

最後に、もう1つ、Pythonの設計の全体像を補おうとするなら、Pythonインタプリタで以下を試してみよう。

import this

This work is licensed under a Creative Commons Attribution-ShareAlike 2.0 Generic License.