↑初めての記事だし、こういう煽るタイトルをつけてみたかった。後悔はしていない。
zen of pythonってググって上位に出るのがクソ真面目なリンクばっかりだったから書こうと思った話。
Zen of Pythonとは?
この記事がすごく良く和訳している。(というかググったら最初に来る)
で、実際はどうなの?
Zen of Pythonが極めて有用なPythonプログラムを書く上での指針で有ることは間違いないが、本質的にはジョークで"も"ある。
所々に矛盾が仕込まれており、"Python"の名前の由来1に恥じないイースターエッグ2である。
以下に具体例を示す。
なお、和訳は非常に良く訳されている記事3から引用しています。作者の@IshitaTakeshiさんからの削除要請が来たら該当部分は消します。
また、具体例は(意図せずだが)ぶっちゃけ殆どこの記事の和訳なので、英語が苦にならない諸君はすぐにそっちを読むべきである。そっちの方がずっと面白おかしく書いているし。あと作者の和訳能力不足で書けなかった内容もあるし。
>>> import this
Zen of Python を表示させる為のコマンドだが、早速矛盾している。
Explicit is better than implicit.
暗示するより明示するほうがいい。
import
しただけなのにprint
される
There should be one-- and preferably only one --obvious way to do it.
これは3では何かいいやり方があるはずだ。誰が見ても明らかな、たったひとつのやり方が。
と訳されているが、3の感想欄での@akinomyogaさんの案を採用させて頂く。(このほうが恐らく原文に近いので)
There should be one-- and preferably only one --obvious way to do it.
何かを実現するのに、一つは (そして望むらくはただ一つの) 明白な方法を用意するべき
この一文だけで矛盾している。
至極最もな事を言っているが、one--
と --obvious
で--
の使い方が二通りある。4
this
モジュールの中身
Pythonではinspect
モジュールを使用することで簡単に(Pythonで実装された部分の)ソースコードが覗ける。
>>> import inspect
>>> print(inspect.getsource(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]))
ファ!?
解説すると、s
はROT-135で暗号化されたZen of Pythonの本文であり、続く内容はROT-13の暗号化・復号化のコードである。
Beautiful is better than ugly.
醜いより美しいほうがいい。
Readability counts.
読みやすいことは善である。
どう考えても美しくないし、読みやすくはない。変数名s
やd
、c
も明示的ではない。
さらに言えば、Pythonには既に標準モジュールのcodecs
ROT-13の暗号化・復号化関数が用意されている。6
Simple is better than complex.
複雑であるよりは平易であるほうがいい。
どう考えてももう一度実装するよりかは標準モジュールの関数を使用したほうが平易だ。7
公式見解
python.orgにはユーモアのリンクがある。
その最初の項目がThe Zen of Pythonである。
後書きと言い訳
作者の文才不足でこんな「なぜこのジョークは面白いのか」と真面目に解説する様な記事が出来て本当に申し訳ない。
また、原作者の本来の意図を読み解きたい奇特な人達は是非PEP8209にあるメーリングリストの履歴を読んでもらいたい。
多分原作者のTim Petersは真面目くさった記事ばかりの現状を見てこう思っているだろう:
こんなげーむにまし゛になっちゃってと゛うするの
なお、作者はあるStackoverflowの質問で初めてこれがジョークでもある事を知った。
残念ながらそのスレッドは見つからなかったが、そこではZen of Pythonを根拠に出した回答に対して"People take it too seriously"(みんな真面目に捉えすぎだ)というコメントがあったのを覚えている。
そして気になってipythonでimport this
した後中身が気になりthis.
を入力し2回タブを押した所…といった所である。
おまけ
19行?20行?
Zen of Pythonが書かれたPEP209を見ると、Abstractはこの様に書かれている:
Long time Pythoneer Tim Peters succinctly channels the BDFL's guiding principles for Python's design into 20 aphorisms, only 19 of which have been written down.
雑に和訳する10と:
長年のPythoneerであるTim Petersは、BDFL11のPython設計の指針を20の格言に簡潔にまとめていますが、そのうち19のみが書き記されました。
となる。"References"にあるリンクを辿ると、20行目の内容はGuidoに任されているらしい。12
d.get(c, c)
の説明
歴戦のPythonistaには自明かもしれないが、作者のようなニワカには仕組みが良く分からなかったので、以下説明する。
問題のコードは以下の通りである。
print("".join([d.get(c, c) for c in s]))
ここで、d
はROT-13の暗号・復号対応表のdict
であり、s
はROT-13で暗号化されたstr
である。
dict
のget()
はこのStackoverflowの回答が良く説明している。
try:
value = dictionary[some_key]
except KeyError:
value = default_value
# 上のコードは次のコードと等価
value = dictionary.get(some_key, default_value)
つまり、すごく丁寧に書き直すと、以下の様になる:
encoded_string = s
decoding_dict = d
decoded_list_of_chars = []
for encoded_char in encoded_string:
try:
decoded_char = decoding_dict[encoded_char]
except KeyError:
decoded_char = encoded_char
decoded_list_of_chars.append(decoded_char)
decoded_string = "".join(decoded_list_of_chars)
print(decoded_string)
this.c
の値
実は、python213とpython3でthis.cの値が違う。
# python2
>>> this.c
'!'
### python3
>>> this.c
97
このStackoverflowの回答にある様に、python2と3ではリストの内包表記で微妙に挙動が違う。
雑に説明するとpython2ではリスト内包表記でスコープが変わらない為、この様に同じ名前を使うと前の値を上書きしてしまう。
上記の回答から少し流用してサンプルコードを書くと:
>>> x = "before"
>>> a = [x for x in 1, 2, 3]
>>> print(a)
# python2
3
# python3
'before'
python2では内包表記の方が速い現象の一因だと思われる。
-
"Monty Python’s Flying Circus"という有名なイギリスのコメディ番組。邦題は「空飛ぶモンティ・パイソン」。 ↩
-
なお19行目の
Namespaces are one honking great idea -- let's do more of those!
を加えると3通りである。それともこれすら作者のTim Petersはオランダ人(Guido van Rossum)じゃないから何通りもの使い方をしていまう、というジョークなのだろうか? ↩ -
codecs.decode(string_to_decode_or_encode, "rot13")
↩ -
このStackoverflowの回答にあるが、一回簡略化された後にまた元に戻されている。 ↩
-
"Python Enhancement Proposal"の略。雑に言えばPythonに関する正式な提案書。有名な例で言えばPythonコードのコーディング規約のPEP8だろうか。少し踏み込んだ内容を知るのに非常に役に立つので、読んで損は無い。 ↩
-
DeepLにかけて軽く手直ししただけとも言う。 ↩
-
Benevolent Dictator For Lifeの略、Guido van Rossum(Pythonの生みの親)の意。 ↩
-
ちなみに作者は「ユーモアを忘れるな」説を押したい。最もこれを書いている時点でユーモアに欠けているのだが。 ↩
-
python2は2020/1/1を持ってEOLとなっており、未だに使っている人はとっととpython3に移行するべきである。 ↩