プログラマが持つべき心構え (The Zen of Python)

  • 352
    いいね
  • 8
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

この記事はstackoverflowのThe Zen of Pythonに関する質問と解答(リンク切れ)を訳したものです。
The Zen of Pythonの日本語訳は"我々は「Python」に何を求めているのか?"を参考にしました。

The Zen of Pythonとは

The Zen of Pythonとは、Pythonプログラマが持つべき心構えを簡潔にまとめたものです。
Pythonを書かないプログラマにとっても、これは大いに役に立つはずです。
ちなみに、"Zen"は日本語の「禅」です。

最初から全文を読もうとする必要はありません。この記事にざっと目を通してみて、気になった部分を読むことをおすすめします。

全文はPythonインタプリタ上で

>>> import this

と入力すると表示できます。

全文は以下のとおりです。

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
醜いより美しいほうがいい。

Explicit is better than implicit.
暗示するより明示するほうがいい。

Simple is better than complex.
複雑であるよりは平易であるほうがいい。

Complex is better than complicated.
それでも、込み入っているよりは複雑であるほうがまし。

Flat is better than nested.
ネストは浅いほうがいい。

Sparse is better than dense.
密集しているよりは隙間があるほうがいい。

Readability counts.
読みやすいことは善である。

Special cases aren't special enough to break the rules.
特殊であることはルールを破る理由にならない。

Although practicality beats purity.
しかし、実用性を求めると自然さが失われることがある。

Errors should never pass silently.
エラーは隠すな、無視するな。

Unless explicitly silenced.
ただし、わざと隠されているのなら見逃せ。

In the face of ambiguity, refuse the temptation to guess.
曖昧なものに出逢ったら、その意味を適当に推測してはいけない。

There should be one-- and preferably only one --obvious way to do it.
たったひとつの冴えたやりかたがあるはずだ。

Although that way may not be obvious at first unless you're Dutch.
そのやり方は一目見ただけではわかりにくいかもしれない。オランダ人にだけわかりやすいなんてこともあるかもしれない。

Now is better than never.
ずっとやらないでいるよりは、今やれ。

Although never is often better than *right* now.
でも、今"すぐ"にやるよりはやらないほうがマシなことが多い。

If the implementation is hard to explain, it's a bad idea.
コードの内容を説明するのが難しいのなら、それは悪い実装である。

If the implementation is easy to explain, it may be a good idea.
コードの内容を容易に説明できるのなら、おそらくそれはよい実装である。

Namespaces are one honking great idea -- let's do more of those!
名前空間は優れたアイデアであるため、積極的に利用すべきである。

解説

それでは原文を一行ずつ解説していきます。

Beautiful is better than ugly.

醜いより美しいほうがいい。

Pythonではたったこれだけのコードで最大公約数を求めることができる。

def gcd(x, y):
    while y:
        x, y = y, x % y
    return x

アルゴリズムが美しいとコードも美しくなる。
そしてPythonは少ない行数でその美しさを表現できる。

Explicit is better than implicit.

暗示するより明示するほうがいい。

例1

こういうことはしてはいけない。

from os import *
print(getcwd())

関数がどのモジュールから提供されているか、ひと目でわかるようにすること。

import os
print(os.getcwd())

The Zen of Pythonにはこう書いてある。

Namespaces are one honking great idea - let's do more of those!

名前空間は素晴らしいアイデアだ。

だからPythonではメソッドを呼び出すとき、フィールドを参照するときにクラス内でもselfと明記する。プログラマは今自分が使っているオブジェクトが何で、どこにあるかを常に意識するべきだ。

例2

スクリプト言語にはこんなことができるものがある。

test.php
<?php
$foo = "5";
echo $foo * 3;
?>

実行するとこうなる。

$php test.php 
15

これは文字列×整数の演算をするときに文字列を整数とみなして計算しているため起こる。暗黙の型変換と呼ばれるものだ。
しかし、Pythonではこのようにエラーになる。

>>> foo = "5"
>>> foo+3
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

結果を整数で返してほしいのなら、それを明示する必要がある。

>>> int(foo)+3
8

Simple is better than complex.

複雑であるよりは平易であるほうがいい。

Complex is better than complicated.

それでも、込み入っているよりは複雑であるほうがまし。

参考にしたページ: What does “Complex is better than complicated” mean?

込み入っている、すなわち難解であることと、複雑なことは少し違う。

例としてこんなコードを挙げてみよう。

counter = 0
while counter < 5:
   print(counter)
   counter += 1

このコードはすごく簡単に理解できるはずだ。だが、このコードは難解だ。
「counter変数の管理」と「print文による値の表示」という2つの要素が1つのコードの中でごちゃまぜになっている。

for i in xrange(5):
   print(i)

一方でこのコードはwihleを使った例よりも複雑、というより、複合的だ。「counter変数の管理」と「print文による値の表示」という2つの要素が明確に分離されている。
xrangeを知らない人には、このコードが何をやっているのかわからないかもしれない。しかし、きれいなコードを書くためなら、xrangeが何なのかを調べるコストはそれほど大きくない。xrangeの動作はドキュメントに目を通せばすぐに理解できる。

コードが大きくなればなるほど、難解なコードと複雑なコードの管理のしやすさの差は大きくなっていく。当然、簡潔で書きやすいほうが管理がしやすい。

Beautiful is better than ugly.

Flat is better than nested.

ネストは浅いほうがいい。

例えば、JavaやC++のライブラリが提供するクラスはたいてい他のクラスを継承している。
こうなると、自分が使いたいクラスが他のクラスをどう継承しているか考えなければならない。
よって、ライブラリの仕様をきちんと理解して使うのが難しくなる。

だが、Pythonなら標準モジュールを使うときにcom.company.java.blah.blahなんて書く必要はない。たいていはtimeitだとかcsvで済むはずだ。これは名前空間がフラットに構築されているからできることなのだ。

Sparse is better than dense.

密集しているよりは隙間があるほうがいい。

if i>0: return sqrt(i)
elif i==0: return 0
else: return 1j * sqrt(-i)
if i > 0:
    return sqrt(i)
elif i == 0:
    return 0
else:
    return 1j * sqrt(-i)

上のコードと下のコード、どちらのほうが読みやすいだろうか。

1行に詰め込もうとしすぎてはいけない。

Readability counts.

読みやすいことは善である。

CとPythonを比較してみよう。

#include <stdio.h>
int main(void) {
    printf("Hello, world!\n");
    return(0);
}
print("Hello, world!")

同じ"Hello, World!"でも、CとPythonでは読みやすさが全然違う。
Pythonならコードが何をしているのかひと目でわかる。

Special cases aren't special enough to break the rules.

特殊であることはルールを破る理由にならない。

Although practicality beats purity.

しかし、実用性を求めると自然さが失われることがある。

Pythonにはcharのような"文字専用"の型は無い。専用の型が必要なほど特殊ではないからだ。
だが、実用性を追求すると、chrやordといった長さ1の文字を引数に取る、または返す関数が必要になる。

Errors should never pass silently.

エラーは隠すな、無視するな。

たとえば、こんなコードを書いてはいけない。

try:
    import this
except ImportError:
    pass

エラーが検出されたことを明示すること。

try:
    import this
except ImportError:
    print('this is not available')

Unless explicitly silenced.

ただし、わざと隠されているのなら見逃せ。

このコードを見てみよう。

d = dict((('spam', 1), ('ham', 2)))

default = 0
k = 'eggs'

try:
    v = d[k]
except KeyError:
    v = d[k] = default

print("v:{}".format(v))
print("d:{}".format(d))

実行するとこうなる。

$python silenced.py 
v:0
d:{'eggs': 0, 'ham': 2, 'spam': 1}

このコードでは、keyが存在しなかったときにそのキーにdefaultの値を設定するようになっている。
except節ではエラーが起きたことを外部に知らせていない。わざとそうしているからだ。

In the face of ambiguity, refuse the temptation to guess.

曖昧なものに出逢ったら、その意味を適当に推測してはいけない。

この条件文はいつ真になるんだろう。

if not a and b:
    pass

こう書きなおすか、

if b and not a:
   pass

もしくは多少不格好だがこう書いたほうがよい。

if (not a) and b:
    pass

There should be one-- and preferably only one --obvious way to do it.

たったひとつの冴えたやりかたがあるはずだ。

C++で配列の要素を順番に見ていくのにはさまざまな方法があり、型によって違う。(私はC++に詳しくないのでよい例があれば教えて欲しい)

しかし、Pythonならこれだけで済む。対象がディクショナリだろうがリストだろうが関係なく、全てこの形でいい。

for element in sequence:

Although that way may not be obvious at first unless you're Dutch.

そのやり方は一目見ただけではわかりにくいかもしれない。オランダ人にだけわかりやすいなんてこともあるかもしれない。

オランダ人について

ここでいう"オランダ人"はPython開発者のGuido van Rossumのことを指している。詳細はこちらを参照して欲しい。

if-then-else節(Cでいうcond?expr1:expr2) に関しては熱い議論が交わされた。その中でGuidoはこれを提案した。

a = expr1 if cond else expr2

これはPythonでif-then-else節を表記するたった1つの方法である。しかしぱっと見では理解しづらい。

Now is better than never

ずっとやらないでいるよりは、今やれ。

never

f = open('stay_open.txt', 'w')
f.write('every even number > 2 is the sum of two primes')
raise AssertionError('this sentence is false')
f.close()

now

with open('will_be_closed.txt', 'w') as f:
    f.write('the sum of two primes > 2 is an even number')
    raise AssertionError('this sentence is false')

neverのコードの何が悪いかお気づきだろうか。
neverのコードではファイルへの接続が閉じられないままassertされてしまう。
「後でcloseするから」という考え方がよくないコードを生んでしまうのだ。
しかしnowのコードならエラーが発生してもちゃんとファイルへの接続を閉じてくれる。

neverのコードは以下のように書き換えることもできる。

try:
    f = open('will_be_closed.txt', 'w')
    f.write('every even number > 2 is the sum of two primes')
    assert not 'this sentence is false'
finally: 
    f.close()

だが、醜いより美しいほうがいい。

Beautiful is better than ugly.

※Python2.7では、ファイルオブジェクトのデストラクタが呼ばれる際にファイルが閉じられるようになっているようです。しかし、GCにオブジェクトの管理を任せる場合、いつデストラクタが呼ばれるかプログラマは通常知ることができないため、ファイルがいつ閉じられるか明確に知ることができず、不安定なプログラムとなってしまいます。
参考: Does a File Object Automatically Close when its Reference Count Hits Zero?

Although never is often better than right now.

でも、今"すぐ"にやるよりはやらないほうがマシなことが多い。

コードを早い段階から最適化し過ぎると、時間のムダになることが多い。

例えばソートの実装が必要になった場合、クイックソートを最初から実装する必要はないことが多い。
一般的にクイックソートはバブルソートより実装が難しい。
本当はバブルソートで十分な問題なのに最初からクイックソートで書いてしまうと時間のムダになる。
テスト段階ではとりあえずバブルソートを使っておいて、必要になったらクイックソートに書き換えるとよい。

If the implementation is hard to explain, it's a bad idea.

コードの内容を説明するのが難しいのなら、それは悪い実装である。

If the implementation is easy to explain, it may be a good idea.

コードの内容を容易に説明できるのなら、おそらくそれはよい実装である。

Namespaces are one honking great idea -- let's do more of those!

名前空間は優れたアイデアであるため、積極的に利用すべきである。

モジュールを使うときはこう書こう。

import module
module.spam()

import module
breakfast = module.SpamAndEggs()

こう書いてはいけない。

from module import *

こう書いていいのはターミナルで関数をテストするときなどに限られる。
通常のプログラムでこう書いてしまうと名前が衝突する可能性がある。また、関数がどのモジュールに属しているかわからないため可読性が下がる。

モジュール名やクラス名が長いのであればasを使えばいい。

import aRidiculouslyLongModuleName as short

最後に

疑問やおかしいと思った点があればコメントしてください。

参考資料一覧

The Zen of Python
我々は「Python」に何を求めているのか?
What does “Complex is better than complicated” mean?
An Introduction to the Zen of Python