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!
醜いより美しいほうがいい。
暗示するより明示するほうがいい。
複雑であるよりは平易であるほうがいい。
それでも、込み入っているよりは複雑であるほうがまし。
ネストは浅いほうがいい。
密集しているよりは隙間があるほうがいい。
読みやすいことは善である。
特殊であることはルールを破る理由にならない。
しかし、実用性を求めると自然さが失われることがある。
エラーは隠すな、無視するな。
ただし、わざと隠されているのなら見逃せ。
曖昧なものに出逢ったら、その意味を適当に推測してはいけない。
たったひとつの冴えたやりかたがあるはずだ。
そのやり方は一目見ただけではわかりにくいかもしれない。オランダ人にだけわかりやすいなんてこともあるかもしれない。
ずっとやらないでいるよりは、今やれ。
でも、今」すぐ」にやるよりはやらないほうがマシなことが多い。
コードの内容を説明するのが難しいのなら、それは悪い実装である。
コードの内容を容易に説明できるのなら、おそらくそれはよい実装である。
名前空間は優れたアイデアであるため、積極的に利用すべきである。