Python入門 〜基本文法編〜

TL;DR

http://diveintopython3-ja.rdy.jp を読めばすべてわかる.
環境構築はhttps://github.com/johshisha/python_hands_on を参照するか, ぐぐってくだしあ.

はじめ

Pythonはインタプリタ(一行ずつ実行される)言語だよ

In [1]:
print("Hello, Pythonic world!")
# これはコメント
Hello, Pythonic world!

本編

変数

変数には「型」がない, 値に「型」がある
変数自体はただの入れ物で,中身に種類があるイメージ
ちなみにPythonに定数はない
In [2]:
x = 2017
print(x)
print(type(x))
2017
<class 'int'>
In [3]:
pi = 3.141592653
print(pi)
print(type(pi))
3.141592653
<class 'float'>
In [4]:
flag = True
print(flag)
print(type(flag))
True
<class 'bool'>
In [5]:
s = "こんにちは"
t = "世界"
print(s, t)
print(type(s), type(t))
こんにちは 世界
<class 'str'> <class 'str'>
In [6]:
sentence = """祇園精舎の鐘の声
諸行無常の響きあり"""
print(sentence)
祇園精舎の鐘の声
諸行無常の響きあり
In [7]:
yoroshiku = "4649"
print(yoroshiku)
print(type(yoroshiku))
yoroshiku = int(yoroshiku)
print(yoroshiku)
print(type(yoroshiku))
4649
<class 'str'>
4649
<class 'int'>

演算

In [8]:
1 + 1
Out[8]:
2
In [9]:
2 * 2
Out[9]:
4
In [10]:
5 / 2
Out[10]:
2.5
In [11]:
7 % 3
Out[11]:
1
In [12]:
3 ** 2
Out[12]:
9
In [13]:
100 == 100 or 100 != 100
Out[13]:
True
In [14]:
100 == 100 and 100 != 100
Out[14]:
False
In [15]:
not 100 != 100
Out[15]:
True

if elif else

コロンを忘れずに

In [16]:
year = 2017
if year > 2017:
    print("未来")
elif year < 2017:
    print("過去")
else:
    print("現在")
現在
In [17]:
year = 2000
if 1991 <= year < 2001:
    print("20世紀だね")
20世紀だね

(Trueの時) if (条件式) else (Falseの時)

In [18]:
val = 39
result = "even" if val % 2 == 0 else "odd"
print(result)
odd

== か is か

is は同じオブジェクトかどうかをチェックする

In [19]:
str_a = "林檎スター"
str_b = "林檎スター"
In [20]:
print(id(str_a))
print(id(str_b))
4514509992
4514512384
In [21]:
if str_a == str_b:
    print("str_a == str_b")
else:
    print("str_a != str_b")
str_a == str_b
In [22]:
if str_a is str_b:
    print("str_a is str_b")
else:
    print("str_a is not str_b")
str_a is not str_b

list

Pythonには配列はなく,もっと便利なリストを使う

In [23]:
empty = []
print(type(empty))
<class 'list'>
In [24]:
fruits = ["apple", "banana", "peach"]
print(fruits)
['apple', 'banana', 'peach']
In [25]:
print(fruits[0])
apple
In [26]:
fruits.append("lemmon")
print(fruits)
print(len(fruits))
['apple', 'banana', 'peach', 'lemmon']
4
In [27]:
print(" + ".join(fruits))
apple + banana + peach + lemmon
In [28]:
"apple,banana,peach,lemmon".split(",")
Out[28]:
['apple', 'banana', 'peach', 'lemmon']
In [29]:
if "lemmon" in fruits:
    print("レモン入りです")
if "orange" not in fruits:
    print("オレンジはないです")
レモン入りです
オレンジはないです

リストは何でも入れられる

In [30]:
print(['もじ', 50, 3.14, ["a"]])
['もじ', 50, 3.14, ['a']]

マイナスの添字とスライス

マイナスの添字は後ろから,スライスは範囲指定

In [31]:
numbers = [0, 1, 2, 3, 4, 5]
numbers += [6, 7, 8, 9]
print (numbers)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [32]:
print(numbers[-1], numbers[len(numbers) - 1])
print(numbers[-3], numbers[7])
9 9
7 7
In [33]:
print(numbers[:6])
print(numbers[3:])
print(numbers[5: -3])
[0, 1, 2, 3, 4, 5]
[3, 4, 5, 6, 7, 8, 9]
[5, 6]
In [34]:
print(numbers[::2])
print(numbers[::3])
print(numbers[::-1], list(reversed(numbers)))
[0, 2, 4, 6, 8]
[0, 3, 6, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In [35]:
print(("000" + "1")[-4:])
print(("000" + "20")[-4:])
print(("000" + "300")[-4:])
print("20".zfill(4))
0001
0020
0300
0020

リストのコピー

immutableなオブジェクト(数値・文字列・タプルなど)は素直にコピーできる
mutableなオブジェクト(リスト・オブジェクトなど)はポインタっぽくなってるので,
「=」でのコピーは意図しない結果になる.
Pythonでの「=」は代入ではなく束縛(bind).
In [36]:
zero_vec = [0] * 10
print(zero_vec)
copy_vec = zero_vec
print(copy_vec)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
In [37]:
copy_vec[1] = 1
print(copy_vec)
print(zero_vec)
print(id(copy_vec))
print(id(zero_vec))
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
4514647496
4514647496
スライスを使うとコピーが発生する
(もしくはcopy.deepcopyを利用)
In [38]:
zero_vec = [0] * 10
print(zero_vec)
copy_vec = zero_vec[:]
print(copy_vec)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
In [39]:
copy_vec[1] = 1
print(copy_vec)
print(zero_vec)
print(id(copy_vec))
print(id(zero_vec))
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4514691720
4514645064

tuple

リストの変更できないver.
変更する予定のないものはタプルにしておくと安心
In [40]:
empty = ()
print(type(empty))
<class 'tuple'>
In [41]:
fruits = ("apple", "banana", "peach")
print(fruits)
print(fruits[0])
print(fruits[1::-1])
('apple', 'banana', 'peach')
apple
('banana', 'apple')
In [42]:
fruits.append("lemmon")  # 失敗する
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-42-82a321abd66f> in <module>()
----> 1 fruits.append("lemmon")  # 失敗する

AttributeError: 'tuple' object has no attribute 'append'

タプルパック,シーケンスアンパック

タプルパック - カンマ区切りで代入するとタプルになる
シーケンスアンパック - 要素数があえば分割してくれる
In [43]:
pack = 1, 2, 3
print(pack)
(1, 2, 3)
In [44]:
a, b, c = "あいう"
print(a)
print(b)
print(c)
あ
い
う
In [45]:
a = "3"
b = "5"
print(a, b)
a, b = b, a
print(a, b)
3 5
5 3

ループ

Pythonのfor文はイテレータ(先頭から一個ずつ取り出すやつ)を使う

In [46]:
for i in [0, 1, 2, 3]:
    print(i)
0
1
2
3
In [47]:
print(range(4))
print(list(range(4)))
print(list(range(1, 5)))
range(0, 4)
[0, 1, 2, 3]
[1, 2, 3, 4]
In [48]:
for i in range(len(fruits)):
    print(i, fruits[i])
0 apple
1 banana
2 peach
In [49]:
for fruit in fruits:
    print(fruit)
apple
banana
peach

enumerateを使えば「今何問目?」という問いにも答えられる

In [50]:
for i, fruit in enumerate(fruits):
    print(i, fruit)
0 apple
1 banana
2 peach

組み合わせを書くときのテク

itertoolsには組み合わせ,順列などを簡単に作ってくれる関数がある
※下2つは同じ結果になる
In [51]:
for i, fruit1 in enumerate(fruits):
    for j, fruit2 in enumerate(fruits):
        if i < j:
            print(fruit1 + " and " + fruit2)
apple and banana
apple and peach
banana and peach

importはモジュール(Pythonのライブラリ)を読み込む

In [52]:
import itertools

for fruit1, fruit2 in itertools.combinations(fruits, 2):
    print(fruit1 + " and " + fruit2)
apple and banana
apple and peach
banana and peach

for else

breakされずに最後までfor文が終わった時,elseを行う

In [53]:
people = ["a", "b", "c", "d"]
lupin = "x"
for person in people:
    if person == lupin:
        print("そいつがルパンだ")
        break
else:
    print("異常なし")
異常なし

while

もあるよ - 関数じゃないとスコープをつくらない - やらない処理はpassを書く - ++とかのインクリメンタル演算子はない

In [54]:
i = 1
while True:
    if i % 56 == 0 and i % 48 == 0:
        j = i/56, i/48
        break
    else:
        pass
    i += 1
print(j)
(6.0, 7.0)

dictionary

一対一対応で結び付けたいときのデータ構造
辞書,ハッシュ,連想配列などプログラミング言語によって呼び名は様々

※ 順番は保持されない

In [55]:
empty = {}
print(type(empty))
<class 'dict'>
In [56]:
name2age = {
    "吉田": 30,
    "鈴木": 28,
    "田中": 25
}
print(name2age)
print(type(name2age))
{'吉田': 30, '鈴木': 28, '田中': 25}
<class 'dict'>
In [57]:
print(name2age["鈴木"])
28
In [58]:
name2age["新島 襄"]=2017-1843
print(name2age)
{'吉田': 30, '鈴木': 28, '田中': 25, '新島 襄': 174}
In [59]:
person = "佐藤"
if person not in name2age:
    print(person+"さんの年齢は不明")
佐藤さんの年齢は不明

ループでデータを一通り見たい時

In [60]:
for name in name2age:
    print(name)
吉田
鈴木
田中
新島 襄
In [61]:
for age in name2age.values():
    print(age)
30
28
25
174
In [62]:
for name, age in name2age.items():
    print("{0}さんは{1}歳です".format(name, age))
吉田さんは30歳です
鈴木さんは28歳です
田中さんは25歳です
新島 襄さんは174歳です

set

集合型.重複を許さないデータ構造.
集合演算が便利.

※ dictionaryと同じく順不同

In [63]:
empty = set()
print(type(empty))
<class 'set'>
In [64]:
seasoning = ["塩", "胡椒", "塩", "砂糖", "塩"]
print(seasoning)
print(type(seasoning))

seasoning = set(seasoning)
print(seasoning)
print(type(seasoning))
['塩', '胡椒', '塩', '砂糖', '塩']
<class 'list'>
{'塩', '砂糖', '胡椒'}
<class 'set'>
In [65]:
set1 = {"A", "B", "C"}
set2 = {"B", "C", "D"}
In [66]:
set1 | set2
Out[66]:
{'A', 'B', 'C', 'D'}
In [67]:
set1 & set2
Out[67]:
{'B', 'C'}
In [68]:
set1 ^ set2
Out[68]:
{'A', 'D'}
In [69]:
set1 - set2
Out[69]:
{'A'}
In [70]:
set2 - set1
Out[70]:
{'D'}

defaultdict

空っぽの要素にアクセスしてもエラーにならないdictionary.

それぞれの要素のカウントをしたい時(BoWを作る時など)

dictionaryでカウントすると場合分けが必要
(カウントだけならcollections.Counterの方が便利だけど)
In [71]:
sentence = "Peter Piper picked a peck of pickled peppers."
print(sentence.count("e"))
8
In [72]:
alphabet_counter = {}

for alphabet in sentence:
    if alphabet in alphabet_counter:
        alphabet_counter[alphabet] += 1
    else:
        alphabet_counter[alphabet] = 1
alphabet_counter
Out[72]:
{' ': 7,
 '.': 1,
 'P': 2,
 'a': 1,
 'c': 3,
 'd': 2,
 'e': 8,
 'f': 1,
 'i': 3,
 'k': 3,
 'l': 1,
 'o': 1,
 'p': 7,
 'r': 3,
 's': 1,
 't': 1}

collections.defaultdictを使うと便利

In [73]:
from collections import defaultdict
alphabet_counter = defaultdict(int)

for alphabet in sentence:
    alphabet_counter[alphabet] += 1
alphabet_counter
Out[73]:
defaultdict(int,
            {' ': 7,
             '.': 1,
             'P': 2,
             'a': 1,
             'c': 3,
             'd': 2,
             'e': 8,
             'f': 1,
             'i': 3,
             'k': 3,
             'l': 1,
             'o': 1,
             'p': 7,
             'r': 3,
             's': 1,
             't': 1})
ちなみにsortedを使うとリストでも辞書でもなんでもソートできる
(名前付き引数をつかっています)
In [74]:
sorted(alphabet_counter.items(),key  = lambda x: x[1], reverse=True)
Out[74]:
[('e', 8),
 (' ', 7),
 ('p', 7),
 ('r', 3),
 ('i', 3),
 ('c', 3),
 ('k', 3),
 ('P', 2),
 ('d', 2),
 ('t', 1),
 ('a', 1),
 ('o', 1),
 ('f', 1),
 ('l', 1),
 ('s', 1),
 ('.', 1)]

二重defaultdict

defaultdictを二重にするときは注意
defaultdictの引数はcallableでなくてはならないので,ラムダ式を使う
In [75]:
double_dict = defaultdict(defaultdict(int))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-75-edc607dc3132> in <module>()
----> 1 double_dict = defaultdict(defaultdict(int))

TypeError: first argument must be callable or None
In [76]:
double_dict = defaultdict(lambda : defaultdict(int))
double_dict["花沢"]["カツオ"] = "フォロー"
double_dict["カツオ"]["花沢"] = "フォローしていない"
double_dict
Out[76]:
defaultdict(<function __main__.<lambda>>,
            {'カツオ': defaultdict(int, {'花沢': 'フォローしていない'}),
             '花沢': defaultdict(int, {'カツオ': 'フォロー'})})

None

Pythonでのnull(空っぽ)はNoneで表す

In [77]:
values = [3, None, 4]
print(values)
print(values[1])
[3, None, 4]
None
In [78]:
for val in values:
    if val is not None:
        print(val)
    if val:
        print(val)
3
3
4
4

pickle

オブジェクトのSerialize(直列化).変数をそのまま保存する.
テキストファイルに毎回書き出してとかはめんどくさいので便利.
In [79]:
siritori = {
    "りんご": 0,
    "ごりら": 1,
    "らっぱ": 2,
    "ぱせり": 3
}
siritori
Out[79]:
{'ごりら': 1, 'ぱせり': 3, 'らっぱ': 2, 'りんご': 0}
In [80]:
import pickle
file = open("siritori.pkl", "wb")
pickle.dump(siritori, file, pickle.HIGHEST_PROTOCOL)
file.close()

!を行頭に書くとシェルのコマンドを実行できる

In [81]:
!ls -la
total 1648
drwxr-xr-x  13 arakimm  staff     442  9 28 13:02 .
drwxr-xr-x  10 arakimm  staff     340  9 26 13:21 ..
-rw-r--r--@  1 arakimm  staff   10244  9 25 16:09 .DS_Store
drwxr-xr-x   4 arakimm  staff     136  9 25 14:52 .ipynb_checkpoints
-rw-r--r--   1 arakimm  staff   57910  9 28 13:02 Python01.ipynb
-rw-r--r--   1 arakimm  staff  738600  9 25 15:16 Python02.ipynb
drwxr-xr-x   2 arakimm  staff      68  9 25 14:25 _static
drwxr-xr-x   2 arakimm  staff      68  9 25 14:25 _templates
-rw-r--r--   1 arakimm  staff    5948  9 25 14:25 conf.py
-rw-r--r--   1 arakimm  staff     386  9 25 14:45 index.rst
-rw-r--r--   1 arakimm  staff    2419  9 25 15:16 predict_result.csv
-rw-r--r--   1 arakimm  staff      72  9 28 13:03 siritori.pkl
-rw-r--r--   1 arakimm  staff    5027  9 25 15:16 svc.pkl.cmp
In [82]:
file = open("siritori.pkl", "rb")
siritori2 = pickle.load(file)
file.close()
siritori2
Out[82]:
{'ごりら': 1, 'ぱせり': 3, 'らっぱ': 2, 'りんご': 0}
ファイルをcloseし忘れると良くないのでwith文を使おう
withのスコープを抜けると自動でclose
(ガベッジコレクションに処理されると自動でcloseされるが)
In [83]:
with open("siritori.pkl", "wb") as f:
    pickle.dump(siritori, f, pickle.HIGHEST_PROTOCOL)
In [84]:
with open("siritori.pkl", "rb") as f:
    siritori2 = pickle.load(f)
siritori2
Out[84]:
{'ごりら': 1, 'ぱせり': 3, 'らっぱ': 2, 'りんご': 0}
Q. pickle.dumpが失敗する
A. Serializeできないオブジェクト(generatorなど)が含まれている
 →dillを使ってみる
A. オブジェクトが大き過ぎる
 →joblib.dumpを使ってみる

関数

Pythonの関数を簡単に
Pythonは変数の型を実行時にチェックするので注意
In [85]:
def average(arg_a, arg_b):
    return (arg_a + arg_b)/ 2
In [86]:
average(3, 4)
Out[86]:
3.5
In [87]:
average("a", "b")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-87-89dc35c91032> in <module>()
----> 1 average("a", "b")

<ipython-input-85-cc4497ef8cf6> in average(arg_a, arg_b)
      1 def average(arg_a, arg_b):
----> 2     return (arg_a + arg_b)/ 2

TypeError: unsupported operand type(s) for /: 'str' and 'int'

デフォルト引数

引数がなかった時のデフォルト値を指定できる

In [88]:
def pow(x, y=2):
    return x ** y
In [89]:
print(pow(3))
print(pow(3, 3))
9
27

キーワード引数

仮引数名を使って実引数を与えることができる

In [90]:
def info(name, address, age):
    print("{1}にお住まいの{0}さん({2})".format(name, address, age))
In [91]:
info("はなわ", "佐賀県", 41)
佐賀県にお住まいのはなわさん(41)
In [92]:
info(address="佐賀県", age=41, name="はなわ")
佐賀県にお住まいのはなわさん(41)

その他テク

実行時間を確かめる

プログラムが遅すぎると実験可能回数が減ってしまう
ボトルネックを確かめる方法として実行時間を測るという方法がある
jupyterではマジックコマンドを使って簡単に実行時間を測ることができる
In [93]:
%%timeit
array = []
for x in range(10000):
    array.append(x)
1.1 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [94]:
%%timeit
array = [x for x in range(10000)]
391 µs ± 46.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

メモリ使用量を確かめる

時間計算量と空間計算量はたいていトレードオフ
メモリを食いすぎている変数がないか確かめることも大事
特にjupyterでは使用できるメモリがデフォルトでは限られている模様
(jupyter generate-configで検索と増やす方法が出るかも)
正しいメモリ使用量を知るにはパッケージ等を導入する必要があるが,
jupyterのマジックコマンドで簡易的に変数の状態を知ることはできる
In [95]:
array = [x for x in range(10000)]
In [96]:
%whos
Variable           Type              Data/Info
----------------------------------------------
a                  str               5
age                int               174
alphabet           str               .
alphabet_counter   defaultdict       defaultdict(<class 'int'><...> 'l': 1, 's': 1, '.': 1})
array              list              n=10000
average            function          <function average at 0x10d1870d0>
b                  str               3
c                  str               う
copy_vec           list              n=10
defaultdict        type              <class 'collections.defaultdict'>
double_dict        defaultdict       defaultdict(<function <la<...>>, {'花沢': 'フォローしていない'})})
empty              set               set()
f                  BufferedReader    <_io.BufferedReader name='siritori.pkl'>
file               BufferedReader    <_io.BufferedReader name='siritori.pkl'>
flag               bool              True
fruit              str               peach
fruit1             str               banana
fruit2             str               peach
fruits             tuple             n=3
i                  int               336
info               function          <function info at 0x10d20a2f0>
itertools          module            <module 'itertools' (built-in)>
j                  tuple             n=2
lupin              str               x
name               str               新島 襄
name2age           dict              n=4
numbers            list              n=10
pack               tuple             n=3
people             list              n=4
person             str               佐藤
pi                 float             3.141592653
pickle             module            <module 'pickle' from '/U<...>lib/python3.6/pickle.py'>
pow                function          <function pow at 0x10d20aae8>
result             str               odd
s                  str               こんにちは
seasoning          set               {'塩', '砂糖', '胡椒'}
sentence           str               Peter Piper picked a peck of pickled peppers.
set1               set               {'B', 'C', 'A'}
set2               set               {'B', 'C', 'D'}
siritori           dict              n=4
siritori2          dict              n=4
str_a              str               林檎スター
str_b              str               林檎スター
t                  str               世界
val                int               4
values             list              n=3
x                  int               2017
year               int               2000
yoroshiku          int               4649
zero_vec           list              n=10
In [97]:
del array
In [98]:
%whos
Variable           Type              Data/Info
----------------------------------------------
a                  str               5
age                int               174
alphabet           str               .
alphabet_counter   defaultdict       defaultdict(<class 'int'><...> 'l': 1, 's': 1, '.': 1})
average            function          <function average at 0x10d1870d0>
b                  str               3
c                  str               う
copy_vec           list              n=10
defaultdict        type              <class 'collections.defaultdict'>
double_dict        defaultdict       defaultdict(<function <la<...>>, {'花沢': 'フォローしていない'})})
empty              set               set()
f                  BufferedReader    <_io.BufferedReader name='siritori.pkl'>
file               BufferedReader    <_io.BufferedReader name='siritori.pkl'>
flag               bool              True
fruit              str               peach
fruit1             str               banana
fruit2             str               peach
fruits             tuple             n=3
i                  int               336
info               function          <function info at 0x10d20a2f0>
itertools          module            <module 'itertools' (built-in)>
j                  tuple             n=2
lupin              str               x
name               str               新島 襄
name2age           dict              n=4
numbers            list              n=10
pack               tuple             n=3
people             list              n=4
person             str               佐藤
pi                 float             3.141592653
pickle             module            <module 'pickle' from '/U<...>lib/python3.6/pickle.py'>
pow                function          <function pow at 0x10d20aae8>
result             str               odd
s                  str               こんにちは
seasoning          set               {'塩', '砂糖', '胡椒'}
sentence           str               Peter Piper picked a peck of pickled peppers.
set1               set               {'B', 'C', 'A'}
set2               set               {'B', 'C', 'D'}
siritori           dict              n=4
siritori2          dict              n=4
str_a              str               林檎スター
str_b              str               林檎スター
t                  str               世界
val                int               4
values             list              n=3
x                  int               2017
year               int               2000
yoroshiku          int               4649
zero_vec           list              n=10

その他マジックコマンドは%quickrefで確認できる

おわりに

ここに書いた文法はごく一部
公式ドキュメントhttps://docs.python.jp/3/index.html を読むとより詳しく理解できるだろう
基本的には「やりたいこと python」で検索すればなんとかなるでしょう
車輪の再発明にならないよう,既存のモジュールもよく調べよう
In [99]:
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!
醜いより美しいほうがいい。
暗示するより明示するほうがいい。
複雑であるよりは平易であるほうがいい。
それでも、込み入っているよりは複雑であるほうがまし。
ネストは浅いほうがいい。
密集しているよりは隙間があるほうがいい。
読みやすいことは善である。
特殊であることはルールを破る理由にならない。
しかし、実用性を求めると自然さが失われることがある。
エラーは隠すな、無視するな。
ただし、わざと隠されているのなら見逃せ。
曖昧なものに出逢ったら、その意味を適当に推測してはいけない。
たったひとつの冴えたやりかたがあるはずだ。
そのやり方は一目見ただけではわかりにくいかもしれない。オランダ人にだけわかりやすいなんてこともあるかもしれない。
ずっとやらないでいるよりは、今やれ。
でも、今」すぐ」にやるよりはやらないほうがマシなことが多い。
コードの内容を説明するのが難しいのなら、それは悪い実装である。
コードの内容を容易に説明できるのなら、おそらくそれはよい実装である。
名前空間は優れたアイデアであるため、積極的に利用すべきである。