Hatena::Groupbugrammer

蟲!虫!蟲!

Esehara Profile Site (by Heroku) / Github / bookable.jp (My Service)
過去の記事一覧はこちら

なにかあったら「えせはら あっと Gmail」まで送って頂ければ幸いです。
株式会社マリーチでは、Pythonやdjango、また自然言語処理を使ったお仕事を探しています

 | 

2011-12-05Python Advent Calender(全部俺):: 五日目

[]Zen of Pythonの核心に触れよ -- thisでわかるPythonのimportの仕組み 11:43

 さて、Pythonを勉強している人であるならば、嫌でも何処かで「this」のことについて聞いたことがあると思います。「this?何それ?」という言う人はモグリです。「import this」を叩くと、下のような文章が出てくることを知っているかと思います。(原文は英語ですけどね)

 404 Not Found

きたないのよりきれいな方がいい

ごちゃごちゃ難しいのより、白黒はっきりしてるのがいい

めんどうなのよりかんたんな方がいい

けど、訳分かんなくなるくらいならめんどうな方がまし

ネストさせなくていいならしない方がいい

たくさん詰め込んだのよりスカスカな方がいい

読みやすさがたいせつなのよ

特別なこともあるけど掟破りってほどじゃない

実用性を求めてくと、ちょっとはずれちゃうこともあるけどね

わざとそうしてるんじゃない限り

エラーをだまって通すようなことがあっちゃいけません

あいまいなことをてきとーに処理しちゃいけません

間違えようのないやり方がひとつだけあるのがいいね

オランダ人以外には、ちょっと分かりにくかったりしてもね

やらないよりは今やるべき

けど今「すぐ」やるならやんない方がいいこともある

作るものをうまく説明できないようならそれはボツ

うまく説明できたらたぶんそれがグッド

ぶらぼーなアイディア名前空間、やっぱこれですね

 import thisはいいんですけど、じゃあ実際にこの"this"のソースを読んだことがない人もいるんじゃないかなと思います。で、この"this"は、Pythonモジュールを作るときのTipsについていいヒントを与えてくれます。なので、今回は"this"を読むという話をしましょう。

ソース

s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print "".join([d.get(c, c) for c in s])

404 Not Found

Pythonは読み込むときに、まずファイルの全体を実行する

 多くの人々は"import this"を読み込んだとき、いきなり文字列が出てくることにびっくりするでしょう。何か特殊なことをしているのかなとも思っていたんですけど、特に何もしていません。もっというと、直に書かれているだけです。

 Pythonにおいては、'if __name__ = "__main__:"'というおまじないを聞くかと思います。__name__は関数などの名前を取るときに使います。例えば、次のようなコードの場合がそうですね。

>>> def hoge():
...     pass
... 
>>> hoge.__name__
'hoge'

 で、これはファイルを実行する時にも割り当てられます。そこで、多くの人達は、そのファイルが他から呼び出されたときは実効せず、そのファイルが直接実行された場合にのみ使う、という説明を聞いている人が殆どなんじゃないのかな、と思います。それはPythonのimportが下記のような挙動を取るからです。つまり、呼び出された時点で、一度ファイル全部を実行してしまうのだ、と。なのでPythonでは、どんなファイルでもモジュールになりうるし、呼び込むことが可能です。例えば、次のような文を一行書いてあっただけだとしても、それは外部から呼び出すことが可能なのです。

#void.py
print

 これは、"import void"できます。

 そして、さらにいうと、Pythonはprotected、つまり外部から参照不可能な変数にはなりません。ちょっとした工夫が必要です。ですから、"import this"をしたときに、this.aとすると、セット時のデータが見れるようになっていたりします。

カエサル暗号の生成

 さて、もう一つ気になることがあります。それが文字列が暗号のようになっているということです。これはカエサル暗号と呼ばれていて、文字の配列をずらすことで設定するものです。

 一つずつ読んでいきましょう。まずforにある(65,97)なのですが、これはchrで一文字を取り出したときに、どこからがアルファベットなのかを決定しています。ですので、dと呼ばれる連想配列には、アルファベットが先頭から順番に26回入るようになっています。

 次なのですが、ちょっと式が難しいですね。例えばiに足される数が3だとすると、こういう風に代入されていきます。

a:d
b:e
c:f
d:g
e:h

 もちろん、アルファベットは26文字ですから、26で割り、余りを使うことで循環を表現しています。

 これらの式を使って辞書を作ったとして、次に気になるのは、forの使い方です。sは文字列で、これも内部的には配列として扱えるので、forを使えば一文字ずつ取り出せます。その一文字をcを代入していくわけです。この使い方は、リスト内包表記という言い方をするとわかりやすいのかな。

 で、このcの使い方なんですが、ちょっと面白かったので調べてみました。

>>> hoge = (c for c in range(10))
>>> hoge.next()
0
>>> hoge.next()
1
>>> hoge.next()
2
>>> hoge.next()
3

 ようするに、こうするとジェネレーターが作れるわけですね。また、これは特殊なgenerateなので、これをリストに入れると、展開してくれます。

>>> hoge = [c for c in range(10)]
>>> hoge
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 また、辞書型は、getという形を持ちます。getの利点は一つで、普通、辞書型で登録していないkeyアクセスしようとするとエラーになるのですが、getで行うとエラーが起きません。また、そのkeyが存在しない時のデフォルト値を第二引数に渡すことが可能です。

Anti Zen of Python

 import thisは、Python聖典みたいなものです。しかし、それに対抗して"import that"というものが存在します。

 Welcome to that’s documentation! — that 1.0.7 documentation

 ここでは詳しく解説しませんが、このような遊びも行われています。

まとめ

 今回は、import thisについて解説しました。import thisに書いてあることの哲学は、Pythonを使う人にとっては、ちょっと片隅に置いておくとスマートにかけるものですが、import thisのもう一つの真髄というのは、そこに込められた遊び心であり、それもまた私たちに大切なことなのだということであるのかもしれませんね。

参考

 The History of Python.jp: import thisとThe Zen of Python(2)

 |